Address Contract Partially Verified
Address
0x2F9EC37d6CcFFf1caB21733BdaDEdE11c823cCB0
Balance
0 ETH
Nonce
1
Code Size
13865 bytes
Creator
0xdfeE8DC2...a84E at tx 0x9e6d4938...78663f
Indexed Transactions
0
Contract Bytecode
13865 bytes
0x6080604052600436106101665763ffffffff60e060020a600035041663024c7ec7811461016b57806302ef521e146101875780630c8496cc146101ad5780632978c10e1461021d5780632fe8a6ad146102a657806349d10b64146102cf578063569706eb146102e45780635d732ff2146103475780635e35359e1461035c57806361cd756e1461038657806379ba5097146103b75780637b103999146103cc5780637f9c0ecd146103e15780638077ccf71461043857806389f9cc61146104595780638da5cb5b146104cc578063ab6214ce146104e1578063b1e9932b1461054b578063b4a176d3146105b6578063b77d239b146105cb578063c52173de14610635578063c7ba24bc14610694578063c98fefed146106f2578063cb32564e14610750578063d4ee1d90146107c4578063d734fa19146107d9578063e57738e514610850578063f2fde38b146108c0578063f3898a97146108e1578063f3bc7d2a14610932575b600080fd5b34801561017757600080fd5b50610185600435151561094a565b005b34801561019357600080fd5b50610185600160a060020a03600435166024351515610992565b3480156101b957600080fd5b50604080516020600480358082013583810280860185019096528085526102049536959394602494938501929182918501908490808284375094975050933594506109db9350505050565b6040805192835260208301919091528051918290030190f35b34801561022957600080fd5b50604080516020600480358082013583810280860185019096528085526102949536959394602494938501929182918501908490808284375094975050843595505050602083013592600160a060020a036040820135811693506060820135169150608001356109f3565b60408051918252519081900360200190f35b3480156102b257600080fd5b506102bb610a0e565b604080519115158252519081900360200190f35b3480156102db57600080fd5b50610185610a2f565b604080516020600480358082013583810280860185019096528085526102949536959394602494938501929182918501908490808284375094975050843595505050602083013592600160a060020a036040820135169250606001359050610cae565b34801561035357600080fd5b50610294610cc9565b34801561036857600080fd5b50610185600160a060020a0360043581169060243516604435610ccf565b34801561039257600080fd5b5061039b610d08565b60408051600160a060020a039092168252519081900360200190f35b3480156103c357600080fd5b50610185610d17565b3480156103d857600080fd5b5061039b610dea565b3480156103ed57600080fd5b5060408051602060048035808201358381028086018501909652808552610294953695939460249493850192918291850190849080828437509497505093359450610df99350505050565b34801561044457600080fd5b506102bb600160a060020a0360043516611628565b34801561046557600080fd5b50604080516020600480358082013583810280860185019096528085526102949536959394602494938501929182918501908490808284375094975050600160a060020a03853581169650602086013595604081013595506060013516925061163d915050565b3480156104d857600080fd5b5061039b6117d2565b604080516020600480358082013583810280860185019096528085526102949536959394602494938501929182918501908490808284375094975050843595505050602083013592600160a060020a036040820135811693506060820135169150608001356117e1565b34801561055757600080fd5b5060408051602060048035808201358381028086018501909652808552610294953695939460249493850192918291850190849080828437509497505084359550505060208301359260400135600160a060020a031691506118079050565b3480156105c257600080fd5b50610185611821565b604080516020600480358082013583810280860185019096528085526102949536959394602494938501929182918501908490808284375094975050843595505050602083013592600160a060020a0360408201358116935060608201351691506080013561185a565b604080516020600480358082013583810280860185019096528085526102949536959394602494938501929182918501908490808284375094975050843595505050602083013592604081013592506060810135915060800135611a9a565b3480156106a057600080fd5b506040805160206004803580820135838102808601850190965280855261029495369593946024949385019291829185019084908082843750949750508435955050506020909201359150611aad9050565b60408051602060048035808201358381028086018501909652808552610294953695939460249493850192918291850190849080828437509497505084359550505060208301359260400135600160a060020a031691506118079050565b6040805160206004803580820135838102808601850190965280855261029495369593946024949385019291829185019084908082843750949750508435955050506020830135926040810135925060608101359150608081013590600160a060020a0360a0820135169060c00135611ac7565b3480156107d057600080fd5b5061039b611c65565b3480156107e557600080fd5b50610800600160a060020a0360043581169060243516611c74565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561083c578181015183820152602001610824565b505050509050019250505060405180910390f35b34801561085c57600080fd5b50604080516020600480358082013583810280860185019096528085526102949536959394602494938501929182918501908490808284375094975050843595505050602083013592600160a060020a036040820135169250606001359050610cae565b3480156108cc57600080fd5b50610185600160a060020a0360043516611da5565b6040805160206004803580820135838102808601850190965280855261029495369593946024949385019291829185019084908082843750949750508435955050506020909201359150611aad9050565b34801561093e57600080fd5b50610185600435611e42565b610952611eaa565b60038054911515740100000000000000000000000000000000000000000274ff000000000000000000000000000000000000000019909216919091179055565b61099a611eaa565b816109a481611f0e565b826109ae81611f71565b5050600160a060020a03919091166000908152600560205260409020805460ff1916911515919091179055565b6000806109e88484610df9565b946000945092505050565b6000610a0387878787878761185a565b979650505050505050565b60035474010000000000000000000000000000000000000000900460ff1681565b60008054600160a060020a0316331480610a64575060035474010000000000000000000000000000000000000000900460ff16155b1515610aba576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f4143434553535f44454e494544000000000000000000000000000000604482015290519081900360640190fd5b610ae37f436f6e7472616374526567697374727900000000000000000000000000000000611fd2565b600254909150600160a060020a03808316911614801590610b0c5750600160a060020a03811615155b1515610b62576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b604080517fbb34534c0000000000000000000000000000000000000000000000000000000081527f436f6e747261637452656769737472790000000000000000000000000000000060048201529051600091600160a060020a0384169163bb34534c9160248082019260209290919082900301818787803b158015610be657600080fd5b505af1158015610bfa573d6000803e3d6000fd5b505050506040513d6020811015610c1057600080fd5b5051600160a060020a03161415610c71576040805160e560020a62461bcd02815260206004820152601460248201527f4552525f494e56414c49445f5245474953545259000000000000000000000000604482015290519081900360640190fd5b6002805460038054600160a060020a0380841673ffffffffffffffffffffffffffffffffffffffff19928316179092559091169216919091179055565b6000610cbf8686866000878761185a565b9695505050505050565b60045481565b610cd7611eaa565b82610ce181611f0e565b82610ceb81611f0e565b83610cf581611f71565b610d0086868661206a565b505050505050565b600354600160a060020a031681565b600154600160a060020a03163314610d79576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f4143434553535f44454e494544000000000000000000000000000000604482015290519081900360640190fd5b60015460008054604051600160a060020a0393841693909116917f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a91a3600180546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b600254600160a060020a031681565b600080600080600080600080600080600080610e347f42616e636f72466f726d756c6100000000000000000000000000000000000000611fd2565b94508c9a5060028e51118015610e4f57508d51600290066001145b1515610ea5576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f494e56414c49445f5041544800000000000000000000000000000000604482015290519081900360640190fd5b600293505b8d51841015611616578d60028503815181101515610ec457fe5b9060200190602002015192508d60018503815181101515610ee157fe5b9060200190602002015191508d84815181101515610efb57fe5b90602001906020020151905081600160a060020a0316638da5cb5b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015610f4557600080fd5b505af1158015610f59573d6000803e3d6000fd5b505050506040513d6020811015610f6f57600080fd5b50519550610f7d86846120f7565b9250610f8986826120f7565b905081600160a060020a031681600160a060020a031614156112ea576003841080610fe057508d60038503815181101515610fc057fe5b90602001906020020151600160a060020a031682600160a060020a031614155b156110525781600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561102357600080fd5b505af1158015611037573d6000803e3d6000fd5b505050506040513d602081101561104d57600080fd5b505198505b85600160a060020a031663d8959512846040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156110ad57600080fd5b505af11580156110c1573d6000803e3d6000fd5b505050506040513d60208110156110d757600080fd5b5051604080517f0e53aae9000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301529151929a5090881691630e53aae99160248082019260a0929091908290030181600087803b15801561114157600080fd5b505af1158015611155573d6000803e3d6000fd5b505050506040513d60a081101561116b57600080fd5b50602090810151604080517f48d73fed000000000000000000000000000000000000000000000000000000008152600481018d9052602481018c905263ffffffff83166044820152606481018f90529051919950600160a060020a038816926348d73fed926084808401938290030181600087803b1580156111ec57600080fd5b505af1158015611200573d6000803e3d6000fd5b505050506040513d602081101561121657600080fd5b5051604080517f579cd3ca0000000000000000000000000000000000000000000000000000000081529051919c506112cc91620f4240916112c091600160a060020a038b169163579cd3ca9160048083019260209291908290030181600087803b15801561128357600080fd5b505af1158015611297573d6000803e3d6000fd5b505050506040513d60208110156112ad57600080fd5b50518e9063ffffffff9081169061215b16565b9063ffffffff6121db16565b9a8b90039a99506112e3898c63ffffffff61224916565b985061160b565b81600160a060020a031683600160a060020a031614156115f957600384108061133f57508d6003850381518110151561131f57fe5b90602001906020020151600160a060020a031682600160a060020a031614155b156113b15781600160a060020a03166318160ddd6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561138257600080fd5b505af1158015611396573d6000803e3d6000fd5b505050506040513d60208110156113ac57600080fd5b505198505b85600160a060020a031663d8959512826040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801561140c57600080fd5b505af1158015611420573d6000803e3d6000fd5b505050506040513d602081101561143657600080fd5b5051604080517f0e53aae9000000000000000000000000000000000000000000000000000000008152600160a060020a0384811660048301529151929a5090881691630e53aae99160248082019260a0929091908290030181600087803b1580156114a057600080fd5b505af11580156114b4573d6000803e3d6000fd5b505050506040513d60a08110156114ca57600080fd5b50602090810151604080517ff732f1c9000000000000000000000000000000000000000000000000000000008152600481018d9052602481018c905263ffffffff83166044820152606481018f90529051919950600160a060020a0388169263f732f1c9926084808401938290030181600087803b15801561154b57600080fd5b505af115801561155f573d6000803e3d6000fd5b505050506040513d602081101561157557600080fd5b5051604080517f579cd3ca0000000000000000000000000000000000000000000000000000000081529051919c506115e291620f4240916112c091600160a060020a038b169163579cd3ca9160048083019260209291908290030181600087803b15801561128357600080fd5b9a8b90039a99506112e3898c63ffffffff6122a616565b6116058684838e612306565b909b5099505b600284019350610eaa565b50989c9b505050505050505050505050565b60056020526000908152604090205460ff1681565b60008085600160a060020a031663fc0c546a6040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561167e57600080fd5b505af1158015611692573d6000803e3d6000fd5b505050506040513d60208110156116a857600080fd5b50518751600160a060020a0390911690889060009081106116c557fe5b60209081029091010151600160a060020a03161461172d576040805160e560020a62461bcd02815260206004820152601860248201527f4552525f494e56414c49445f534f555243455f544f4b454e0000000000000000604482015290519081900360640190fd5b604080517faafd6b76000000000000000000000000000000000000000000000000000000008152600481018790523360248201529051600160a060020a0388169163aafd6b769160448083019260209291908290030181600087803b15801561179557600080fd5b505af11580156117a9573d6000803e3d6000fd5b505050506040513d60208110156117bf57600080fd5b50519050610a038782868660008061185a565b600054600160a060020a031681565b6000846117ed816123ea565b6117fb88888888888861185a565b98975050505050505050565b60006118188585858560008061185a565b95945050505050565b611829611eaa565b6003546002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03909216919091179055565b60008060006060600061186b612442565b6003805475ff00000000000000000000000000000000000000000019167501000000000000000000000000000000000000000000179055886118ac816123ea565b60028c511180156118c257508b51600290066001145b1515611918576040805160e560020a62461bcd02815260206004820152601060248201527f4552525f494e56414c49445f5041544800000000000000000000000000000000604482015290519081900360640190fd5b6119538c600081518110151561192a57fe5b906020019060200201518d600181518110151561194357fe5b906020019060200201518d6124b6565b60009450600160a060020a03881615156119c25786156119bd576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f414646494c494154455f46454500000000000000604482015290519081900360640190fd5b611a2f565b8660001080156119d457506004548711155b1515611a2a576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f414646494c494154455f46454500000000000000604482015290519081900360640190fd5b600194505b339350600160a060020a03891615611a45578893505b611a508c85876126ba565b9250611a5f838c8c8b8b612ad1565b9150611a6c838386613031565b506003805475ff000000000000000000000000000000000000000000191690559a9950505050505050505050565b6000610a03878787878787600080611ac7565b6000611abf848484600080600061185a565b949350505050565b60008060008089611ad7816123ea565b8c518d906000198101908110611ae957fe5b906020019060200201519350611b1e7f42616e636f725800000000000000000000000000000000000000000000000000611fd2565b9250611b497f424e54546f6b656e000000000000000000000000000000000000000000000000611fd2565b600160a060020a03858116911614611bab576040805160e560020a62461bcd02815260206004820152601860248201527f4552525f494e56414c49445f5441524745545f544f4b454e0000000000000000604482015290519081900360640190fd5b611bb98d8d8d308b8b61185a565b9150611bc6848484613114565b604080517f427c0374000000000000000000000000000000000000000000000000000000008152600481018c9052602481018b905260448101849052606481018a90529051600160a060020a0385169163427c037491608480830192600092919082900301818387803b158015611c3c57600080fd5b505af1158015611c50573d6000803e3d6000fd5b50939f9e505050505050505050505050505050565b600154600160a060020a031681565b60606000611ca17f436f6e76657273696f6e5061746846696e646572000000000000000000000000611fd2565b604080517fa1c421cd000000000000000000000000000000000000000000000000000000008152600160a060020a038781166004830152868116602483015291519293509083169163a1c421cd9160448082019260009290919082900301818387803b158015611d1057600080fd5b505af1158015611d24573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015611d4d57600080fd5b810190808051640100000000811115611d6557600080fd5b82016020810184811115611d7857600080fd5b8151856020820283011164010000000082111715611d9557600080fd5b50909550505050505b5092915050565b611dad611eaa565b600054600160a060020a0382811691161415611e13576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f53414d455f4f574e4552000000000000000000000000000000000000604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b611e4a611eaa565b620f4240811115611ea5576040805160e560020a62461bcd02815260206004820152601960248201527f4552525f494e56414c49445f414646494c494154455f46454500000000000000604482015290519081900360640190fd5b600455565b600054600160a060020a03163314611f0c576040805160e560020a62461bcd02815260206004820152601160248201527f4552525f4143434553535f44454e494544000000000000000000000000000000604482015290519081900360640190fd5b565b600160a060020a0381161515611f6e576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f494e56414c49445f4144445245535300000000000000000000000000604482015290519081900360640190fd5b50565b600160a060020a038116301415611f6e576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f414444524553535f49535f53454c4600000000000000000000000000604482015290519081900360640190fd5b600254604080517fbb34534c000000000000000000000000000000000000000000000000000000008152600481018490529051600092600160a060020a03169163bb34534c91602480830192602092919082900301818787803b15801561203857600080fd5b505af115801561204c573d6000803e3d6000fd5b505050506040513d602081101561206257600080fd5b505192915050565b604080517f7472616e7366657228616464726573732c75696e74323536290000000000000081528151908190036019018120600160a060020a03851660248301526044808301859052835180840390910181526064909201909252602081018051600160e060020a0316600160e060020a0319909316929092179091526120f29084906131db565b505050565b600160a060020a03811660009081526005602052604081205460ff161515612120575080612155565b61212983613269565b15612149575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee612155565b612152836132fa565b90505b92915050565b60008083151561216e5760009150611d9e565b5082820282848281151561217e57fe5b04146121d4576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b9392505050565b600080808311612235576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f4449564944455f42595f5a45524f0000000000000000000000000000604482015290519081900360640190fd5b828481151561224057fe5b04949350505050565b6000828201838110156121d4576040805160e560020a62461bcd02815260206004820152600c60248201527f4552525f4f564552464c4f570000000000000000000000000000000000000000604482015290519081900360640190fd5b600081831015612300576040805160e560020a62461bcd02815260206004820152600d60248201527f4552525f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b50900390565b600080612311613587565b604080517f67657452657475726e28616464726573732c616464726573732c75696e74323581527f36290000000000000000000000000000000000000000000000000000000000006020808301919091528251918290036022018220600160a060020a03808b16602485015289166044840152606480840189905284518085039091018152608490930184529082018051600160e060020a0316600160e060020a0319909216919091178152815191929184918b5afa8015156123d357600080fd5b505080516020909101519097909650945050505050565b60008111611f6e576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f5a45524f5f56414c5545000000000000000000000000000000000000604482015290519081900360640190fd5b6003547501000000000000000000000000000000000000000000900460ff1615611f0c576040805160e560020a62461bcd02815260206004820152600e60248201527f4552525f5245454e5452414e4359000000000000000000000000000000000000604482015290519081900360640190fd5b60008083600160a060020a0316638da5cb5b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156124f757600080fd5b505af115801561250b573d6000803e3d6000fd5b505050506040513d602081101561252157600080fd5b5051915061252e82613269565b905060003411156125fc57348314612590576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4554485f414d4f554e545f4d49534d41544348000000000000000000604482015290519081900360640190fd5b8015156125f7576125a0826132fa565b600160a060020a031663d0e30db0346040518263ffffffff1660e060020a0281526004016000604051808303818588803b1580156125dd57600080fd5b505af11580156125f1573d6000803e3d6000fd5b50505050505b6126b3565b600160a060020a03851660009081526005602052604090205460ff16156126955761262985333086613447565b80156125f75784600160a060020a0316632e1a7d4d846040518263ffffffff1660e060020a02815260040180828152602001915050600060405180830381600087803b15801561267857600080fd5b505af115801561268c573d6000803e3d6000fd5b505050506126b3565b80156126a7576125f785338486613447565b6126b385333086613447565b5050505050565b60608060008060008060008060006126d06135a2565b8c516002900460405190808252806020026020018201604052801561270f57816020015b6126fc6135a2565b8152602001906001900390816126f45790505b5098506000975061273f7f424e54546f6b656e000000000000000000000000000000000000000000000000611fd2565b9650600095505b60018d51038610156128da578c8660010181518110151561276357fe5b90602001906020020151945084600160a060020a0316638da5cb5b6040518163ffffffff1660e060020a028152600401602060405180830381600087803b1580156127ad57600080fd5b505af11580156127c1573d6000803e3d6000fd5b505050506040513d60208110156127d757600080fd5b50518d519094508d90600288019081106127ed57fe5b9060200190602002015192508a8015612804575087155b8015612821575086600160a060020a031683600160a060020a0316145b9150811561282e57600197505b60e06040519081016040528085600160a060020a0316815260200186600160a060020a031681526020018e8881518110151561286657fe5b90602001906020020151600160a060020a0316815260200184600160a060020a031681526020016000600160a060020a031681526020016128a686613269565b1515815283151560209091015289600288048151811015156128c457fe5b6020908102909101015260029590950194612746565b8860008151811015156128e957fe5b6020908102909101810151604080820151600160a060020a0316600090815260059093529091205490915060ff161561295f578060a00151156129455773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee604082015261295f565b8051612950906132fa565b600160a060020a031660408201525b88518990600019810190811061297157fe5b60209081029091018101516060810151600160a060020a03166000908152600590925260409091205490915060ff16156129e8578060a00151156129ce5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60608201526129e8565b80516129d9906132fa565b600160a060020a031660608201525b600095505b8851861015612ac0578886815181101515612a0457fe5b9060200190602002015190508060a0015115612aae578060c0015115612a2f57306080820152612aa9565b6001895103861415612a4f57600160a060020a038c166080820152612aa9565b8886600101815181101515612a6057fe5b9060200190602002015160a0015115612aa2578886600101815181101515612a8457fe5b6020908102909101015151600160a060020a03166080820152612aa9565b3060808201525b612ab5565b3060808201525b6001909501946129ed565b50969b9a5050505050505050505050565b600080600080612adf6135a2565b6000899350600092505b8a51831015612fca578a83815181101515612b0057fe5b9060200190602002015191508160a0015115612b91578215801590612b4d57508a5130908c906000198601908110612b3457fe5b9060200190602002015160800151600160a060020a0316145b8015612b745750604080830151600160a060020a031660009081526005602052205460ff16155b15612b8c57612b8c826040015183600001518661206a565b612bc7565b8160200151600160a060020a03168260400151600160a060020a0316141515612bc757612bc78260400151836000015186613114565b8160a001511515612c8a578151604080840151606085015182517f5e5144eb000000000000000000000000000000000000000000000000000000008152600160a060020a039283166004820152908216602482015260448101889052600160648201529151921691635e5144eb916084808201926020929091908290030181600087803b158015612c5757600080fd5b505af1158015612c6b573d6000803e3d6000fd5b505050506040513d6020811015612c8157600080fd5b50519450612e27565b604080830151600160a060020a031660009081526005602052205460ff1615612d685781516040808401516060850151608086015183517fe8dc12ff000000000000000000000000000000000000000000000000000000008152600160a060020a03938416600482015291831660248301526044820189905233606483015282166084820152915192169163e8dc12ff91349160a480830192602092919082900301818588803b158015612d3d57600080fd5b505af1158015612d51573d6000803e3d6000fd5b50505050506040513d6020811015612c8157600080fd5b81516040808401516060850151608086015183517fe8dc12ff000000000000000000000000000000000000000000000000000000008152600160a060020a03938416600482015291831660248301526044820189905233606483015282166084820152915192169163e8dc12ff9160a4808201926020929091908290030181600087803b158015612df857600080fd5b505af1158015612e0c573d6000803e3d6000fd5b505050506040513d6020811015612e2257600080fd5b505194505b8160c0015115612f3957612e48620f42406112c0878a63ffffffff61215b16565b90508160600151600160a060020a031663a9059cbb89836040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050602060405180830381600087803b158015612eb157600080fd5b505af1158015612ec5573d6000803e3d6000fd5b505050506040513d6020811015612edb57600080fd5b50511515612f33576040805160e560020a62461bcd02815260206004820152601760248201527f4552525f4645455f5452414e534645525f4641494c4544000000000000000000604482015290519081900360640190fd5b80850394505b8160600151600160a060020a03168260400151600160a060020a03168360200151600160a060020a03167f7154b38b5dd31bb3122436a96d4e09aba5b323ae1fd580025fab55074334c0958789336040518084815260200183815260200182600160a060020a0316600160a060020a03168152602001935050505060405180910390a4849350600190920191612ae9565b88851015613022576040805160e560020a62461bcd02815260206004820152601260248201527f4552525f52455455524e5f544f4f5f4c4f570000000000000000000000000000604482015290519081900360640190fd5b50929998505050505050505050565b6130396135a2565b600084600186510381518110151561304d57fe5b602090810290910101516080810151909250600160a060020a03163014613073576126b3565b506060810151600160a060020a03811660009081526005602052604090205460ff16156131095760a0820151156130a657fe5b80600160a060020a031663205c287884866040518363ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200182815260200192505050600060405180830381600087803b15801561267857600080fd5b6126b381848661206a565b604080517fdd62ed3e000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a038481166024830152915160009286169163dd62ed3e91604480830192602092919082900301818787803b15801561317f57600080fd5b505af1158015613193573d6000803e3d6000fd5b505050506040513d60208110156131a957600080fd5b50519050818110156131d55760008111156131ca576131ca848460006134ff565b6131d58484846134ff565b50505050565b6131e36135de565b602060405190810160405280600181525090506020818351602085016000875af180151561321057600080fd5b50805115156120f2576040805160e560020a62461bcd02815260206004820152601360248201527f4552525f5452414e534645525f4641494c454400000000000000000000000000604482015290519081900360640190fd5b6000806132746135de565b604080517f69735632384f72486967686572282900000000000000000000000000000000008152815190819003600f018120600482526024820190925260208082018051600160e060020a0316600160e060020a0319909416939093178352815191929091849188611388fa92508280156132ef5750815115155b93505b505050919050565b60008060008084600160a060020a03166371f52bf36040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561333e57600080fd5b505af1158015613352573d6000803e3d6000fd5b505050506040513d602081101561336857600080fd5b505161ffff169250600091505b828210156134295784600160a060020a03166319b64015836040518263ffffffff1660e060020a02815260040180828152602001915050602060405180830381600087803b1580156133c657600080fd5b505af11580156133da573d6000803e3d6000fd5b505050506040513d60208110156133f057600080fd5b5051600160a060020a03811660009081526005602052604090205490915060ff161561341e578093506132f2565b600190910190613375565b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee949350505050565b604080517f7472616e7366657246726f6d28616464726573732c616464726573732c75696e81527f74323536290000000000000000000000000000000000000000000000000000006020808301919091528251918290036025018220600160a060020a03808816602485015286166044840152606480840186905284518085039091018152608490930190935281018051600160e060020a0316600160e060020a0319909316929092179091526131d59085906131db565b604080517f617070726f766528616464726573732c75696e7432353629000000000000000081528151908190036018018120600160a060020a03851660248301526044808301859052835180840390910181526064909201909252602081018051600160e060020a0316600160e060020a0319909316929092179091526120f29084906131db565b60408051808201825290600290829080388339509192915050565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b60206040519081016040528060019060208202803883395091929150505600a165627a7a723058204c6d6f7ef1fe9e0170d19e339c72b77e0e50abade5d2e911ba59ffce0be466220029
Verified Source Code Partial Match
Compiler: v0.4.26+commit.4563c3fc
EVM: byzantium
Optimization: Yes (200 runs)
BancorNetwork.sol 1520 lines
// File: contracts/token/interfaces/IERC20Token.sol
pragma solidity 0.4.26;
/*
ERC20 Standard Token interface
*/
contract IERC20Token {
// these functions aren't abstract since the compiler emits automatically generated getter functions as external
function name() public view returns (string) {this;}
function symbol() public view returns (string) {this;}
function decimals() public view returns (uint8) {this;}
function totalSupply() public view returns (uint256) {this;}
function balanceOf(address _owner) public view returns (uint256) {_owner; this;}
function allowance(address _owner, address _spender) public view returns (uint256) {_owner; _spender; this;}
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
}
// File: contracts/IBancorNetwork.sol
pragma solidity 0.4.26;
/*
Bancor Network interface
*/
contract IBancorNetwork {
function convert2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _affiliateAccount,
uint256 _affiliateFee
) public payable returns (uint256);
function claimAndConvert2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _affiliateAccount,
uint256 _affiliateFee
) public returns (uint256);
function convertFor2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
address _affiliateAccount,
uint256 _affiliateFee
) public payable returns (uint256);
function claimAndConvertFor2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for,
address _affiliateAccount,
uint256 _affiliateFee
) public returns (uint256);
// deprecated, backward compatibility
function convert(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn
) public payable returns (uint256);
// deprecated, backward compatibility
function claimAndConvert(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn
) public returns (uint256);
// deprecated, backward compatibility
function convertFor(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for
) public payable returns (uint256);
// deprecated, backward compatibility
function claimAndConvertFor(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
address _for
) public returns (uint256);
}
// File: contracts/IConversionPathFinder.sol
pragma solidity 0.4.26;
/*
Conversion Path Finder interface
*/
contract IConversionPathFinder {
function findPath(address _sourceToken, address _targetToken) public view returns (address[] memory);
}
// File: contracts/utility/interfaces/IOwned.sol
pragma solidity 0.4.26;
/*
Owned contract interface
*/
contract IOwned {
// this function isn't abstract since the compiler emits automatically generated getter functions as external
function owner() public view returns (address) {this;}
function transferOwnership(address _newOwner) public;
function acceptOwnership() public;
}
// File: contracts/utility/interfaces/ITokenHolder.sol
pragma solidity 0.4.26;
/*
Token Holder interface
*/
contract ITokenHolder is IOwned {
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public;
}
// File: contracts/converter/interfaces/IConverterAnchor.sol
pragma solidity 0.4.26;
/*
Converter Anchor interface
*/
contract IConverterAnchor is IOwned, ITokenHolder {
}
// File: contracts/utility/interfaces/IWhitelist.sol
pragma solidity 0.4.26;
/*
Whitelist interface
*/
contract IWhitelist {
function isWhitelisted(address _address) public view returns (bool);
}
// File: contracts/converter/interfaces/IConverter.sol
pragma solidity 0.4.26;
/*
Converter interface
*/
contract IConverter is IOwned {
function converterType() public pure returns (uint16);
function anchor() public view returns (IConverterAnchor) {this;}
function isActive() public view returns (bool);
function rateAndFee(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount) public view returns (uint256, uint256);
function convert(IERC20Token _sourceToken,
IERC20Token _targetToken,
uint256 _amount,
address _trader,
address _beneficiary) public payable returns (uint256);
function conversionWhitelist() public view returns (IWhitelist) {this;}
function conversionFee() public view returns (uint32) {this;}
function maxConversionFee() public view returns (uint32) {this;}
function reserveBalance(IERC20Token _reserveToken) public view returns (uint256);
function() external payable;
function transferAnchorOwnership(address _newOwner) public;
function acceptAnchorOwnership() public;
function setConversionFee(uint32 _conversionFee) public;
function setConversionWhitelist(IWhitelist _whitelist) public;
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount) public;
function withdrawETH(address _to) public;
function addReserve(IERC20Token _token, uint32 _ratio) public;
// deprecated, backward compatibility
function token() public view returns (IConverterAnchor);
function transferTokenOwnership(address _newOwner) public;
function acceptTokenOwnership() public;
function connectors(address _address) public view returns (uint256, uint32, bool, bool, bool);
function getConnectorBalance(IERC20Token _connectorToken) public view returns (uint256);
function connectorTokens(uint256 _index) public view returns (IERC20Token);
function connectorTokenCount() public view returns (uint16);
}
// File: contracts/converter/interfaces/IBancorFormula.sol
pragma solidity 0.4.26;
/*
Bancor Formula interface
*/
contract IBancorFormula {
function purchaseRate(uint256 _supply,
uint256 _reserveBalance,
uint32 _reserveWeight,
uint256 _amount)
public view returns (uint256);
function saleRate(uint256 _supply,
uint256 _reserveBalance,
uint32 _reserveWeight,
uint256 _amount)
public view returns (uint256);
function crossReserveRate(uint256 _sourceReserveBalance,
uint32 _sourceReserveWeight,
uint256 _targetReserveBalance,
uint32 _targetReserveWeight,
uint256 _amount)
public view returns (uint256);
function fundCost(uint256 _supply,
uint256 _reserveBalance,
uint32 _reserveRatio,
uint256 _amount)
public view returns (uint256);
function liquidateRate(uint256 _supply,
uint256 _reserveBalance,
uint32 _reserveRatio,
uint256 _amount)
public view returns (uint256);
}
// File: contracts/utility/Owned.sol
pragma solidity 0.4.26;
/**
* @dev Provides support and utilities for contract ownership
*/
contract Owned is IOwned {
address public owner;
address public newOwner;
/**
* @dev triggered when the owner is updated
*
* @param _prevOwner previous owner
* @param _newOwner new owner
*/
event OwnerUpdate(address indexed _prevOwner, address indexed _newOwner);
/**
* @dev initializes a new Owned instance
*/
constructor() public {
owner = msg.sender;
}
// allows execution by the owner only
modifier ownerOnly {
_ownerOnly();
_;
}
// error message binary size optimization
function _ownerOnly() internal view {
require(msg.sender == owner, "ERR_ACCESS_DENIED");
}
/**
* @dev allows transferring the contract ownership
* the new owner still needs to accept the transfer
* can only be called by the contract owner
*
* @param _newOwner new contract owner
*/
function transferOwnership(address _newOwner) public ownerOnly {
require(_newOwner != owner, "ERR_SAME_OWNER");
newOwner = _newOwner;
}
/**
* @dev used by a new owner to accept an ownership transfer
*/
function acceptOwnership() public {
require(msg.sender == newOwner, "ERR_ACCESS_DENIED");
emit OwnerUpdate(owner, newOwner);
owner = newOwner;
newOwner = address(0);
}
}
// File: contracts/utility/Utils.sol
pragma solidity 0.4.26;
/**
* @dev Utilities & Common Modifiers
*/
contract Utils {
// verifies that a value is greater than zero
modifier greaterThanZero(uint256 _value) {
_greaterThanZero(_value);
_;
}
// error message binary size optimization
function _greaterThanZero(uint256 _value) internal pure {
require(_value > 0, "ERR_ZERO_VALUE");
}
// validates an address - currently only checks that it isn't null
modifier validAddress(address _address) {
_validAddress(_address);
_;
}
// error message binary size optimization
function _validAddress(address _address) internal pure {
require(_address != address(0), "ERR_INVALID_ADDRESS");
}
// verifies that the address is different than this contract address
modifier notThis(address _address) {
_notThis(_address);
_;
}
// error message binary size optimization
function _notThis(address _address) internal view {
require(_address != address(this), "ERR_ADDRESS_IS_SELF");
}
}
// File: contracts/utility/interfaces/IContractRegistry.sol
pragma solidity 0.4.26;
/*
Contract Registry interface
*/
contract IContractRegistry {
function addressOf(bytes32 _contractName) public view returns (address);
// deprecated, backward compatibility
function getAddress(bytes32 _contractName) public view returns (address);
}
// File: contracts/utility/ContractRegistryClient.sol
pragma solidity 0.4.26;
/**
* @dev Base contract for ContractRegistry clients
*/
contract ContractRegistryClient is Owned, Utils {
bytes32 internal constant CONTRACT_REGISTRY = "ContractRegistry";
bytes32 internal constant BANCOR_NETWORK = "BancorNetwork";
bytes32 internal constant BANCOR_FORMULA = "BancorFormula";
bytes32 internal constant CONVERTER_FACTORY = "ConverterFactory";
bytes32 internal constant CONVERSION_PATH_FINDER = "ConversionPathFinder";
bytes32 internal constant CONVERTER_UPGRADER = "BancorConverterUpgrader";
bytes32 internal constant CONVERTER_REGISTRY = "BancorConverterRegistry";
bytes32 internal constant CONVERTER_REGISTRY_DATA = "BancorConverterRegistryData";
bytes32 internal constant BNT_TOKEN = "BNTToken";
bytes32 internal constant BANCOR_X = "BancorX";
bytes32 internal constant BANCOR_X_UPGRADER = "BancorXUpgrader";
IContractRegistry public registry; // address of the current contract-registry
IContractRegistry public prevRegistry; // address of the previous contract-registry
bool public onlyOwnerCanUpdateRegistry; // only an owner can update the contract-registry
/**
* @dev verifies that the caller is mapped to the given contract name
*
* @param _contractName contract name
*/
modifier only(bytes32 _contractName) {
_only(_contractName);
_;
}
// error message binary size optimization
function _only(bytes32 _contractName) internal view {
require(msg.sender == addressOf(_contractName), "ERR_ACCESS_DENIED");
}
/**
* @dev initializes a new ContractRegistryClient instance
*
* @param _registry address of a contract-registry contract
*/
constructor(IContractRegistry _registry) internal validAddress(_registry) {
registry = IContractRegistry(_registry);
prevRegistry = IContractRegistry(_registry);
}
/**
* @dev updates to the new contract-registry
*/
function updateRegistry() public {
// verify that this function is permitted
require(msg.sender == owner || !onlyOwnerCanUpdateRegistry, "ERR_ACCESS_DENIED");
// get the new contract-registry
IContractRegistry newRegistry = IContractRegistry(addressOf(CONTRACT_REGISTRY));
// verify that the new contract-registry is different and not zero
require(newRegistry != address(registry) && newRegistry != address(0), "ERR_INVALID_REGISTRY");
// verify that the new contract-registry is pointing to a non-zero contract-registry
require(newRegistry.addressOf(CONTRACT_REGISTRY) != address(0), "ERR_INVALID_REGISTRY");
// save a backup of the current contract-registry before replacing it
prevRegistry = registry;
// replace the current contract-registry with the new contract-registry
registry = newRegistry;
}
/**
* @dev restores the previous contract-registry
*/
function restoreRegistry() public ownerOnly {
// restore the previous contract-registry
registry = prevRegistry;
}
/**
* @dev restricts the permission to update the contract-registry
*
* @param _onlyOwnerCanUpdateRegistry indicates whether or not permission is restricted to owner only
*/
function restrictRegistryUpdate(bool _onlyOwnerCanUpdateRegistry) public ownerOnly {
// change the permission to update the contract-registry
onlyOwnerCanUpdateRegistry = _onlyOwnerCanUpdateRegistry;
}
/**
* @dev returns the address associated with the given contract name
*
* @param _contractName contract name
*
* @return contract address
*/
function addressOf(bytes32 _contractName) internal view returns (address) {
return registry.addressOf(_contractName);
}
}
// File: contracts/utility/ReentrancyGuard.sol
pragma solidity 0.4.26;
/**
* @dev ReentrancyGuard
*
* The contract provides protection against re-entrancy - calling a function (directly or
* indirectly) from within itself.
*/
contract ReentrancyGuard {
// true while protected code is being executed, false otherwise
bool private locked = false;
/**
* @dev ensures instantiation only by sub-contracts
*/
constructor() internal {}
// protects a function against reentrancy attacks
modifier protected() {
_protected();
locked = true;
_;
locked = false;
}
// error message binary size optimization
function _protected() internal view {
require(!locked, "ERR_REENTRANCY");
}
}
// File: contracts/utility/TokenHandler.sol
pragma solidity 0.4.26;
contract TokenHandler {
bytes4 private constant APPROVE_FUNC_SELECTOR = bytes4(keccak256("approve(address,uint256)"));
bytes4 private constant TRANSFER_FUNC_SELECTOR = bytes4(keccak256("transfer(address,uint256)"));
bytes4 private constant TRANSFER_FROM_FUNC_SELECTOR = bytes4(keccak256("transferFrom(address,address,uint256)"));
/**
* @dev executes the ERC20 token's `approve` function and reverts upon failure
* the main purpose of this function is to prevent a non standard ERC20 token
* from failing silently
*
* @param _token ERC20 token address
* @param _spender approved address
* @param _value allowance amount
*/
function safeApprove(IERC20Token _token, address _spender, uint256 _value) internal {
execute(_token, abi.encodeWithSelector(APPROVE_FUNC_SELECTOR, _spender, _value));
}
/**
* @dev executes the ERC20 token's `transfer` function and reverts upon failure
* the main purpose of this function is to prevent a non standard ERC20 token
* from failing silently
*
* @param _token ERC20 token address
* @param _to target address
* @param _value transfer amount
*/
function safeTransfer(IERC20Token _token, address _to, uint256 _value) internal {
execute(_token, abi.encodeWithSelector(TRANSFER_FUNC_SELECTOR, _to, _value));
}
/**
* @dev executes the ERC20 token's `transferFrom` function and reverts upon failure
* the main purpose of this function is to prevent a non standard ERC20 token
* from failing silently
*
* @param _token ERC20 token address
* @param _from source address
* @param _to target address
* @param _value transfer amount
*/
function safeTransferFrom(IERC20Token _token, address _from, address _to, uint256 _value) internal {
execute(_token, abi.encodeWithSelector(TRANSFER_FROM_FUNC_SELECTOR, _from, _to, _value));
}
/**
* @dev executes a function on the ERC20 token and reverts upon failure
* the main purpose of this function is to prevent a non standard ERC20 token
* from failing silently
*
* @param _token ERC20 token address
* @param _data data to pass in to the token's contract for execution
*/
function execute(IERC20Token _token, bytes memory _data) private {
uint256[1] memory ret = [uint256(1)];
assembly {
let success := call(
gas, // gas remaining
_token, // destination address
0, // no ether
add(_data, 32), // input buffer (starts after the first 32 bytes in the `data` array)
mload(_data), // input length (loaded from the first 32 bytes in the `data` array)
ret, // output buffer
32 // output length
)
if iszero(success) {
revert(0, 0)
}
}
require(ret[0] != 0, "ERR_TRANSFER_FAILED");
}
}
// File: contracts/utility/TokenHolder.sol
pragma solidity 0.4.26;
/**
* @dev We consider every contract to be a 'token holder' since it's currently not possible
* for a contract to deny receiving tokens.
*
* The TokenHolder's contract sole purpose is to provide a safety mechanism that allows
* the owner to send tokens that were sent to the contract by mistake back to their sender.
*
* Note that we use the non standard ERC-20 interface which has no return value for transfer
* in order to support both non standard as well as standard token contracts.
* see https://github.com/ethereum/solidity/issues/4116
*/
contract TokenHolder is ITokenHolder, TokenHandler, Owned, Utils {
/**
* @dev withdraws tokens held by the contract and sends them to an account
* can only be called by the owner
*
* @param _token ERC20 token contract address
* @param _to account to receive the new amount
* @param _amount amount to withdraw
*/
function withdrawTokens(IERC20Token _token, address _to, uint256 _amount)
public
ownerOnly
validAddress(_token)
validAddress(_to)
notThis(_to)
{
safeTransfer(_token, _to, _amount);
}
}
// File: contracts/utility/SafeMath.sol
pragma solidity 0.4.26;
/**
* @dev Library for basic math operations with overflow/underflow protection
*/
library SafeMath {
/**
* @dev returns the sum of _x and _y, reverts if the calculation overflows
*
* @param _x value 1
* @param _y value 2
*
* @return sum
*/
function add(uint256 _x, uint256 _y) internal pure returns (uint256) {
uint256 z = _x + _y;
require(z >= _x, "ERR_OVERFLOW");
return z;
}
/**
* @dev returns the difference of _x minus _y, reverts if the calculation underflows
*
* @param _x minuend
* @param _y subtrahend
*
* @return difference
*/
function sub(uint256 _x, uint256 _y) internal pure returns (uint256) {
require(_x >= _y, "ERR_UNDERFLOW");
return _x - _y;
}
/**
* @dev returns the product of multiplying _x by _y, reverts if the calculation overflows
*
* @param _x factor 1
* @param _y factor 2
*
* @return product
*/
function mul(uint256 _x, uint256 _y) internal pure returns (uint256) {
// gas optimization
if (_x == 0)
return 0;
uint256 z = _x * _y;
require(z / _x == _y, "ERR_OVERFLOW");
return z;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*
* @param _x dividend
* @param _y divisor
*
* @return quotient
*/
function div(uint256 _x, uint256 _y) internal pure returns (uint256) {
require(_y > 0, "ERR_DIVIDE_BY_ZERO");
uint256 c = _x / _y;
return c;
}
}
// File: contracts/token/interfaces/IEtherToken.sol
pragma solidity 0.4.26;
/*
Ether Token interface
*/
contract IEtherToken is IERC20Token {
function deposit() public payable;
function withdraw(uint256 _amount) public;
function depositTo(address _to) public payable;
function withdrawTo(address _to, uint256 _amount) public;
}
// File: contracts/token/interfaces/ISmartToken.sol
pragma solidity 0.4.26;
/*
Smart Token interface
*/
contract ISmartToken is IConverterAnchor, IERC20Token {
function disableTransfers(bool _disable) public;
function issue(address _to, uint256 _amount) public;
function destroy(address _from, uint256 _amount) public;
}
// File: contracts/bancorx/interfaces/IBancorX.sol
pragma solidity 0.4.26;
contract IBancorX {
function token() public view returns (IERC20Token) {this;}
function xTransfer(bytes32 _toBlockchain, bytes32 _to, uint256 _amount, uint256 _id) public;
function getXTransferAmount(uint256 _xTransferId, address _for) public view returns (uint256);
}
// File: contracts/BancorNetwork.sol
pragma solidity 0.4.26;
// interface of older converters for backward compatibility
contract ILegacyConverter {
function change(IERC20Token _sourceToken, IERC20Token _targetToken, uint256 _amount, uint256 _minReturn) public returns (uint256);
}
/**
* @dev The BancorNetwork contract is the main entry point for Bancor token conversions.
* It also allows for the conversion of any token in the Bancor Network to any other token in a single
* transaction by providing a conversion path.
*
* A note on Conversion Path: Conversion path is a data structure that is used when converting a token
* to another token in the Bancor Network, when the conversion cannot necessarily be done by a single
* converter and might require multiple 'hops'.
* The path defines which converters should be used and what kind of conversion should be done in each step.
*
* The path format doesn't include complex structure; instead, it is represented by a single array
* in which each 'hop' is represented by a 2-tuple - converter anchor & target token.
* In addition, the first element is always the source token.
* The converter anchor is only used as a pointer to a converter (since converter addresses are more
* likely to change as opposed to anchor addresses).
*
* Format:
* [source token, converter anchor, target token, converter anchor, target token...]
*/
contract BancorNetwork is IBancorNetwork, TokenHolder, ContractRegistryClient, ReentrancyGuard {
using SafeMath for uint256;
uint256 private constant CONVERSION_FEE_RESOLUTION = 1000000;
uint256 private constant AFFILIATE_FEE_RESOLUTION = 1000000;
address private constant ETH_RESERVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
struct ConversionStep {
IConverter converter;
IConverterAnchor anchor;
IERC20Token sourceToken;
IERC20Token targetToken;
address beneficiary;
bool isV28OrHigherConverter;
bool processAffiliateFee;
}
uint256 public maxAffiliateFee = 30000; // maximum affiliate-fee
mapping (address => bool) public etherTokens; // list of all supported ether tokens
/**
* @dev triggered when a conversion between two tokens occurs
*
* @param _smartToken anchor governed by the converter
* @param _fromToken source ERC20 token
* @param _toToken target ERC20 token
* @param _fromAmount amount converted, in the source token
* @param _toAmount amount returned, minus conversion fee
* @param _trader wallet that initiated the trade
*/
event Conversion(
address indexed _smartToken,
address indexed _fromToken,
address indexed _toToken,
uint256 _fromAmount,
uint256 _toAmount,
address _trader
);
/**
* @dev initializes a new BancorNetwork instance
*
* @param _registry address of a contract registry contract
*/
constructor(IContractRegistry _registry) ContractRegistryClient(_registry) public {
etherTokens[ETH_RESERVE_ADDRESS] = true;
}
/**
* @dev allows the owner to update the maximum affiliate-fee
*
* @param _maxAffiliateFee maximum affiliate-fee
*/
function setMaxAffiliateFee(uint256 _maxAffiliateFee)
public
ownerOnly
{
require(_maxAffiliateFee <= AFFILIATE_FEE_RESOLUTION, "ERR_INVALID_AFFILIATE_FEE");
maxAffiliateFee = _maxAffiliateFee;
}
/**
* @dev allows the owner to register/unregister ether tokens
*
* @param _token ether token contract address
* @param _register true to register, false to unregister
*/
function registerEtherToken(IEtherToken _token, bool _register)
public
ownerOnly
validAddress(_token)
notThis(_token)
{
etherTokens[_token] = _register;
}
/**
* @dev returns the conversion path between two tokens in the network
* note that this method is quite expensive in terms of gas and should generally be called off-chain
*
* @param _sourceToken source token address
* @param _targetToken target token address
*
* @return conversion path between the two tokens
*/
function conversionPath(IERC20Token _sourceToken, IERC20Token _targetToken) public view returns (address[]) {
IConversionPathFinder pathFinder = IConversionPathFinder(addressOf(CONVERSION_PATH_FINDER));
return pathFinder.findPath(_sourceToken, _targetToken);
}
/**
* @dev returns the expected rate of converting a given amount on a given path
* note that there is no support for circular paths
*
* @param _path conversion path (see conversion path format above)
* @param _amount amount of _path[0] tokens received from the sender
*
* @return expected rate
*/
function rateByPath(IERC20Token[] _path, uint256 _amount) public view returns (uint256) {
uint256 amount;
uint256 fee;
uint256 supply;
uint256 balance;
uint32 weight;
IConverter converter;
IBancorFormula formula = IBancorFormula(addressOf(BANCOR_FORMULA));
amount = _amount;
// verify that the number of elements is larger than 2 and odd
require(_path.length > 2 && _path.length % 2 == 1, "ERR_INVALID_PATH");
// iterate over the conversion path
for (uint256 i = 2; i < _path.length; i += 2) {
IERC20Token sourceToken = _path[i - 2];
IERC20Token anchor = _path[i - 1];
IERC20Token targetToken = _path[i];
converter = IConverter(IConverterAnchor(anchor).owner());
// backward compatibility
sourceToken = getConverterTokenAddress(converter, sourceToken);
targetToken = getConverterTokenAddress(converter, targetToken);
if (targetToken == anchor) { // buy the smart token
// check if the current smart token has changed
if (i < 3 || anchor != _path[i - 3])
supply = ISmartToken(anchor).totalSupply();
// get the amount & the conversion fee
balance = converter.getConnectorBalance(sourceToken);
(, weight, , , ) = converter.connectors(sourceToken);
amount = formula.purchaseRate(supply, balance, weight, amount);
fee = amount.mul(converter.conversionFee()).div(CONVERSION_FEE_RESOLUTION);
amount -= fee;
// update the smart token supply for the next iteration
supply = supply.add(amount);
}
else if (sourceToken == anchor) { // sell the smart token
// check if the current smart token has changed
if (i < 3 || anchor != _path[i - 3])
supply = ISmartToken(anchor).totalSupply();
// get the amount & the conversion fee
balance = converter.getConnectorBalance(targetToken);
(, weight, , , ) = converter.connectors(targetToken);
amount = formula.saleRate(supply, balance, weight, amount);
fee = amount.mul(converter.conversionFee()).div(CONVERSION_FEE_RESOLUTION);
amount -= fee;
// update the smart token supply for the next iteration
supply = supply.sub(amount);
}
else { // cross reserve conversion
(amount, fee) = getReturn(converter, sourceToken, targetToken, amount);
}
}
return amount;
}
/**
* @dev converts the token to any other token in the bancor network by following
* a predefined conversion path and transfers the result tokens to a target account
* affiliate account/fee can also be passed in to receive a conversion fee (on top of the liquidity provider fees)
* note that the network should already have been given allowance of the source token (if not ETH)
*
* @param _path conversion path, see conversion path format above
* @param _amount amount to convert from, in the source token
* @param _minReturn if the conversion results in an amount smaller than the minimum return - it is cancelled, must be greater than zero
* @param _beneficiary account that will receive the conversion result or 0x0 to send the result to the sender account
* @param _affiliateAccount wallet address to receive the affiliate fee or 0x0 to disable affiliate fee
* @param _affiliateFee affiliate fee in PPM or 0 to disable affiliate fee
*
* @return amount of tokens received from the conversion
*/
function convertByPath(IERC20Token[] _path, uint256 _amount, uint256 _minReturn, address _beneficiary, address _affiliateAccount, uint256 _affiliateFee)
public
payable
protected
greaterThanZero(_minReturn)
returns (uint256)
{
// verify that the path contrains at least a single 'hop' and that the number of elements is odd
require(_path.length > 2 && _path.length % 2 == 1, "ERR_INVALID_PATH");
// validate msg.value and prepare the source token for the conversion
handleSourceToken(_path[0], IConverterAnchor(_path[1]), _amount);
// check if affiliate fee is enabled
bool affiliateFeeEnabled = false;
if (address(_affiliateAccount) == 0) {
require(_affiliateFee == 0, "ERR_INVALID_AFFILIATE_FEE");
}
else {
require(0 < _affiliateFee && _affiliateFee <= maxAffiliateFee, "ERR_INVALID_AFFILIATE_FEE");
affiliateFeeEnabled = true;
}
// check if beneficiary is set
address beneficiary = msg.sender;
if (_beneficiary != address(0))
beneficiary = _beneficiary;
// convert and get the resulting amount
ConversionStep[] memory data = createConversionData(_path, beneficiary, affiliateFeeEnabled);
uint256 amount = doConversion(data, _amount, _minReturn, _affiliateAccount, _affiliateFee);
// handle the conversion target tokens
handleTargetToken(data, amount, beneficiary);
return amount;
}
/**
* @dev converts any other token to BNT in the bancor network by following
a predefined conversion path and transfers the result to an account on a different blockchain
* note that the network should already have been given allowance of the source token (if not ETH)
*
* @param _path conversion path, see conversion path format above
* @param _amount amount to convert from, in the source token
* @param _minReturn if the conversion results in an amount smaller than the minimum return - it is cancelled, must be greater than zero
* @param _targetBlockchain blockchain BNT will be issued on
* @param _targetAccount address/account on the target blockchain to send the BNT to
* @param _conversionId pre-determined unique (if non zero) id which refers to this transaction
*
* @return the amount of BNT received from this conversion
*/
function xConvert(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
bytes32 _targetBlockchain,
bytes32 _targetAccount,
uint256 _conversionId
)
public
payable
returns (uint256)
{
return xConvert2(_path, _amount, _minReturn, _targetBlockchain, _targetAccount, _conversionId, address(0), 0);
}
/**
* @dev converts any other token to BNT in the bancor network by following
a predefined conversion path and transfers the result to an account on a different blockchain
* note that the network should already have been given allowance of the source token (if not ETH)
*
* @param _path conversion path, see conversion path format above
* @param _amount amount to convert from, in the source token
* @param _minReturn if the conversion results in an amount smaller than the minimum return - it is cancelled, must be greater than zero
* @param _targetBlockchain blockchain BNT will be issued on
* @param _targetAccount address/account on the target blockchain to send the BNT to
* @param _conversionId pre-determined unique (if non zero) id which refers to this transaction
* @param _affiliateAccount affiliate account
* @param _affiliateFee affiliate fee in PPM
*
* @return the amount of BNT received from this conversion
*/
function xConvert2(
IERC20Token[] _path,
uint256 _amount,
uint256 _minReturn,
bytes32 _targetBlockchain,
bytes32 _targetAccount,
uint256 _conversionId,
address _affiliateAccount,
uint256 _affiliateFee
)
public
payable
greaterThanZero(_minReturn)
returns (uint256)
{
IERC20Token targetToken = _path[_path.length - 1];
IBancorX bancorX = IBancorX(addressOf(BANCOR_X));
// verify that the destination token is BNT
require(targetToken == addressOf(BNT_TOKEN), "ERR_INVALID_TARGET_TOKEN");
// convert and get the resulting amount
uint256 amount = convertByPath(_path, _amount, _minReturn, this, _affiliateAccount, _affiliateFee);
// grant BancorX allowance
ensureAllowance(targetToken, bancorX, amount);
// transfer the resulting amount to BancorX
bancorX.xTransfer(_targetBlockchain, _targetAccount, amount, _conversionId);
return amount;
}
/**
* @dev allows a user to convert a token that was sent from another blockchain into any other
* token on the BancorNetwork
* ideally this transaction is created before the previous conversion is even complete, so
* so the input amount isn't known at that point - the amount is actually take from the
* BancorX contract directly by specifying the conversion id
*
* @param _path conversion path
* @param _bancorX address of the BancorX contract for the source token
* @param _conversionId pre-determined unique (if non zero) id which refers to this conversion
* @param _minReturn if the conversion results in an amount smaller than the minimum return - it is cancelled, must be nonzero
* @param _beneficiary wallet to receive the conversion result
*
* @return amount of tokens received from the conversion
*/
function completeXConversion(IERC20Token[] _path, IBancorX _bancorX, uint256 _conversionId, uint256 _minReturn, address _beneficiary)
public returns (uint256)
{
// verify that the source token is the BancorX token
require(_path[0] == _bancorX.token(), "ERR_INVALID_SOURCE_TOKEN");
// get conversion amount from BancorX contract
uint256 amount = _bancorX.getXTransferAmount(_conversionId, msg.sender);
// perform the conversion
return convertByPath(_path, amount, _minReturn, _beneficiary, address(0), 0);
}
/**
* @dev executes the actual conversion by following the conversion path
*
* @param _data conversion data, see ConversionStep struct above
* @param _amount amount to convert from, in the source token
* @param _minReturn if the conversion results in an amount smaller than the minimum return - it is cancelled, must be greater than zero
* @param _affiliateAccount affiliate account
* @param _affiliateFee affiliate fee in PPM
*
* @return amount of tokens received from the conversion
*/
function doConversion(
ConversionStep[] _data,
uint256 _amount,
uint256 _minReturn,
address _affiliateAccount,
uint256 _affiliateFee
) private returns (uint256) {
uint256 toAmount;
uint256 fromAmount = _amount;
// iterate over the conversion data
for (uint256 i = 0; i < _data.length; i++) {
ConversionStep memory stepData = _data[i];
// newer converter
if (stepData.isV28OrHigherConverter) {
// transfer the tokens to the converter only if the network contract currently holds the tokens
// not needed with ETH or if it's the first conversion step
if (i != 0 && _data[i - 1].beneficiary == address(this) && !etherTokens[stepData.sourceToken])
safeTransfer(stepData.sourceToken, stepData.converter, fromAmount);
}
// older converter
// if the source token is the smart token, no need to do any transfers as the converter controls it
else if (stepData.sourceToken != ISmartToken(stepData.anchor)) {
// grant allowance for it to transfer the tokens from the network contract
ensureAllowance(stepData.sourceToken, stepData.converter, fromAmount);
}
// do the conversion
if (!stepData.isV28OrHigherConverter)
toAmount = ILegacyConverter(stepData.converter).change(stepData.sourceToken, stepData.targetToken, fromAmount, 1);
else if (etherTokens[stepData.sourceToken])
toAmount = stepData.converter.convert.value(msg.value)(stepData.sourceToken, stepData.targetToken, fromAmount, msg.sender, stepData.beneficiary);
else
toAmount = stepData.converter.convert(stepData.sourceToken, stepData.targetToken, fromAmount, msg.sender, stepData.beneficiary);
// pay affiliate-fee if needed
if (stepData.processAffiliateFee) {
uint256 affiliateAmount = toAmount.mul(_affiliateFee).div(AFFILIATE_FEE_RESOLUTION);
require(stepData.targetToken.transfer(_affiliateAccount, affiliateAmount), "ERR_FEE_TRANSFER_FAILED");
toAmount -= affiliateAmount;
}
emit Conversion(stepData.anchor, stepData.sourceToken, stepData.targetToken, fromAmount, toAmount, msg.sender);
fromAmount = toAmount;
}
// ensure the trade meets the minimum requested amount
require(toAmount >= _minReturn, "ERR_RETURN_TOO_LOW");
return toAmount;
}
/**
* @dev validates msg.value and prepares the conversion source token for the conversion
*
* @param _sourceToken source token of the first conversion step
* @param _anchor converter anchor of the first conversion step
* @param _amount amount to convert from, in the source token
*/
function handleSourceToken(IERC20Token _sourceToken, IConverterAnchor _anchor, uint256 _amount) private {
IConverter firstConverter = IConverter(_anchor.owner());
bool isNewerConverter = isV28OrHigherConverter(firstConverter);
// ETH
if (msg.value > 0) {
// validate msg.value
require(msg.value == _amount, "ERR_ETH_AMOUNT_MISMATCH");
// EtherToken converter - deposit the ETH into the EtherToken
// note that it can still be a non ETH converter if the path is wrong
// but such conversion will simply revert
if (!isNewerConverter)
IEtherToken(getConverterEtherTokenAddress(firstConverter)).deposit.value(msg.value)();
}
// EtherToken
else if (etherTokens[_sourceToken]) {
// claim the tokens - if the source token is ETH reserve, this call will fail
// since in that case the transaction must be sent with msg.value
safeTransferFrom(_sourceToken, msg.sender, this, _amount);
// ETH converter - withdraw the ETH
if (isNewerConverter)
IEtherToken(_sourceToken).withdraw(_amount);
}
// other ERC20 token
else {
// newer converter - transfer the tokens from the sender directly to the converter
// otherwise claim the tokens
if (isNewerConverter)
safeTransferFrom(_sourceToken, msg.sender, firstConverter, _amount);
else
safeTransferFrom(_sourceToken, msg.sender, this, _amount);
}
}
/**
* @dev handles the conversion target token if the network still holds it at the end of the conversion
*
* @param _data conversion data, see ConversionStep struct above
* @param _amount conversion return amount, in the target token
* @param _beneficiary wallet to receive the conversion result
*/
function handleTargetToken(ConversionStep[] _data, uint256 _amount, address _beneficiary) private {
ConversionStep memory stepData = _data[_data.length - 1];
// network contract doesn't hold the tokens, do nothing
if (stepData.beneficiary != address(this))
return;
IERC20Token targetToken = stepData.targetToken;
// ETH / EtherToken
if (etherTokens[targetToken]) {
// newer converter should send ETH directly to the beneficiary
assert(!stepData.isV28OrHigherConverter);
// EtherToken converter - withdraw the ETH and transfer to the beneficiary
IEtherToken(targetToken).withdrawTo(_beneficiary, _amount);
}
// other ERC20 token
else {
safeTransfer(targetToken, _beneficiary, _amount);
}
}
/**
* @dev creates a memory cache of all conversion steps data to minimize logic and external calls during conversions
*
* @param _conversionPath conversion path, see conversion path format above
* @param _beneficiary wallet to receive the conversion result
* @param _affiliateFeeEnabled true if affiliate fee was requested by the sender, false if not
*
* @return cached conversion data to be ingested later on by the conversion flow
*/
function createConversionData(IERC20Token[] _conversionPath, address _beneficiary, bool _affiliateFeeEnabled) private view returns (ConversionStep[]) {
ConversionStep[] memory data = new ConversionStep[](_conversionPath.length / 2);
bool affiliateFeeProcessed = false;
address bntToken = addressOf(BNT_TOKEN);
// iterate the conversion path and create the conversion data for each step
uint256 i;
for (i = 0; i < _conversionPath.length - 1; i += 2) {
IConverterAnchor anchor = IConverterAnchor(_conversionPath[i + 1]);
IConverter converter = IConverter(anchor.owner());
IERC20Token targetToken = _conversionPath[i + 2];
// check if the affiliate fee should be processed in this step
bool processAffiliateFee = _affiliateFeeEnabled && !affiliateFeeProcessed && targetToken == bntToken;
if (processAffiliateFee)
affiliateFeeProcessed = true;
data[i / 2] = ConversionStep({
// set the converter anchor
anchor: anchor,
// set the converter
converter: converter,
// set the source/target tokens
sourceToken: _conversionPath[i],
targetToken: targetToken,
// requires knowledge about the next step, so initialize in the next phase
beneficiary: address(0),
// set flags
isV28OrHigherConverter: isV28OrHigherConverter(converter),
processAffiliateFee: processAffiliateFee
});
}
// ETH support
// source is ETH
ConversionStep memory stepData = data[0];
if (etherTokens[stepData.sourceToken]) {
// newer converter - replace the source token address with ETH reserve address
if (stepData.isV28OrHigherConverter)
stepData.sourceToken = IERC20Token(ETH_RESERVE_ADDRESS);
// older converter - replace the source token with the EtherToken address used by the converter
else
stepData.sourceToken = IERC20Token(getConverterEtherTokenAddress(stepData.converter));
}
// target is ETH
stepData = data[data.length - 1];
if (etherTokens[stepData.targetToken]) {
// newer converter - replace the target token address with ETH reserve address
if (stepData.isV28OrHigherConverter)
stepData.targetToken = IERC20Token(ETH_RESERVE_ADDRESS);
// older converter - replace the target token with the EtherToken address used by the converter
else
stepData.targetToken = IERC20Token(getConverterEtherTokenAddress(stepData.converter));
}
// set the beneficiary for each step
for (i = 0; i < data.length; i++) {
stepData = data[i];
// first check if the converter in this step is newer as older converters don't even support the beneficiary argument
if (stepData.isV28OrHigherConverter) {
// if affiliate fee is processed in this step, beneficiary is the network contract
if (stepData.processAffiliateFee)
stepData.beneficiary = this;
// if it's the last step, beneficiary is the final beneficiary
else if (i == data.length - 1)
stepData.beneficiary = _beneficiary;
// if the converter in the next step is newer, beneficiary is the next converter
else if (data[i + 1].isV28OrHigherConverter)
stepData.beneficiary = data[i + 1].converter;
// the converter in the next step is older, beneficiary is the network contract
else
stepData.beneficiary = this;
}
else {
// conver...
// [truncated — 57416 bytes total]
Read Contract
conversionPath 0xd734fa19 → address[]
etherTokens 0x8077ccf7 → bool
getReturnByPath 0x0c8496cc → uint256, uint256
maxAffiliateFee 0x5d732ff2 → uint256
newOwner 0xd4ee1d90 → address
onlyOwnerCanUpdateRegistry 0x2fe8a6ad → bool
owner 0x8da5cb5b → address
prevRegistry 0x61cd756e → address
rateByPath 0x7f9c0ecd → uint256
registry 0x7b103999 → address
Write Contract 20 functions
These functions modify contract state and require a wallet transaction to execute.
acceptOwnership 0x79ba5097
No parameters
claimAndConvert 0xc7ba24bc
address[] _path
uint256 _amount
uint256 _minReturn
returns: uint256
claimAndConvert2 0xe57738e5
address[] _path
uint256 _amount
uint256 _minReturn
address _affiliateAccount
uint256 _affiliateFee
returns: uint256
claimAndConvertFor 0xb1e9932b
address[] _path
uint256 _amount
uint256 _minReturn
address _beneficiary
returns: uint256
claimAndConvertFor2 0x2978c10e
address[] _path
uint256 _amount
uint256 _minReturn
address _beneficiary
address _affiliateAccount
uint256 _affiliateFee
returns: uint256
completeXConversion 0x89f9cc61
address[] _path
address _bancorX
uint256 _conversionId
uint256 _minReturn
address _beneficiary
returns: uint256
convert 0xf3898a97
address[] _path
uint256 _amount
uint256 _minReturn
returns: uint256
convert2 0x569706eb
address[] _path
uint256 _amount
uint256 _minReturn
address _affiliateAccount
uint256 _affiliateFee
returns: uint256
convertByPath 0xb77d239b
address[] _path
uint256 _amount
uint256 _minReturn
address _beneficiary
address _affiliateAccount
uint256 _affiliateFee
returns: uint256
convertFor 0xc98fefed
address[] _path
uint256 _amount
uint256 _minReturn
address _beneficiary
returns: uint256
convertFor2 0xab6214ce
address[] _path
uint256 _amount
uint256 _minReturn
address _beneficiary
address _affiliateAccount
uint256 _affiliateFee
returns: uint256
registerEtherToken 0x02ef521e
address _token
bool _register
restoreRegistry 0xb4a176d3
No parameters
restrictRegistryUpdate 0x024c7ec7
bool _onlyOwnerCanUpdateRegistry
setMaxAffiliateFee 0xf3bc7d2a
uint256 _maxAffiliateFee
transferOwnership 0xf2fde38b
address _newOwner
updateRegistry 0x49d10b64
No parameters
withdrawTokens 0x5e35359e
address _token
address _to
uint256 _amount
xConvert 0xc52173de
address[] _path
uint256 _amount
uint256 _minReturn
bytes32 _targetBlockchain
bytes32 _targetAccount
uint256 _conversionId
returns: uint256
xConvert2 0xcb32564e
address[] _path
uint256 _amount
uint256 _minReturn
bytes32 _targetBlockchain
bytes32 _targetAccount
uint256 _conversionId
address _affiliateAccount
uint256 _affiliateFee
returns: uint256
Token Balances (1)
View Transfers →Recent Transactions
No transactions found for this address