Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x2F9EC37d6CcFFf1caB21733BdaDEdE11c823cCB0
Balance 0 ETH
Nonce 1
Code Size 13865 bytes
Indexed Transactions 0
External Etherscan · Sourcify

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 →
WETH 0

Recent Transactions

No transactions found for this address