Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0xfF20817765cB7f73d4bde2e66e067E58D11095C2
Balance 0 ETH
Nonce 1
Code Size 13920 bytes
Last Active
Indexed Transactions 1 (24,584,03224,584,032)
Gas Used (indexed) 69,786
External Etherscan · Sourcify

Contract Bytecode

13920 bytes
0x608060405234801561001057600080fd5b50600436106102695760003560e01c8063740ab8f411610151578063a2c1cae2116100c3578063b9d7b47111610087578063b9d7b4711461090f578063c2f89a5114610917578063dc73e49c14610949578063dd62ed3e14610951578063e30834e01461097f578063fad8b32a146109b557610269565b8063a2c1cae21461084d578063a457c2d714610855578063a9059cbb14610881578063aeb72e70146108ad578063b6363cf2146108e157610269565b80638da5cb5b116101155780638da5cb5b146107cb578063900ff16d146107d3578063959b8c3f146107fa57806395d89b4114610820578063a0cf6b8414610828578063a26734dc1461083057610269565b8063740ab8f41461072057806375deca02146107465780637e3a262d14610780578063814435af1461078857806387f4427e146107a557610269565b80632036a94d116101ea57806339509351116101ae57806339509351146106165780635481eed314610642578063556f0dc71461066657806369598efe1461066e5780636d77cad6146106c657806370a08231146106fa57610269565b80632036a94d1461048357806323b872dd1461056a578063249cb3fa146105a057806330e82803146105cc578063313ce567146105f857610269565b806314d1e62f1161023157806314d1e62f146103a5578063168ecec5146103d757806317ec83ca1461040357806318160ddd146104495780631ff6442e1461045157610269565b806303438dd01461026e57806306fdde0314610296578063095ea7b3146103135780630e0e923b14610353578063103ef9e114610379575b600080fd5b6102946004803603602081101561028457600080fd5b50356001600160a01b03166109db565b005b61029e610c41565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102d85781810151838201526020016102c0565b50505050905090810190601f1680156103055780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61033f6004803603604081101561032957600080fd5b506001600160a01b038135169060200135610cd7565b604080519115158252519081900360200190f35b61033f6004803603602081101561036957600080fd5b50356001600160a01b0316610cef565b6102946004803603604081101561038f57600080fd5b50803590602001356001600160a01b0316610d0c565b61033f600480360360608110156103bb57600080fd5b508035906001600160a01b036020820135169060400135610de3565b610294600480360360408110156103ed57600080fd5b50803590602001356001600160a01b0316610dfc565b6104376004803603606081101561041957600080fd5b508035906001600160a01b0360208201358116916040013516610ed0565b60408051918252519081900360200190f35b610437610f00565b61033f6004803603606081101561046757600080fd5b508035906001600160a01b036020820135169060400135610f06565b610437600480360360c081101561049957600080fd5b8135916001600160a01b03602082013581169260408301359091169160608101359181019060a0810160808201356401000000008111156104d957600080fd5b8201836020820111156104eb57600080fd5b8035906020019184600183028401116401000000008311171561050d57600080fd5b91939092909160208101903564010000000081111561052b57600080fd5b82018360208201111561053d57600080fd5b8035906020019184600183028401116401000000008311171561055f57600080fd5b509092509050610f50565b61033f6004803603606081101561058057600080fd5b506001600160a01b03813581169160208101359091169060400135610fd7565b610437600480360360408110156105b657600080fd5b50803590602001356001600160a01b0316610ff5565b610437600480360360408110156105e257600080fd5b50803590602001356001600160a01b0316611059565b61060061107e565b6040805160ff9092168252519081900360200190f35b61033f6004803603604081101561062c57600080fd5b506001600160a01b038135169060200135611083565b61064a6110e1565b604080516001600160a01b039092168252519081900360200190f35b6104376110f0565b6106766110f5565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156106b257818101518382015260200161069a565b505050509050019250505060405180910390f35b61033f600480360360608110156106dc57600080fd5b508035906001600160a01b036020820135811691604001351661114c565b6104376004803603602081101561071057600080fd5b50356001600160a01b0316611161565b6106766004803603602081101561073657600080fd5b50356001600160a01b031661117c565b6107636004803603602081101561075c57600080fd5b50356111e8565b604080516001600160e01b03199092168252519081900360200190f35b61043761121c565b61064a6004803603602081101561079e57600080fd5b5035611221565b610294600480360360208110156107bb57600080fd5b50356001600160a01b0316611248565b61064a6112e8565b61033f600480360360208110156107e957600080fd5b50356001600160e01b0319166112f7565b6102946004803603602081101561081057600080fd5b50356001600160a01b0316611316565b61029e6113e1565b61064a611442565b6104376004803603602081101561084657600080fd5b5035611448565b61029461145a565b61033f6004803603604081101561086b57600080fd5b506001600160a01b03813516906020013561150a565b61033f6004803603604081101561089757600080fd5b506001600160a01b038135169060200135611568565b61033f600480360360608110156108c357600080fd5b508035906001600160a01b0360208201358116916040013516611586565b61033f600480360360408110156108f757600080fd5b506001600160a01b03813581169160200135166115ef565b6102946115fb565b61033f6004803603606081101561092d57600080fd5b508035906001600160a01b036020820135169060400135611705565b61064a61174a565b6104376004803603604081101561096757600080fd5b506001600160a01b0381358116916020013516611759565b6102946004803603604081101561099557600080fd5b5080356001600160e01b03191690602001356001600160a01b03166117a3565b610294600480360360208110156109cb57600080fd5b50356001600160a01b0316611a64565b60235460408051636eb1769f60e11b81526001600160a01b0384811660048301523060248301529151600093929092169163dd62ed3e91604480820192602092909190829003018186803b158015610a3257600080fd5b505afa158015610a46573d6000803e3d6000fd5b505050506040513d6020811015610a5c57600080fd5b50519050600481610b005760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b820191906000526020600020905b815481529060010190602001808311610ad457829003601f168201915b50509250505060405180910390fd5b50602354604080516323b872dd60e01b81526001600160a01b03858116600483015261dead602483015260448201859052915191909216916323b872dd9160648083019260209291908290030181600087803b158015610b5f57600080fd5b505af1158015610b73573d6000803e3d6000fd5b505050506040513d6020811015610b8957600080fd5b5051600f90610bf15760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50610bfd338383611cba565b6040805182815290516001600160a01b0384169133917fea368a40e9570069bb8e6511d668293ad2e1f03b0d982431fd223de9f3b70ca69181900360200190a35050565b60128054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610ccd5780601f10610ca257610100808354040283529160200191610ccd565b820191906000526020600020905b815481529060010190602001808311610cb057829003601f168201915b5050505050905090565b6000610ce581338585611e7d565b5060015b92915050565b6001600160a01b0316600090815260208052604090205460ff1690565b60076001600160a01b038216331415610d7e5760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50336000818152601e6020908152604080832086845282528083206001600160a01b0386168085529252808320805460ff1916600117905551909185917f3646a897c70797ecc134b0adc32f471b07bf1d6f451133b0384badab531e3fd69190a45050565b6000610df184338585611e7d565b5060015b9392505050565b60076001600160a01b038216331415610e6e5760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50336000818152601e6020908152604080832086845282528083206001600160a01b0386168085529252808320805460ff1916905551909185917f3b287c4f1bab4df949b33bceacef984f544dc5d5479930d00e4ee8c9d8dd96f29190a45050565b6000928352601d602090815260408085206001600160a01b03948516865282528085209290931684525290205490565b60145490565b6000838152601d60209081526040808320338085529083528184206001600160a01b0387168552909252822054610df19186918690610f4b908763ffffffff61201f16565b611e7d565b6000610fca89338a8a8a8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b908190840183828082843760009201919091525061206192505050565b9998505050505050505050565b6000610df13385858560405180602001604052806000815250612508565b60008281526020819052604081205460ff161561105157604051602001808073455243313832305f4143434550545f4d4147494360601b8152506014019050604051602081830303815290604052805190602001209050610ce9565b506000610ce9565b6001600160a01b03166000908152601b60209081526040808320938352929052205490565b601290565b3360008181527f0a51588b1664495f089dd83d2d26f247920f94a57a4a09f20cf068efc8f82bd4602090815260408083206001600160a01b03871684529091528120549091610ce5918391908690610f4b908763ffffffff61253116565b6011546001600160a01b031690565b600190565b60606016805480602002602001604051908101604052809291908181526020018280548015610ccd57602002820191906000526020600020905b81548152602001906001019080831161112f575050505050905090565b600061115984848461258b565b949350505050565b6001600160a01b031660009081526015602052604090205490565b6001600160a01b0381166000908152601960209081526040918290208054835181840281018401909452808452606093928301828280156111dc57602002820191906000526020600020905b8154815260200190600101908083116111c8575b50505050509050919050565b602181815481106111f557fe5b9060005260206000209060089182820401919006600402915054906101000a900460e01b81565b600081565b601f818154811061122e57fe5b6000918252602090912001546001600160a01b0316905081565b6010546001600160a01b03163314611298576040805162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b73232b960911b604482015290519081900360640190fd5b601180546001600160a01b0319166001600160a01b0383811691909117918290556040519116907fb58bcc286020502f4931905baafed22acc969c092ed724234c73361efc68839090600090a250565b6010546001600160a01b031690565b6001600160e01b03191660009081526022602052604090205460ff1690565b60076001600160a01b0382163314156113885760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50336000818152601c602090815260408083206001600160a01b0386168085529252808320805460ff191660011790555190917ff4caeb2d6ca8932a215a353d0703c326ec2d81fc68170f320eb2ab49e9df61f991a350565b60138054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610ccd5780601f10610ca257610100808354040283529160200191610ccd565b61dead81565b60186020526000908152604090205481565b6011546001600160a01b031633146114aa576040805162461bcd60e51b815260206004820152600e60248201526d24b73b30b634b21039b2b73232b960911b604482015290519081900360640190fd5b60108054601180546001600160a01b03198084166001600160a01b038381169190911795869055911690915560405191811692169082907f343765429aea5a34b3ff6a3785a98a5abb2597aca87bfbb58632c173d585373a90600090a350565b3360008181527f0a51588b1664495f089dd83d2d26f247920f94a57a4a09f20cf068efc8f82bd4602090815260408083206001600160a01b03871684529091528120549091610ce5918391908690610f4b908763ffffffff61201f16565b6000610ce53333858560405180602001604052806000815250612508565b6001600160a01b038116600090815260208052604081205460ff16801561115957506115b283836125e0565b806111595750506001600160a01b039081166000908152601e60209081526040808320958352948152848220939092168152919052205460ff1690565b6000610df583836125e0565b336000908152602080526040902054600b9060ff16156116745760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50601f805460018181019092557fa03837a25210ee280c2113ff4b77ca23440b19d4866cca721c801278fd08d8070180546001600160a01b0319163390811790915560008181526020808052604091829020805460ff19169094179093558051918252517f2d9629b61129967906b4b31b246507fe09b2b62e2c963a3b9e4d1aff6d4af75b929181900390910190a1565b6000838152601d60209081526040808320338085529083528184206001600160a01b0387168552909252822054610df19186918690610f4b908763ffffffff61253116565b6023546001600160a01b031681565b6001600160a01b0391821660009081527f0a51588b1664495f089dd83d2d26f247920f94a57a4a09f20cf068efc8f82bd46020908152604080832093909416825291909152205490565b6117ab6112e8565b6001600160a01b0316336001600160a01b0316146005906118255760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b506001600160e01b03198216600090815260226020526040902054600d9060ff16156118aa5760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50600e6001600160e01b0319831661191b5760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b5060606119278361262d565b90506119338183611b2c565b6021805460018082019092557f3a6357012c1a3ae0a17d304c9920310382d968ebcc4b1771f41c6b304205b5706008820401805463ffffffff60079093166004026101000a928302191660e087901c929092029190911790556001600160e01b031984166000818152602260209081526040808320805460ff1916909517909455835192835282810184815285519484019490945284516001600160a01b038716947fb1c6e929e0b0638c228622a32f1f2fb3375541d8faa4a0176173b50b4bfc75ea9489948894919360608501928601918190849084905b83811015611a24578181015183820152602001611a0c565b50505050905090810190601f168015611a515780820380516001836020036101000a031916815260200191505b50935050505060405180910390a2505050565b60076001600160a01b038216331415611ad65760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50336000818152601c602090815260408083206001600160a01b0386168085529252808320805460ff191690555190917f50546e66e5f44d728365dc3908c63bc5cfeeab470722c1677e3073a6ac294aa191a350565b6000826040516020018082805190602001908083835b60208310611b615780518252601f199092019160209182019101611b42565b51815160209384036101000a60001901801990921691161790526040805192909401828103601f19018352808552825192909101919091206329965a1d60e01b8252306004830152602482018190526001600160a01b03881660448301529251929550731820a4b7618bde71dce8cdc73aab6c95905fad2494506329965a1d9350606480820193600093509182900301818387803b158015611c0257600080fd5b505af1158015611c16573d6000803e3d6000fd5b50505050505050565b6001600080836040516020018082805190602001908083835b60208310611c575780518252601f199092019160209182019101611c38565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b60066001600160a01b038316611d295760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50601454611d3d908263ffffffff61253116565b601455611d4c8260008361267d565b611d7d6000801b846000858560405180602001604052806000815250604051806020016040528060008152506127c7565b604080518281526020810182905260008183015290516001600160a01b0380851692908616917fbcd28e05e57d4bcd5bfcc92a4661d412893e6112c44a2e25d96cfdfc30d5f22e9181900360800190a36040805182815290516001600160a01b038416916000917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a3604080516001600160a01b038581168252602082018490526080828401819052600090830181905260c06060840181905283018190529251908516929182917fff4e9a26af4eb73b8bacfaa4abd4fea03d9448e7b912dc5ff4019048875aa2d4918190036101000190a4505050565b60056001600160a01b038416611eec5760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b5060076001600160a01b038316611f5c5760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b506000848152601d602090815260408083206001600160a01b038088168086529184528285209087168086529084529382902085905581518581529151909288927ff061499aa77c2f6f5e25e34955a06623705344a88256cc861a121ec0bce5cfec929081900390910190a48361201957816001600160a01b0316836001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a35b50505050565b6000610df583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612c43565b600060066001600160a01b0386166120d25760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b50866001600160a01b0316866001600160a01b03161461226b576120f788888861258b565b8061213057506000888152601d602090815260408083206001600160a01b03808b168552908352818420908b1684529091529020548411155b6004906121965760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b506000888152601d602090815260408083206001600160a01b03808b168552908352818420908b168452909152902054841161223b576000888152601d602090815260408083206001600160a01b03808b168552908352818420908b16845290915290205461220b908563ffffffff61201f16565b6000898152601d602090815260408083206001600160a01b038b168452825280832033845290915290205561226b565b6000888152601d602090815260408083206001600160a01b03808b168552908352818420908b1684529091528120555b61227a88888888888888612cda565b6001600160a01b0386166000908152601b602090815260408083208b84529091529020546003908511156123075760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b506000612314848a6130d6565b9050612321878a8761312b565b61232c86828761267d565b61233b818989898989896127c7565b856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef876040518082815260200191505060405180910390a3856001600160a01b0316876001600160a01b03168a7fff4e9a26af4eb73b8bacfaa4abd4fea03d9448e7b912dc5ff4019048875aa2d48b89898960405180856001600160a01b03166001600160a01b031681526020018481526020018060200180602001838103835285818151815260200191508051906020019080838360005b8381101561241f578181015183820152602001612407565b50505050905090810190601f16801561244c5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b8381101561247f578181015183820152602001612467565b50505050905090810190601f1680156124ac5780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a48881146124fc5760408051868152905182918b917f67c8ba31d2dd11f1384577b3405b04ed91eed1231e408432ad2458cab37b2fa19181900360200190a35b98975050505050505050565b6125296000801b868686868660405180602001604052806000815250612061565b505050505050565b600082820183811015610df5576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600061259783836125e0565b806125cf57506001600160a01b038083166000908152601e6020908152604080832088845282528083209387168352929052205460ff165b806111595750611159848484613347565b6000816001600160a01b0316836001600160a01b03161480610df55750506001600160a01b039081166000908152601c602090815260408083209490931682529290925290205460ff1690565b604080517f416d70506172746974696f6e537472617465677956616c696461746f7200000060208201526001600160e01b031992909216603d830152805180830360210181526041909201905290565b80612687576127c2565b6001600160a01b0383166000908152601560205260409020546126b0908263ffffffff61253116565b6001600160a01b038416600090815260156020908152604080832093909355601a815282822085835290522054612725576001600160a01b03831660008181526019602090815260408083208054600181018255818552838520018790559383529254601a8252838320868452909152919020555b6001600160a01b0383166000908152601b60209081526040808320858452909152902054612759908263ffffffff61253116565b6001600160a01b0384166000908152601b60209081526040808320868452825280832093909355601790522054612793576127938261343c565b6000828152601860205260409020546127b2908263ffffffff61253116565b6000838152601860205260409020555b505050565b60006127d28861347e565b6001600160e01b0319811660009081526022602052604090205490915060ff16156129d057600061280b306128068461262d565b613481565b90506001600160a01b038116156129ca57806001600160a01b031663b3c46f426000356001600160e01b0319168b8b8b8b8b8b8b6040518963ffffffff1660e01b815260040180896001600160e01b0319166001600160e01b0319168152602001888152602001876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b031681526020018481526020018060200180602001838103835285818151815260200191508051906020019080838360005b838110156128fd5781810151838201526020016128e5565b50505050905090810190601f16801561292a5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b8381101561295d578181015183820152602001612945565b50505050905090810190601f16801561298a5780820380516001836020036101000a031916815260200191505b509a5050505050505050505050600060405180830381600087803b1580156129b157600080fd5b505af11580156129c5573d6000803e3d6000fd5b505050505b50612a43565b600c6001600160e01b0319821615612a415760405162461bcd60e51b8152602060048201908152825460026000196101006001841615020190911604602483018190529091829160449091019084908015610af15780601f10610ac657610100808354040283529160200191610af1565b505b6000612a798660405180604001604052806012815260200171105b5c151bdad95b9cd49958da5c1a595b9d60721b815250613481565b90506001600160a01b03811615612c3857806001600160a01b0316638240ef486000356001600160e01b0319168b8b8b8b8b8b8b6040518963ffffffff1660e01b815260040180896001600160e01b0319166001600160e01b0319168152602001888152602001876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b031681526020018481526020018060200180602001838103835285818151815260200191508051906020019080838360005b83811015612b6b578181015183820152602001612b53565b50505050905090810190601f168015612b985780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015612bcb578181015183820152602001612bb3565b50505050905090810190601f168015612bf85780820380516001836020036101000a031916815260200191505b509a5050505050505050505050600060405180830381600087803b158015612c1f57600080fd5b505af1158015612c33573d6000803e3d6000fd5b505050505b505050505050505050565b60008184841115612cd25760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612c97578181015183820152602001612c7f565b50505050905090810190601f168015612cc45780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000612d0d866040518060400160405280600f81526020016e20b6b82a37b5b2b739a9b2b73232b960891b815250613481565b90506001600160a01b03811615612ecc57806001600160a01b031663ec3bb2886000356001600160e01b0319168a8a8a8a8a8a8a6040518963ffffffff1660e01b815260040180896001600160e01b0319166001600160e01b0319168152602001888152602001876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b031681526020018481526020018060200180602001838103835285818151815260200191508051906020019080838360005b83811015612dff578181015183820152602001612de7565b50505050905090810190601f168015612e2c5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b83811015612e5f578181015183820152602001612e47565b50505050905090810190601f168015612e8c5780820380516001836020036101000a031916815260200191505b509a5050505050505050505050600060405180830381600087803b158015612eb357600080fd5b505af1158015612ec7573d6000803e3d6000fd5b505050505b6000612ed78961347e565b6001600160e01b0319811660009081526022602052604090205490915060ff1615612c38576000612f0b306128068461262d565b90506001600160a01b038116156130ca57806001600160a01b031663dc86ad7a6000356001600160e01b0319168c8c8c8c8c8c8c6040518963ffffffff1660e01b815260040180896001600160e01b0319166001600160e01b0319168152602001888152602001876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b03168152602001856001600160a01b03166001600160a01b031681526020018481526020018060200180602001838103835285818151815260200191508051906020019080838360005b83811015612ffd578181015183820152602001612fe5565b50505050905090810190601f16801561302a5780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b8381101561305d578181015183820152602001613045565b50505050905090810190601f16801561308a5780820380516001836020036101000a031916815260200191505b509a5050505050505050505050600060405180830381600087803b1580156130b157600080fd5b505af11580156130c5573d6000803e3d6000fd5b505050505b50505050505050505050565b60006040835110156130e9575080610ce9565b60008084806020019051604081101561310157600080fd5b5080516020909101519092509050600019821415613122579150610ce99050565b50919392505050565b80613135576127c2565b6001600160a01b03831660009081526015602052604090205461315e908263ffffffff61201f16565b6001600160a01b038416600090815260156020908152604080832093909355601b81528282208583529052205461319b908263ffffffff61201f16565b6001600160a01b0384166000908152601b602090815260408083208684528252808320939093556018905220546131d8908263ffffffff61201f16565b60008381526018602052604090208190551580156131f557508115155b156132035761320382613584565b6001600160a01b0383166000908152601b602090815260408083208584529091529020546127c2576001600160a01b0383166000908152601a602090815260408083208584529091529020548061325a57506127c2565b6001600160a01b03841660009081526019602052604081208054600019810190811061328257fe5b906000526020600020015490508060196000876001600160a01b03166001600160a01b0316815260200190815260200160002060018403815481106132c357fe5b60009182526020808320909101929092556001600160a01b038716808252601a83526040808320858452845280832086905590825260199092522080548061330757fe5b6000828152602080822083016000199081018390559092019092556001600160a01b0387168252601a815260408083208784529091528120555050505050565b6000806133538561347e565b6001600160e01b0319811660009081526022602052604090205490915060ff16613381576000915050610df5565b6000613390306128068461262d565b90506001600160a01b038116156134305760408051633f0413df60e01b8152600481018890526001600160a01b0387811660248301528681166044830152915191831691633f0413df91606480820192602092909190829003018186803b1580156133fa57600080fd5b505afa15801561340e573d6000803e3d6000fd5b505050506040513d602081101561342457600080fd5b50519250610df5915050565b50600095945050505050565b601680546001810182557fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b5124289018290555460009182526017602052604090912055565b90565b600080826040516020018082805190602001908083835b602083106134b75780518252601f199092019160209182019101613498565b51815160209384036101000a60001901801990921691161790526040805192909401828103601f1901835280855282519282019290922063555ddc6560e11b83526001600160a01b038b166004840152602483018190529351939650731820a4b7618bde71dce8cdc73aab6c95905fad24955063aabbb8ca94506044808301949193509091829003018186803b15801561355057600080fd5b505afa158015613564573d6000803e3d6000fd5b505050506040513d602081101561357a57600080fd5b5051949350505050565b6000818152601760205260409020548061359e5750613627565b601680546000919060001981019081106135b457fe5b9060005260206000200154905080601660018403815481106135d257fe5b600091825260208083209091019290925582815260179091526040902082905560168054806135fd57fe5b60008281526020808220830160001990810183905590920190925584825260179052604081205550505b5056fea264697066735822122046f1197cc0a6e3d6399ed22c3480b4059302d3180614e1c23cf41dc5ac02219764736f6c634300060a0033

Verified Source Code Partial Match

Compiler: v0.6.10+commit.00c0fcaf EVM: istanbul Optimization: Yes (200 runs)
Amp.sol 2111 lines
// SPDX-License-Identifier: MIT

pragma solidity 0.6.10;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
 * @title Ownable is a contract the provides contract ownership functionality, including a two-
 * phase transfer.
 */
contract Ownable {
    address private _owner;
    address private _authorizedNewOwner;

    /**
     * @notice Emitted when the owner authorizes ownership transfer to a new address
     * @param authorizedAddress New owner address
     */
    event OwnershipTransferAuthorization(address indexed authorizedAddress);

    /**
     * @notice Emitted when the authorized address assumed ownership
     * @param oldValue Old owner
     * @param newValue New owner
     */
    event OwnerUpdate(address indexed oldValue, address indexed newValue);

    /**
     * @notice Sets the owner to the sender / contract creator
     */
    constructor() internal {
        _owner = msg.sender;
    }

    /**
     * @notice Retrieves the owner of the contract
     * @return The contract owner
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @notice Retrieves the authorized new owner of the contract
     * @return The authorized new contract owner
     */
    function authorizedNewOwner() public view returns (address) {
        return _authorizedNewOwner;
    }

    /**
     * @notice Authorizes the transfer of ownership from owner to the provided address.
     * NOTE: No transfer will occur unless authorizedAddress calls assumeOwnership().
     * This authorization may be removed by another call to this function authorizing the zero
     * address.
     * @param _authorizedAddress The address authorized to become the new owner
     */
    function authorizeOwnershipTransfer(address _authorizedAddress) external {
        require(msg.sender == _owner, "Invalid sender");

        _authorizedNewOwner = _authorizedAddress;

        emit OwnershipTransferAuthorization(_authorizedNewOwner);
    }

    /**
     * @notice Transfers ownership of this contract to the _authorizedNewOwner
     * @dev Error invalid sender.
     */
    function assumeOwnership() external {
        require(msg.sender == _authorizedNewOwner, "Invalid sender");

        address oldValue = _owner;
        _owner = _authorizedNewOwner;
        _authorizedNewOwner = address(0);

        emit OwnerUpdate(oldValue, _owner);
    }
}

abstract contract ERC1820Registry {
    function setInterfaceImplementer(
        address _addr,
        bytes32 _interfaceHash,
        address _implementer
    ) external virtual;

    function getInterfaceImplementer(address _addr, bytes32 _interfaceHash)
        external
        virtual
        view
        returns (address);

    function setManager(address _addr, address _newManager) external virtual;

    function getManager(address _addr) public virtual view returns (address);
}

/// Base client to interact with the registry.
contract ERC1820Client {
    ERC1820Registry constant ERC1820REGISTRY = ERC1820Registry(
        0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24
    );

    function setInterfaceImplementation(
        string memory _interfaceLabel,
        address _implementation
    ) internal {
        bytes32 interfaceHash = keccak256(abi.encodePacked(_interfaceLabel));
        ERC1820REGISTRY.setInterfaceImplementer(
            address(this),
            interfaceHash,
            _implementation
        );
    }

    function interfaceAddr(address addr, string memory _interfaceLabel)
        internal
        view
        returns (address)
    {
        bytes32 interfaceHash = keccak256(abi.encodePacked(_interfaceLabel));
        return ERC1820REGISTRY.getInterfaceImplementer(addr, interfaceHash);
    }

    function delegateManagement(address _newManager) internal {
        ERC1820REGISTRY.setManager(address(this), _newManager);
    }
}

contract ERC1820Implementer {
    /**
     * @dev ERC1820 well defined magic value indicating the contract has
     * registered with the ERC1820Registry that it can implement an interface.
     */
    bytes32 constant ERC1820_ACCEPT_MAGIC = keccak256(
        abi.encodePacked("ERC1820_ACCEPT_MAGIC")
    );

    /**
     * @dev Mapping of interface name keccak256 hashes for which this contract
     * implements the interface.
     * @dev Only settable internally.
     */
    mapping(bytes32 => bool) internal _interfaceHashes;

    /**
     * @notice Indicates whether the contract implements the interface `_interfaceHash`
     * for the address `_addr`.
     * @param _interfaceHash keccak256 hash of the name of the interface.
     * @return ERC1820_ACCEPT_MAGIC only if the contract implements `ìnterfaceHash`
     * for the address `_addr`.
     * @dev In this implementation, the `_addr` (the address for which the
     * contract will implement the interface) is always `address(this)`.
     */
    function canImplementInterfaceForAddress(
        bytes32 _interfaceHash,
        address // Comments to avoid compilation warnings for unused variables. /*addr*/
    ) external view returns (bytes32) {
        if (_interfaceHashes[_interfaceHash]) {
            return ERC1820_ACCEPT_MAGIC;
        } else {
            return "";
        }
    }

    /**
     * @notice Internally set the fact this contract implements the interface
     * identified by `_interfaceLabel`
     * @param _interfaceLabel String representation of the interface.
     */
    function _setInterface(string memory _interfaceLabel) internal {
        _interfaceHashes[keccak256(abi.encodePacked(_interfaceLabel))] = true;
    }
}

/**
 * @title IAmpTokensSender
 * @dev IAmpTokensSender token transfer hook interface
 */
interface IAmpTokensSender {
    /**
     * @dev Report if the transfer will succeed from the pespective of the
     * token sender
     */
    function canTransfer(
        bytes4 functionSig,
        bytes32 partition,
        address operator,
        address from,
        address to,
        uint256 value,
        bytes calldata data,
        bytes calldata operatorData
    ) external view returns (bool);

    /**
     * @dev Hook executed upon a transfer on behalf of the sender
     */
    function tokensToTransfer(
        bytes4 functionSig,
        bytes32 partition,
        address operator,
        address from,
        address to,
        uint256 value,
        bytes calldata data,
        bytes calldata operatorData
    ) external;
}

/**
 * @title IAmpTokensRecipient
 * @dev IAmpTokensRecipient token transfer hook interface
 */
interface IAmpTokensRecipient {
    /**
     * @dev Report if the recipient will successfully receive the tokens
     */
    function canReceive(
        bytes4 functionSig,
        bytes32 partition,
        address operator,
        address from,
        address to,
        uint256 value,
        bytes calldata data,
        bytes calldata operatorData
    ) external view returns (bool);

    /**
     * @dev Hook executed upon a transfer to the recipient
     */
    function tokensReceived(
        bytes4 functionSig,
        bytes32 partition,
        address operator,
        address from,
        address to,
        uint256 value,
        bytes calldata data,
        bytes calldata operatorData
    ) external;
}

/**
 * @notice Partition strategy validator hooks for Amp
 */
interface IAmpPartitionStrategyValidator {
    function tokensFromPartitionToValidate(
        bytes4 _functionSig,
        bytes32 _partition,
        address _operator,
        address _from,
        address _to,
        uint256 _value,
        bytes calldata _data,
        bytes calldata _operatorData
    ) external;

    function tokensToPartitionToValidate(
        bytes4 _functionSig,
        bytes32 _partition,
        address _operator,
        address _from,
        address _to,
        uint256 _value,
        bytes calldata _data,
        bytes calldata _operatorData
    ) external;

    function isOperatorForPartitionScope(
        bytes32 _partition,
        address _operator,
        address _tokenHolder
    ) external view returns (bool);
}

/**
 * @title PartitionUtils
 * @notice Partition related helper functions.
 */

library PartitionUtils {
    bytes32 public constant CHANGE_PARTITION_FLAG = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

    /**
     * @notice Retrieve the destination partition from the 'data' field.
     * A partition change is requested ONLY when 'data' starts with the flag:
     *
     *   0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
     *
     * When the flag is detected, the destination partition is extracted from the
     * 32 bytes following the flag.
     * @param _data Information attached to the transfer. Will contain the
     * destination partition if a change is requested.
     * @param _fallbackPartition Partition value to return if a partition change
     * is not requested in the `_data`.
     * @return toPartition Destination partition. If the `_data` does not contain
     * the prefix and bytes32 partition in the first 64 bytes, the method will
     * return the provided `_fromPartition`.
     */
    function _getDestinationPartition(bytes memory _data, bytes32 _fallbackPartition)
        internal
        pure
        returns (bytes32)
    {
        if (_data.length < 64) {
            return _fallbackPartition;
        }

        (bytes32 flag, bytes32 toPartition) = abi.decode(_data, (bytes32, bytes32));
        if (flag == CHANGE_PARTITION_FLAG) {
            return toPartition;
        }

        return _fallbackPartition;
    }

    /**
     * @notice Helper to get the strategy identifying prefix from the `_partition`.
     * @param _partition Partition to get the prefix for.
     * @return 4 byte partition strategy prefix.
     */
    function _getPartitionPrefix(bytes32 _partition) internal pure returns (bytes4) {
        return bytes4(_partition);
    }

    /**
     * @notice Helper method to split the partition into the prefix, sub partition
     * and partition owner components.
     * @param _partition The partition to split into parts.
     * @return The 4 byte partition prefix, 8 byte sub partition, and final 20
     * bytes representing an address.
     */
    function _splitPartition(bytes32 _partition)
        internal
        pure
        returns (
            bytes4,
            bytes8,
            address
        )
    {
        bytes4 prefix = bytes4(_partition);
        bytes8 subPartition = bytes8(_partition << 32);
        address addressPart = address(uint160(uint256(_partition)));
        return (prefix, subPartition, addressPart);
    }

    /**
     * @notice Helper method to get a partition strategy ERC1820 interface name
     * based on partition prefix.
     * @param _prefix 4 byte partition prefix.
     * @dev Each 4 byte prefix has a unique interface name so that an individual
     * hook implementation can be set for each prefix.
     */
    function _getPartitionStrategyValidatorIName(bytes4 _prefix)
        internal
        pure
        returns (string memory)
    {
        return string(abi.encodePacked("AmpPartitionStrategyValidator", _prefix));
    }
}

/**
 * @title ErrorCodes
 * @notice Amp error codes.
 */
contract ErrorCodes {
    string internal EC_50_TRANSFER_FAILURE = "50";
    string internal EC_51_TRANSFER_SUCCESS = "51";
    string internal EC_52_INSUFFICIENT_BALANCE = "52";
    string internal EC_53_INSUFFICIENT_ALLOWANCE = "53";

    string internal EC_56_INVALID_SENDER = "56";
    string internal EC_57_INVALID_RECEIVER = "57";
    string internal EC_58_INVALID_OPERATOR = "58";

    string internal EC_59_INSUFFICIENT_RIGHTS = "59";

    string internal EC_5A_INVALID_SWAP_TOKEN_ADDRESS = "5A";
    string internal EC_5B_INVALID_VALUE_0 = "5B";
    string internal EC_5C_ADDRESS_CONFLICT = "5C";
    string internal EC_5D_PARTITION_RESERVED = "5D";
    string internal EC_5E_PARTITION_PREFIX_CONFLICT = "5E";
    string internal EC_5F_INVALID_PARTITION_PREFIX_0 = "5F";
    string internal EC_60_SWAP_TRANSFER_FAILURE = "60";
}

interface ISwapToken {
    function allowance(address owner, address spender)
        external
        view
        returns (uint256 remaining);

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) external returns (bool success);
}

/**
 * @title Amp
 * @notice Amp is an ERC20 compatible collateral token designed to support
 * multiple classes of collateralization systems.
 * @dev The Amp token contract includes the following features:
 *
 * Partitions
 *   Tokens can be segmented within a given address by "partition", which in
 *   pracice is a 32 byte identifier. These partitions can have unique
 *   permissions globally, through the using of partition strategies, and
 *   locally, on a per address basis. The ability to create the sub-segments
 *   of tokens and assign special behavior gives collateral managers
 *   flexibility in how they are implemented.
 *
 * Operators
 *   Inspired by ERC777, Amp allows token holders to assign "operators" on
 *   all (or any number of partitions) of their tokens. Operators are allowed
 *   to execute transfers on behalf of token owners without the need to use the
 *   ERC20 "allowance" semantics.
 *
 * Transfers with Data
 *   Inspired by ERC777, Amp transfers can include arbitrary data, as well as
 *   operator data. This data can be used to change the partition of tokens,
 *   be used by collateral manager hooks to validate a transfer, be propagated
 *   via event to an off chain system, etc.
 *
 * Token Transfer Hooks on Send and Receive
 *   Inspired by ERC777, Amp uses the ERC1820 Registry to allow collateral
 *   manager implementations to register hooks to be called upon sending to
 *   or transferring from the collateral manager's address or, using partition
 *   strategies, owned partition space. The hook implementations can be used
 *   to validate transfer properties, gate transfers, emit custom events,
 *   update local state, etc.
 *
 * Collateral Management Partition Strategies
 *   Amp is able to define certain sets of partitions, identified by a 4 byte
 *   prefix, that will allow special, custom logic to be executed when transfers
 *   are made to or from those partitions. This opens up the possibility of
 *   entire classes of collateral management systems that would not be possible
 *   without it.
 *
 * These features give collateral manager implementers flexibility while
 * providing a consistent, "collateral-in-place", interface for interacting
 * with collateral systems directly through the Amp contract.
 */
contract Amp is IERC20, ERC1820Client, ERC1820Implementer, ErrorCodes, Ownable {
    using SafeMath for uint256;

    /**************************************************************************/
    /********************** ERC1820 Interface Constants ***********************/

    /**
     * @dev AmpToken interface label.
     */
    string internal constant AMP_INTERFACE_NAME = "AmpToken";

    /**
     * @dev ERC20Token interface label.
     */
    string internal constant ERC20_INTERFACE_NAME = "ERC20Token";

    /**
     * @dev AmpTokensSender interface label.
     */
    string internal constant AMP_TOKENS_SENDER = "AmpTokensSender";

    /**
     * @dev AmpTokensRecipient interface label.
     */
    string internal constant AMP_TOKENS_RECIPIENT = "AmpTokensRecipient";

    /**
     * @dev AmpTokensChecker interface label.
     */
    string internal constant AMP_TOKENS_CHECKER = "AmpTokensChecker";

    /**************************************************************************/
    /*************************** Token properties *****************************/

    /**
     * @dev Token name (Amp).
     */
    string internal _name;

    /**
     * @dev Token symbol (AMP).
     */
    string internal _symbol;

    /**
     * @dev Total minted supply of token. This will increase comensurately with
     * successful swaps of the swap token.
     */
    uint256 internal _totalSupply;

    /**
     * @dev The granularity of the token. Hard coded to 1.
     */
    uint256 internal constant _granularity = 1;

    /**************************************************************************/
    /***************************** Token mappings *****************************/

    /**
     * @dev Mapping from tokenHolder to balance. This reflects the balance
     * across all partitions of an address.
     */
    mapping(address => uint256) internal _balances;

    /**************************************************************************/
    /************************** Partition mappings ****************************/

    /**
     * @dev List of active partitions. This list reflects all partitions that
     * have tokens assigned to them.
     */
    bytes32[] internal _totalPartitions;

    /**
     * @dev Mapping from partition to their index.
     */
    mapping(bytes32 => uint256) internal _indexOfTotalPartitions;

    /**
     * @dev Mapping from partition to global balance of corresponding partition.
     */
    mapping(bytes32 => uint256) public totalSupplyByPartition;

    /**
     * @dev Mapping from tokenHolder to their partitions.
     */
    mapping(address => bytes32[]) internal _partitionsOf;

    /**
     * @dev Mapping from (tokenHolder, partition) to their index.
     */
    mapping(address => mapping(bytes32 => uint256)) internal _indexOfPartitionsOf;

    /**
     * @dev Mapping from (tokenHolder, partition) to balance of corresponding
     * partition.
     */
    mapping(address => mapping(bytes32 => uint256)) internal _balanceOfByPartition;

    /**
     * @notice Default partition of the token.
     * @dev All ERC20 operations operate solely on this partition.
     */
    bytes32
        public constant defaultPartition = 0x0000000000000000000000000000000000000000000000000000000000000000;

    /**
     * @dev Zero partition prefix. Parititions with this prefix can not have
     * a strategy assigned, and partitions with a different prefix must have one.
     */
    bytes4 internal constant ZERO_PREFIX = 0x00000000;

    /**************************************************************************/
    /***************************** Operator mappings **************************/

    /**
     * @dev Mapping from (tokenHolder, operator) to authorized status. This is
     * specific to the token holder.
     */
    mapping(address => mapping(address => bool)) internal _authorizedOperator;

    /**************************************************************************/
    /********************** Partition operator mappings ***********************/

    /**
     * @dev Mapping from (partition, tokenHolder, spender) to allowed value.
     * This is specific to the token holder.
     */
    mapping(bytes32 => mapping(address => mapping(address => uint256)))
        internal _allowedByPartition;

    /**
     * @dev Mapping from (tokenHolder, partition, operator) to 'approved for
     * partition' status. This is specific to the token holder.
     */
    mapping(address => mapping(bytes32 => mapping(address => bool)))
        internal _authorizedOperatorByPartition;

    /**************************************************************************/
    /********************** Collateral Manager mappings ***********************/
    /**
     * @notice Collection of registered collateral managers.
     */
    address[] public collateralManagers;
    /**
     * @dev Mapping of collateral manager addresses to registration status.
     */
    mapping(address => bool) internal _isCollateralManager;

    /**************************************************************************/
    /********************* Partition Strategy mappings ************************/

    /**
     * @notice Collection of reserved partition strategies.
     */
    bytes4[] public partitionStrategies;

    /**
     * @dev Mapping of partition strategy flag to registration status.
     */
    mapping(bytes4 => bool) internal _isPartitionStrategy;

    /**************************************************************************/
    /***************************** Swap storage *******************************/

    /**
     * @notice Swap token address. Immutable.
     */
    ISwapToken public swapToken;

    /**
     * @notice Swap token graveyard address.
     * @dev This is the address that the incoming swapped tokens will be
     * forwarded to upon successfully minting Amp.
     */
    address
        public constant swapTokenGraveyard = 0x000000000000000000000000000000000000dEaD;

    /**************************************************************************/
    /** EVENTS ****************************************************************/
    /**************************************************************************/

    /**************************************************************************/
    /**************************** Transfer Events *****************************/

    /**
     * @notice Emitted when a transfer has been successfully completed.
     * @param fromPartition The partition the tokens were transfered from.
     * @param operator The address that initiated the transfer.
     * @param from The address the tokens were transferred from.
     * @param to The address the tokens were transferred to.
     * @param value The amount of tokens transferred.
     * @param data Additional metadata included with the transfer. Can include
     * the partition the tokens were transferred to (if different than
     * `fromPartition`).
     * @param operatorData Additional metadata included with the transfer on
     * behalf of the operator.
     */
    event TransferByPartition(
        bytes32 indexed fromPartition,
        address operator,
        address indexed from,
        address indexed to,
        uint256 value,
        bytes data,
        bytes operatorData
    );

    /**
     * @notice Emitted when a transfer has been successfully completed and the
     * tokens that were transferred have changed partitions.
     * @param fromPartition The partition the tokens were transfered from.
     * @param toPartition The partition the tokens were transfered to.
     * @param value The amount of tokens transferred.
     */
    event ChangedPartition(
        bytes32 indexed fromPartition,
        bytes32 indexed toPartition,
        uint256 value
    );

    /**************************************************************************/
    /**************************** Operator Events *****************************/

    /**
     * @notice Emitted when a token holder specifies an amount of tokens in a
     * a partition that an operator can transfer.
     * @param partition The partition of the tokens the holder has authorized the
     * operator to transfer from.
     * @param owner The token holder.
     * @param spender The operator the `owner` has authorized the allowance for.
     */
    event ApprovalByPartition(
        bytes32 indexed partition,
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    /**
     * @notice Emitted when a token holder has authorized an operator for their
     * tokens.
     * @dev This event applies to the token holder address across all partitions.
     * @param operator The address that was authorized to transfer tokens on
     * behalf of the `tokenHolder`.
     * @param tokenHolder The address that authorized the `operator` to transfer
     * their tokens.
     */
    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);

    /**
     * @notice Emitted when a token holder has de-authorized an operator from
     * transferring their tokens.
     * @dev This event applies to the token holder address across all partitions.
     * @param operator The address that was de-authorized from transferring tokens
     * on behalf of the `tokenHolder`.
     * @param tokenHolder The address that revoked the `operator`'s permission
     * to transfer their tokens.
     */
    event RevokedOperator(address indexed operator, address indexed tokenHolder);

    /**
     * @notice Emitted when a token holder has authorized an operator to transfer
     * their tokens of one partition.
     * @param partition The partition the `operator` is allowed to transfer
     * tokens from.
     * @param operator The address that was authorized to transfer tokens on
     * behalf of the `tokenHolder`.
     * @param tokenHolder The address that authorized the `operator` to transfer
     * their tokens in `partition`.
     */
    event AuthorizedOperatorByPartition(
        bytes32 indexed partition,
        address indexed operator,
        address indexed tokenHolder
    );

    /**
     * @notice Emitted when a token holder has de-authorized an operator from
     * transferring their tokens from a specific partition.
     * @param partition The partition the `operator` is no longer allowed to
     * transfer tokens from on behalf of the `tokenHolder`.
     * @param operator The address that was de-authorized from transferring
     * tokens on behalf of the `tokenHolder`.
     * @param tokenHolder The address that revoked the `operator`'s permission
     * to transfer their tokens from `partition`.
     */
    event RevokedOperatorByPartition(
        bytes32 indexed partition,
        address indexed operator,
        address indexed tokenHolder
    );

    /**************************************************************************/
    /********************** Collateral Manager Events *************************/

    /**
     * @notice Emitted when a collateral manager has been registered.
     * @param collateralManager The address of the collateral manager.
     */
    event CollateralManagerRegistered(address collateralManager);

    /**************************************************************************/
    /*********************** Partition Strategy Events ************************/

    /**
     * @notice Emitted when a new partition strategy validator is set.
     * @param flag The 4 byte prefix of the partitions that the stratgy affects.
     * @param name The name of the partition strategy.
     * @param implementation The address of the partition strategy hook
     * implementation.
     */
    event PartitionStrategySet(bytes4 flag, string name, address indexed implementation);

    // ************** Mint & Swap **************

    /**
     * @notice Emitted when tokens are minted as a result of a token swap
     * @param operator Address that executed the swap that resulted in tokens being minted
     * @param to Address that received the newly minted tokens.
     * @param value Amount of tokens minted
     * @param data Empty bytes, required for interface compatibility
     */
    event Minted(address indexed operator, address indexed to, uint256 value, bytes data);

    /**
     * @notice Indicates tokens swapped for Amp.
     * @dev The tokens that are swapped for Amp will be transferred to a
     * graveyard address that is for all practical purposes inaccessible.
     * @param operator Address that executed the swap.
     * @param from Address that the tokens were swapped from, and Amp minted for.
     * @param value Amount of tokens swapped into Amp.
     */
    event Swap(address indexed operator, address indexed from, uint256 value);

    /**************************************************************************/
    /** CONSTRUCTOR ***********************************************************/
    /**************************************************************************/

    /**
     * @notice Initialize Amp, initialize the default partition, and register the
     * contract implementation in the global ERC1820Registry.
     * @param _swapTokenAddress_ The address of the ERC20 token that is set to be
     * swappable for Amp.
     * @param _name_ Name of the token.
     * @param _symbol_ Symbol of the token.
     */
    constructor(
        address _swapTokenAddress_,
        string memory _name_,
        string memory _symbol_
    ) public {
        // "Swap token cannot be 0 address"
        require(_swapTokenAddress_ != address(0), EC_5A_INVALID_SWAP_TOKEN_ADDRESS);
        swapToken = ISwapToken(_swapTokenAddress_);

        _name = _name_;
        _symbol = _symbol_;
        _totalSupply = 0;

        // Add the default partition to the total partitions on deploy
        _addPartitionToTotalPartitions(defaultPartition);

        // Register contract in ERC1820 registry
        ERC1820Client.setInterfaceImplementation(AMP_INTERFACE_NAME, address(this));
        ERC1820Client.setInterfaceImplementation(ERC20_INTERFACE_NAME, address(this));

        // Indicate token verifies Amp and ERC20 interfaces
        ERC1820Implementer._setInterface(AMP_INTERFACE_NAME);
        ERC1820Implementer._setInterface(ERC20_INTERFACE_NAME);
    }

    /**************************************************************************/
    /** EXTERNAL FUNCTIONS (ERC20) ********************************************/
    /**************************************************************************/

    /**
     * @notice Get the total number of issued tokens.
     * @return Total supply of tokens currently in circulation.
     */
    function totalSupply() external override view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @notice Get the balance of the account with address `_tokenHolder`.
     * @dev This returns the balance of the holder across all partitions. Note
     * that due to other functionality in Amp, this figure should not be used
     * as the arbiter of the amount a token holder will successfully be able to
     * send via the ERC20 compatible `transfer` method. In order to get that
     * figure, use `balanceOfByParition` and to get the balance of the default
     * partition.
     * @param _tokenHolder Address for which the balance is returned.
     * @return Amount of token held by `_tokenHolder` in the default partition.
     */
    function balanceOf(address _tokenHolder) external override view returns (uint256) {
        return _balances[_tokenHolder];
    }

    /**
     * @notice Transfer token for a specified address.
     * @dev This method is for ERC20 compatibility, and only affects the
     * balance of the `msg.sender` address's default partition.
     * @param _to The address to transfer to.
     * @param _value The value to be transferred.
     * @return A boolean that indicates if the operation was successful.
     */
    function transfer(address _to, uint256 _value) external override returns (bool) {
        _transferByDefaultPartition(msg.sender, msg.sender, _to, _value, "");
        return true;
    }

    /**
     * @notice Transfer tokens from one address to another.
     * @dev This method is for ERC20 compatibility, and only affects the
     * balance and allowance of the `_from` address's default partition.
     * @param _from The address which you want to transfer tokens from.
     * @param _to The address which you want to transfer to.
     * @param _value The amount of tokens to be transferred.
     * @return A boolean that indicates if the operation was successful.
     */
    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) external override returns (bool) {
        _transferByDefaultPartition(msg.sender, _from, _to, _value, "");
        return true;
    }

    /**
     * @notice Check the value of tokens that an owner allowed to a spender.
     * @dev This method is for ERC20 compatibility, and only affects the
     * allowance of the `msg.sender`'s default partition.
     * @param _owner address The address which owns the funds.
     * @param _spender address The address which will spend the funds.
     * @return A uint256 specifying the value of tokens still available for the
     * spender.
     */
    function allowance(address _owner, address _spender)
        external
        override
        view
        returns (uint256)
    {
        return _allowedByPartition[defaultPartition][_owner][_spender];
    }

    /**
     * @notice Approve the passed address to spend the specified amount of
     * tokens from the default partition on behalf of 'msg.sender'.
     * @dev This method is for ERC20 compatibility, and only affects the
     * allowance of the `msg.sender`'s default partition.
     * @param _spender The address which will spend the funds.
     * @param _value The amount of tokens to be spent.
     * @return A boolean that indicates if the operation was successful.
     */
    function approve(address _spender, uint256 _value) external override returns (bool) {
        _approveByPartition(defaultPartition, msg.sender, _spender, _value);
        return true;
    }

    /**
     * @notice Atomically increases the allowance granted to `_spender` by the
     * for caller.
     * @dev This is an alternative to {approve} that can be used as a mitigation
     * problems described in {IERC20-approve}.
     * Emits an {Approval} event indicating the updated allowance.
     * Requirements:
     * - `_spender` cannot be the zero address.
     * @dev This method is for ERC20 compatibility, and only affects the
     * allowance of the `msg.sender`'s default partition.
     * @param _spender Operator allowed to transfer the tokens
     * @param _addedValue Additional amount of the `msg.sender`s tokens `_spender`
     * is allowed to transfer
     * @return 'true' is successful, 'false' otherwise
     */
    function increaseAllowance(address _spender, uint256 _addedValue)
        external
        returns (bool)
    {
        _approveByPartition(
            defaultPartition,
            msg.sender,
            _spender,
            _allowedByPartition[defaultPartition][msg.sender][_spender].add(_addedValue)
        );
        return true;
    }

    /**
     * @notice Atomically decreases the allowance granted to `_spender` by the
     * caller.
     * @dev This is an alternative to {approve} that can be used as a mitigation
     * for bugs caused by reentrancy.
     * Emits an {Approval} event indicating the updated allowance.
     * Requirements:
     * - `_spender` cannot be the zero address.
     * - `_spender` must have allowance for the caller of at least
     * `_subtractedValue`.
     * @dev This method is for ERC20 compatibility, and only affects the
     * allowance of the `msg.sender`'s default partition.
     * @param _spender Operator allowed to transfer the tokens
     * @param _subtractedValue Amount of the `msg.sender`s tokens `_spender`
     * is no longer allowed to transfer
     * @return 'true' is successful, 'false' otherwise
     */
    function decreaseAllowance(address _spender, uint256 _subtractedValue)
        external
        returns (bool)
    {
        _approveByPartition(
            defaultPartition,
            msg.sender,
            _spender,
            _allowedByPartition[defaultPartition][msg.sender][_spender].sub(
                _subtractedValue
            )
        );
        return true;
    }

    /**************************************************************************/
    /** EXTERNAL FUNCTIONS (AMP) **********************************************/
    /**************************************************************************/

    /******************************** Swap  ***********************************/

    /**
     * @notice Swap tokens to mint AMP.
     * @dev Requires `_from` to have given allowance of swap token to contract.
     * Otherwise will throw error code 53 (Insuffient Allowance).
     * @param _from Token holder to execute the swap for.
     */
    function swap(address _from) public {
        uint256 amount = swapToken.allowance(_from, address(this));
        require(amount > 0, EC_53_INSUFFICIENT_ALLOWANCE);

        require(
            swapToken.transferFrom(_from, swapTokenGraveyard, amount),
            EC_60_SWAP_TRANSFER_FAILURE
        );

        _mint(msg.sender, _from, amount);

        emit Swap(msg.sender, _from, amount);
    }

    /**************************************************************************/
    /************************** Holder information ****************************/

    /**
     * @notice Get balance of a tokenholder for a specific partition.
     * @param _partition Name of the partition.
     * @param _tokenHolder Address for which the balance is returned.
     * @return Amount of token of partition `_partition` held by `_tokenHolder` in the token contract.
     */
    function balanceOfByPartition(bytes32 _partition, address _tokenHolder)
        external
        view
        returns (uint256)
    {
        return _balanceOfByPartition[_tokenHolder][_partition];
    }

    /**
     * @notice Get partitions index of a token holder.
     * @param _tokenHolder Address for which the partitions index are returned.
     * @return Array of partitions index of '_tokenHolder'.
     */
    function partitionsOf(address _tokenHolder) external view returns (bytes32[] memory) {
        return _partitionsOf[_tokenHolder];
    }

    /**************************************************************************/
    /************************** Advanced Transfers ****************************/

    /**
     * @notice Transfer tokens from a specific partition on behalf of a token
     * holder, optionally changing the parittion and optionally including
     * arbitrary data with the transfer.
     * @dev This can be used to transfer an address's own tokens, or transfer
     * a different addresses tokens by specifying the `_from` param. If
     * attempting to transfer from a different address than `msg.sender`, the
     * `msg.sender` will need to be an operator or have enough allowance for the
     * `_partition` of the `_from` address.
     * @param _partition Name of the partition to transfer from.
     * @param _from Token holder.
     * @param _to Token recipient.
     * @param _value Number of tokens to transfer.
     * @param _data Information attached to the transfer. Will contain the
     * destination partition (if changing partitions).
     * @param _operatorData Information attached to the transfer, by the operator.
     * @return Destination partition.
     */
    function transferByPartition(
        bytes32 _partition,
        address _from,
        address _to,
        uint256 _value,
        bytes calldata _data,
        bytes calldata _operatorData
    ) external returns (bytes32) {
        return
            _transferByPartition(
                _partition,
                msg.sender,
                _from,
                _to,
                _value,
                _data,
                _operatorData
            );
    }

    /**************************************************************************/
    /************************** Operator Management ***************************/

    /**
     * @notice Set a third party operator address as an operator of 'msg.sender'
     * to transfer and redeem tokens on its behalf.
     * @dev The msg.sender is always an operator for itself, and does not need to
     * be explicitly added.
     * @param _operator Address to set as an operator for 'msg.sender'.
     */
    function authorizeOperator(address _operator) external {
        require(_operator != msg.sender, EC_58_INVALID_OPERATOR);

        _authorizedOperator[msg.sender][_operator] = true;
        emit AuthorizedOperator(_operator, msg.sender);
    }

    /**
     * @notice Remove the right of the operator address to be an operator for
     * 'msg.sender' and to transfer and redeem tokens on its behalf.
     * @dev The msg.sender is always an operator for itself, and cannot be
     * removed.
     * @param _operator Address to rescind as an operator for 'msg.sender'.
     */
    function revokeOperator(address _operator) external {
        require(_operator != msg.sender, EC_58_INVALID_OPERATOR);

        _authorizedOperator[msg.sender][_operator] = false;
        emit RevokedOperator(_operator, msg.sender);
    }

    /**
     * @notice Set `_operator` as an operator for 'msg.sender' for a given partition.
     * @dev The msg.sender is always an operator for itself, and does not need to
     * be explicitly added to a partition.
     * @param _partition Name of the partition.
     * @param _operator Address to set as an operator for 'msg.sender'.
     */
    function authorizeOperatorByPartition(bytes32 _partition, address _operator)
        external
    {
        require(_operator != msg.sender, EC_58_INVALID_OPERATOR);

        _authorizedOperatorByPartition[msg.sender][_partition][_operator] = true;
        emit AuthorizedOperatorByPartition(_partition, _operator, msg.sender);
    }

    /**
     * @notice Remove the right of the operator address to be an operator on a
     * given part...

// [truncated — 80206 bytes total]

Read Contract

allowance 0xdd62ed3e → uint256
allowanceByPartition 0x17ec83ca → uint256
authorizedNewOwner 0x5481eed3 → address
balanceOf 0x70a08231 → uint256
balanceOfByPartition 0x30e82803 → uint256
canImplementInterfaceForAddress 0x249cb3fa → bytes32
collateralManagers 0x814435af → address
decimals 0x313ce567 → uint8
defaultPartition 0x7e3a262d → bytes32
granularity 0x556f0dc7 → uint256
isCollateralManager 0x0e0e923b → bool
isOperator 0xb6363cf2 → bool
isOperatorForCollateralManager 0xaeb72e70 → bool
isOperatorForPartition 0x6d77cad6 → bool
isPartitionStrategy 0x900ff16d → bool
name 0x06fdde03 → string
owner 0x8da5cb5b → address
partitionStrategies 0x75deca02 → bytes4
partitionsOf 0x740ab8f4 → bytes32[]
swapToken 0xdc73e49c → address
swapTokenGraveyard 0xa0cf6b84 → address
symbol 0x95d89b41 → string
totalPartitions 0x69598efe → bytes32[]
totalSupply 0x18160ddd → uint256
totalSupplyByPartition 0xa26734dc → uint256

Write Contract 18 functions

These functions modify contract state and require a wallet transaction to execute.

approve 0x095ea7b3
address _spender
uint256 _value
returns: bool
approveByPartition 0x14d1e62f
bytes32 _partition
address _spender
uint256 _value
returns: bool
assumeOwnership 0xa2c1cae2
No parameters
authorizeOperator 0x959b8c3f
address _operator
authorizeOperatorByPartition 0x103ef9e1
bytes32 _partition
address _operator
authorizeOwnershipTransfer 0x87f4427e
address _authorizedAddress
decreaseAllowance 0xa457c2d7
address _spender
uint256 _subtractedValue
returns: bool
decreaseAllowanceByPartition 0x1ff6442e
bytes32 _partition
address _spender
uint256 _subtractedValue
returns: bool
increaseAllowance 0x39509351
address _spender
uint256 _addedValue
returns: bool
increaseAllowanceByPartition 0xc2f89a51
bytes32 _partition
address _spender
uint256 _addedValue
returns: bool
registerCollateralManager 0xb9d7b471
No parameters
revokeOperator 0xfad8b32a
address _operator
revokeOperatorByPartition 0x168ecec5
bytes32 _partition
address _operator
setPartitionStrategy 0xe30834e0
bytes4 _prefix
address _implementation
swap 0x03438dd0
address _from
transfer 0xa9059cbb
address _to
uint256 _value
returns: bool
transferByPartition 0x2036a94d
bytes32 _partition
address _from
address _to
uint256 _value
bytes _data
bytes _operatorData
returns: bytes32
transferFrom 0x23b872dd
address _from
address _to
uint256 _value
returns: bool

Top Interactions

AddressTxnsSentReceived
0xA8A7D147...25fe 1 1

Recent Transactions

CSV
|
Hash Method Block Age From/To Value Txn Fee Type
0x4ee0e9b1...7de2d2 transfer 24,584,032 IN 0xA8A7D147...25fe 0 ETH 0.000029541305 ETH EIP-1559