Address Contract Partially Verified
Address
0x5ba073f65C751F419BF880d57Cf51289CbDb55fE
Balance
0 ETH
Nonce
1
Code Size
23906 bytes
Creator
0xcBfd32FD...A9eD at tx 0x2e484a06...d8dae3
Indexed Transactions
0 (1 on-chain, 1.6% indexed)
Contract Bytecode
23906 bytes
0x6080604052600436106102285760003560e01c80638e8920e311610123578063c4552791116100ab578063f3dced3c1161006f578063f3dced3c14610700578063f46901ed14610720578063f7260d3e14610740578063f72f863b14610760578063f851a4401461078057600080fd5b8063c455279114610644578063ca68d8f614610674578063cea8ef5c1461068a578063e2587da1146106c0578063f2fde38b146106e057600080fd5b8063aeee23c4116100f2578063aeee23c414610522578063b796af131461055d578063bb8c17d314610598578063be75ddac146105b8578063c1a8e6fd146105f357600080fd5b80638e8920e3146104bc578063972250fe146104cf578063aa0bd4de146104e2578063adc927af1461050257600080fd5b806359605679116101b15780638129fc1c116101755780638129fc1c1461043157806381a52222146104465780638456cb5914610476578063861a8dcb1461048b5780638da5cb5b1461049e57600080fd5b8063596056791461036e5780635c975abb146103ae578063704b6c02146103c6578063715018a6146103e65780637ae729ca146103fb57600080fd5b80633d21e25a116101f85780633d21e25a146102d35780633eee9156146102e65780633f4ba83a14610306578063474707f01461031b578063534015b31461033b57600080fd5b80621a9f6214610234578063017e7e58146102565780630758d92414610293578063123119cd146102b357600080fd5b3661022f57005b600080fd5b34801561024057600080fd5b5061025461024f366004614d6f565b6107a0565b005b34801561026257600080fd5b5060ce54610276906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561029f57600080fd5b5060cb54610276906001600160a01b031681565b3480156102bf57600080fd5b5060cc54610276906001600160a01b031681565b6102546102e1366004614fa9565b610957565b3480156102f257600080fd5b506102546103013660046150a9565b61097d565b34801561031257600080fd5b506102546109ea565b34801561032757600080fd5b506102546103363660046150dd565b610a42565b34801561034757600080fd5b5060cc5460cd54604080516001600160a01b0393841681529290911660208301520161028a565b34801561037a57600080fd5b5061039e610389366004615194565b60d76020526000908152604090205460ff1681565b604051901515815260200161028a565b3480156103ba57600080fd5b5060335460ff1661039e565b3480156103d257600080fd5b506102546103e13660046151af565b610a84565b3480156103f257600080fd5b50610254610b29565b34801561040757600080fd5b506102766104163660046151cc565b60d4602052600090815260409020546001600160a01b031681565b34801561043d57600080fd5b50610254610b3b565b34801561045257600080fd5b5061039e6104613660046151af565b60d06020526000908152604090205460ff1681565b34801561048257600080fd5b50610254610c67565b6102546104993660046152fc565b610cbd565b3480156104aa57600080fd5b506065546001600160a01b0316610276565b6102546104ca3660046153c5565b610e29565b6102546104dd3660046153f9565b610ee6565b3480156104ee57600080fd5b506102546104fd366004615514565b610eff565b34801561050e57600080fd5b5061025461051d366004614d6f565b6110ab565b34801561052e57600080fd5b5061039e61053d36600461557f565b60d160209081526000928352604080842090915290825290205460ff1681565b34801561056957600080fd5b5061058a6105783660046151cc565b60d36020526000908152604090205481565b60405190815260200161028a565b3480156105a457600080fd5b506102546105b336600461557f565b611254565b3480156105c457600080fd5b5061039e6105d336600461557f565b60d260209081526000928352604080842090915290825290205460ff1681565b3480156105ff57600080fd5b5061062d61060e3660046151af565b60d5602052600090815260409020805460019091015460ff9091169082565b60408051921515835260208301919091520161028a565b34801561065057600080fd5b5061039e61065f3660046151af565b60d66020526000908152604090205460ff1681565b34801561068057600080fd5b5061058a61012c81565b34801561069657600080fd5b506102766106a53660046151cc565b60c9602052600090815260409020546001600160a01b031681565b3480156106cc57600080fd5b506102546106db3660046155a1565b6112f2565b3480156106ec57600080fd5b506102546106fb3660046151af565b61149e565b34801561070c57600080fd5b5060ca54610276906001600160a01b031681565b34801561072c57600080fd5b5061025461073b3660046151af565b611514565b34801561074c57600080fd5b5060cd54610276906001600160a01b031681565b34801561076c57600080fd5b5061025461077b3660046151af565b6115f8565b34801561078c57600080fd5b5060cf54610276906001600160a01b031681565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b031633146107f65760405162461bcd60e51b81526004016107ed9190615683565b60405180910390fd5b5080518251146040518060400160405280601081526020016f1b195b99dd1a081b9bdd08195c5d585b60821b815250906108435760405162461bcd60e51b81526004016107ed9190615683565b5060005b82518110156109525781818151811061086257610862615696565b602002602001015160d0600085848151811061088057610880615696565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f0bf1a6b9bd400a8478e3082dd8932968c39600716acaf5dbf7553e798c1cd36a8382815181106108f2576108f2615696565b602002602001015183838151811061090c5761090c615696565b60200260200101516040516109389291906001600160a01b039290921682521515602082015260400190565b60405180910390a18061094a816156c2565b915050610847565b505050565b61095f6116dc565b610967611735565b6109708161177b565b61097a6001609755565b50565b6109856116dc565b61098d611735565b33600090815260d0602090815260409182902054825180840190935260088352676f6e6c79206d706360c01b9183019190915260ff166109e05760405162461bcd60e51b81526004016107ed9190615683565b50610970816122c8565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b03163314610a375760405162461bcd60e51b81526004016107ed9190615683565b50610a40612a51565b565b610a4a6116dc565b610a52611735565b610a69610a6260208501856151af565b8383612aa3565b610a7a610a75846156db565b61177b565b6109526001609755565b610a8c612c02565b60408051808201909152600981526806164647265737320360bc1b60208201526001600160a01b038216610ad35760405162461bcd60e51b81526004016107ed9190615683565b5060cf80546001600160a01b0319166001600160a01b0383169081179091556040519081527f7ce7ec0b50378fb6c0186ffb5f48325f6593fcb4ca4386f21861af3129188f5c906020015b60405180910390a150565b610b31612c02565b610a406000612c5c565b600054610100900460ff1615808015610b5b5750600054600160ff909116105b80610b755750303b158015610b75575060005460ff166001145b610bd85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107ed565b6000805460ff191660011790558015610bfb576000805461ff0019166101001790555b610c03612cae565b610c0b612cdd565b610c13612d0c565b60cf80546001600160a01b03191633179055801561097a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610b1e565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b03163314610cb45760405162461bcd60e51b81526004016107ed9190615683565b50610a40612d3b565b610cc56116dc565b610ccd611735565b33600090815260d0602090815260409182902054825180840190935260088352676f6e6c79206d706360c01b9183019190915260ff16610d205760405162461bcd60e51b81526004016107ed9190615683565b503460005b8351811015610d8d57610d50848281518110610d4357610d43615696565b6020026020010151612d78565b838181518110610d6257610d62615696565b60200260200101516020015182610d7991906156e7565b915080610d85816156c2565b915050610d25565b5060005b8251811015610dce57610dbc838281518110610daf57610daf615696565b60200260200101516122c8565b80610dc6816156c2565b915050610d91565b5060408051808201909152601481527306c6566742076616c7565206d75737420626520360641b60208201528115610e195760405162461bcd60e51b81526004016107ed9190615683565b5050610e256001609755565b5050565b610e316116dc565b610e39611735565b33600090815260d0602090815260409182902054825180840190935260088352676f6e6c79206d706360c01b9183019190915260ff16610e8c5760405162461bcd60e51b81526004016107ed9190615683565b508060200151341460405180604001604052806011815260200170696e76616c6964206d73672076616c756560781b81525090610edc5760405162461bcd60e51b81526004016107ed9190615683565b5061097081612d78565b610eee6116dc565b610ef6611735565b61097081612f39565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b03163314610f4c5760405162461bcd60e51b81526004016107ed9190615683565b5060408051808201909152601081526f1b195b99dd1a081b9bdd08195c5d585b60821b6020820152838214610f945760405162461bcd60e51b81526004016107ed9190615683565b5060005b838110156110a457828282818110610fb257610fb2615696565b9050602002016020810190610fc791906151af565b60c96000878785818110610fdd57610fdd615696565b90506020020135815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555084848281811061102857611028615696565b905060200201357f0f86ee2bbb4d6370cc5e337c548e9af76e112c16b1aa97877c11e1328fa8ca3984848481811061106257611062615696565b905060200201602081019061107791906151af565b6040516001600160a01b03909116815260200160405180910390a28061109c816156c2565b915050610f98565b5050505050565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b031633146110f85760405162461bcd60e51b81526004016107ed9190615683565b5080518251146040518060400160405280601081526020016f1b195b99dd1a081b9bdd08195c5d585b60821b815250906111455760405162461bcd60e51b81526004016107ed9190615683565b5060005b82518110156109525781818151811061116457611164615696565b602002602001015160d6600085848151811061118257611182615696565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055507f4519d4931af171182c3df6a6b61730c684f07903a4bd23a3edbff97685da43748382815181106111f4576111f4615696565b602002602001015183838151811061120e5761120e615696565b602002602001015160405161123a9291906001600160a01b039290921682521515602082015260400190565b60405180910390a18061124c816156c2565b915050611149565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b031633146112a15760405162461bcd60e51b81526004016107ed9190615683565b50600082815260d3602090815260409182902083905581518481529081018390527f7ef26aca67d68e814b326749559541e70261dc0bb13ec23b061cb4efae5bf10a91015b60405180910390a15050565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b0316331461133f5760405162461bcd60e51b81526004016107ed9190615683565b5080518251146040518060400160405280601081526020016f1b195b99dd1a081b9bdd08195c5d585b60821b8152509061138c5760405162461bcd60e51b81526004016107ed9190615683565b5060005b8251811015610952578181815181106113ab576113ab615696565b602002602001015160d760008584815181106113c9576113c9615696565b60200260200101516001600160e01b0319166001600160e01b031916815260200190815260200160002060006101000a81548160ff0219169083151502179055507f2fc5194644b0d028829e475d57cad5ccad073d27cef6d863b7bd7ed88ae9a2c183828151811061143d5761143d615696565b602002602001015183838151811061145757611457615696565b60200260200101516040516114849291906001600160e01b03199290921682521515602082015260400190565b60405180910390a180611496816156c2565b915050611390565b6114a6612c02565b6001600160a01b03811661150b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016107ed565b61097a81612c5c565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b031633146115615760405162461bcd60e51b81526004016107ed9190615683565b5060408051808201909152600981526806164647265737320360bc1b60208201526001600160a01b0382166115a95760405162461bcd60e51b81526004016107ed9190615683565b5060ce80546001600160a01b0319166001600160a01b0383169081179091556040519081527f3dedba2a214b4fff9bf20fc473c114824654e0bc70512b4a92f6d5978763c28d90602001610b1e565b60cf5460408051808201909152600a81526937b7363c9030b236b4b760b11b6020820152906001600160a01b031633146116455760405162461bcd60e51b81526004016107ed9190615683565b5060408051808201909152600981526806164647265737320360bc1b60208201526001600160a01b03821661168d5760405162461bcd60e51b81526004016107ed9190615683565b5060cb80546001600160a01b0319166001600160a01b0383169081179091556040519081527f33f0bdb7050bc888ca819c34892844adff2a3109dc1810301e8fd6af0ac7edb990602001610b1e565b60026097540361172e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016107ed565b6002609755565b60335460ff1615610a405760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016107ed565b6117df60405180610120016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160001515815260200160006001600160e01b0319168152602001606081525090565b60608201516040805180820190915260118152701a5b9d985b1a59081859185c1d1bdc9251607a1b60208201529061182a5760405162461bcd60e51b81526004016107ed9190615683565b506060820151600090815260c96020908152604091829020546001600160a01b031680845282518084019093526017835276696e76616c69642061646170746f72206164647265737360481b9183019190915261189a5760405162461bcd60e51b81526004016107ed9190615683565b50815160408051808201909152600981526806164647265737320360bc1b6020820152906001600160a01b03166118e45760405162461bcd60e51b81526004016107ed9190615683565b5060006001600160a01b031682602001516001600160a01b031614156040518060400160405280600981526020016806164647265737320360bc1b815250906119405760405162461bcd60e51b81526004016107ed9190615683565b5081602001516001600160a01b031682600001516001600160a01b031614156040518060400160405280600d81526020016c1859191c995cdcc8195c5d585b609a1b815250906119a35760405162461bcd60e51b81526004016107ed9190615683565b506040808301518151808301909252600982526806164647265737320360bc1b60208301526001600160a01b03166119ee5760405162461bcd60e51b81526004016107ed9190615683565b5060cb5460408051808201909152600981526806164647265737320360bc1b6020820152906001600160a01b0316611a395760405162461bcd60e51b81526004016107ed9190615683565b5060a08201516040805180820190915260128152710616d6f756e74206d757374206265203e20360741b602082015290611a865760405162461bcd60e51b81526004016107ed9190615683565b5060c082015160408051808201909152601681527506d696e20616d6f756e74206d757374206265203e20360541b602082015290611ad75760405162461bcd60e51b81526004016107ed9190615683565b50608082015160c081901c90602081901c6001600160a01b03169063ffffffff166080840152606083015260a08201526020820151611b15906133e5565b604082015261012082015160d790600090611b2f906156fa565b6001600160e01b03191681526020808201929092526040908101600020548151808301909252600f82526e195c9c881cd95b1958dd1bdc881a59608a1b928201929092529060ff16611b945760405162461bcd60e51b81526004016107ed9190615683565b5060cc80546001600160a01b0319908116331790915560cd80549091163017905560a082015182516101408401516000928392611bd0926133f7565b6101408601819052855191935091506001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed1901611d275760a0840151611c1283346156e7565b101560405180604001604052806011815260200170696e76616c6964206d73672076616c756560781b81525090611c5c5760405162461bcd60e51b81526004016107ed9190615683565b5073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031684602001516001600160a01b031603611cab57611c9f30308660a0015160006136a6565b151560c0840152611dfd565b60cb5460a08501516101208601516040516001600160a01b0390931692611cd29190615731565b60006040518083038185875af1925050503d8060008114611d0f576040519150601f19603f3d011682016040523d82523d6000602084013e611d14565b606091505b50610100850152151560c0840152611dfd565b83516001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2148015611d74575060208401516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15611d8a57611c9f33308660a0015160016136a6565b60cb546101208501516040516001600160a01b0390921691611dac9190615731565b6000604051808303816000865af19150503d8060008114611de9576040519150601f19603f3d011682016040523d82523d6000602084013e611dee565b606091505b50610100850152151560c08401525b60cc80546001600160a01b031990811690915560cd8054909116905560c08301516101008401515115611e6757611e628461010001516040518060400160405280601181526020017003232bc103937baba32b91032b939101d1607d1b8152506139a2565b611e93565b604051806040016040528060128152602001711a5b9d195c9b985b081ddc985c0819985a5b60721b8152505b90611eb15760405162461bcd60e51b81526004016107ed9190615683565b508260400151611ec485602001516133e5565b611ece91906156e7565b602084015260c08401516060840151611ee7919061574d565b836020015110156040518060400160405280600e81526020016d36b4b71030b6b7bab73a1032b93960911b81525090611f335760405162461bcd60e51b81526004016107ed9190615683565b5060ce5460208501516060850151611f55926001600160a01b03169190613b05565b82606001518360200151611f6991906156e7565b83602001818152505073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031684602001516001600160a01b03160361203b5782600001516001600160a01b0316636f82189d348560200151611fc6919061574d565b33876040015133896020015189602001518a608001518c61010001516040518963ffffffff1660e01b81526004016120049796959493929190615760565b6000604051808303818588803b15801561201d57600080fd5b505af1158015612031573d6000803e3d6000fd5b505050505061212b565b612052836000015185602001518560200151613b05565b83516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed19016120a65782600001516001600160a01b0316636f82189d8560a00151843461209c91906156e7565b611fc691906156e7565b82600001516001600160a01b0316636f82189d3433876040015133896020015189602001518a608001518c61010001516040518963ffffffff1660e01b81526004016120f89796959493929190615760565b6000604051808303818588803b15801561211157600080fd5b505af1158015612125573d6000803e3d6000fd5b50505050505b60006121558460a001518560800151876060015188604001518961010001518a6101400151613be5565b905084606001517fb9dae57db52a734b183c77227c96068231beb6a93a060ca7a9d3164f716714ea33876040015188600001518960a001518a602001518a602001518b60600151896040516121b19897969594939291906157f2565b60405180910390a273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031685602001516001600160a01b03160361225a578360400151346121fd87602001516133e5565b612207919061574d565b101560405180604001604052806014815260200173736c617368206d75636820746f6f206d6f6e657960601b815250906122545760405162461bcd60e51b81526004016107ed9190615683565b506110a4565b836040015161226c86602001516133e5565b101560405180604001604052806014815260200173736c617368206d75636820746f6f206d6f6e657960601b815250906122b95760405162461bcd60e51b81526004016107ed9190615683565b505050505050565b6001609755565b60006122d782600001516133e5565b90506000826080015183606001516122ef919061574d565b90506122fb8382613ed8565b60408051808201909152600f81526e6e6f20656e6f756768206d6f6e657960881b6020820152818310156123425760405162461bcd60e51b81526004016107ed9190615683565b5060cb5460408051808201909152600981526806164647265737320360bc1b6020820152906001600160a01b031661238d5760405162461bcd60e51b81526004016107ed9190615683565b5060a0830151600090815260d16020908152604080832060c0870151845282529182902054825180840190935260088352671a185cc81c185a5960c21b9183019190915260ff16156123f25760405162461bcd60e51b81526004016107ed9190615683565b5060a0830151600090815260d16020908152604080832060c087015184528252808320805460ff191660019081179091558151818152808301909252909182810190803683370190505090508360c001518160008151811061245657612456615696565b602090810291909101015260ce54845160808601516000926060928392612487926001600160a01b03169190613b05565b60e0870151511561294a5760006124a68860200151896040015161425d565b60cc8054306001600160a01b03199182161790915560408a015160cd80549092166001600160a01b039182161790915589519192501673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed19016125ea5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031688602001516001600160a01b0316036125775761253d3089604001518a6060015160006136a6565b93508361257257604051806040016040528060128152602001711a5b9d195c9b985b081ddc985c0819985a5b60721b81525091505b6127e4565b60cb54606089015160e08a01516040516001600160a01b039093169261259d9190615731565b60006040518083038185875af1925050503d80600081146125da576040519150601f19603f3d011682016040523d82523d6000602084013e6125df565b606091505b5090945092506127e4565b87516001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2148015612637575060208801516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156126515761253d3089604001518a6060015160016136a6565b60007370cbb871e8f30fc8ce23609e9e0ea87b6b222f586001600160a01b0316631c6eced56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c99190615853565b60608a01518a519192506126e8916001600160a01b0316908390614305565b60cb5460e08a01516040516001600160a01b03909216916127099190615731565b6000604051808303816000865af19150503d8060008114612746576040519150601f19603f3d011682016040523d82523d6000602084013e61274b565b606091505b508a51604051636eb1769f60e11b81523060048201526001600160a01b038581166024830152939850919650919091169063dd62ed3e90604401602060405180830381865afa1580156127a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c69190615870565b156127e25788516127e2906001600160a01b0316826000614305565b505b831580156127f3575060008351115b1561282e5761282b836040518060400160405280601181526020017003232bc103937baba32b91032b939101d1607d1b8152506139a2565b91505b60cc80546001600160a01b031990811690915560cd80549091169055836128cb57612866886040015189600001518a60600151613b05565b7f6d1b775ce655ea3b568c59e0f161908781f216e4d9feb04fa524ca23a44f4b07886040015189600001518a602001518b6060015160008d608001518e60a00151898d6040516128be99989796959493929190615889565b60405180910390a1612944565b806128de89602001518a6040015161425d565b6128e891906156e7565b6040808a01518a5160208c015160808d015160a08e015194519596507f6d1b775ce655ea3b568c59e0f161908781f216e4d9feb04fa524ca23a44f4b079561293b9560009289929091908b908f90615889565b60405180910390a15b506129e2565b50604080518082018252600a8152695f5f726566756e645f5f60b01b60208201529087015187516060890151612981929190613b05565b7f6d1b775ce655ea3b568c59e0f161908781f216e4d9feb04fa524ca23a44f4b078760400151886000015189602001518a6060015160008c608001518d60a00151888c6040516129d999989796959493929190615889565b60405180910390a15b846129f088600001516133e5565b6129fa90886156e7565b111560405180604001604052806014815260200173736c617368206d75636820746f6f206d6f6e657960601b81525090612a475760405162461bcd60e51b81526004016107ed9190615683565b5050505050505050565b612a5961444d565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b8015610952576000606060e0839003612b44576040516001600160a01b03861690612add9063d505accf60e01b90879087906020016158fa565b60408051601f1981840301815290829052612af791615731565b6000604051808303816000865af19150503d8060008114612b34576040519150601f19603f3d011682016040523d82523d6000602084013e612b39565b606091505b509092509050612bb3565b610100839003612b75576040516001600160a01b03861690612add906323f2ebc360e21b90879087906020016158fa565b60405162461bcd60e51b81526020600482015260136024820152720aee4dedcce40e0cae4dad2e840d8cadccee8d606b1b60448201526064016107ed565b816110a457612be9816040518060400160405280600f81526020016e02832b936b4ba103330b4b632b21d1608d1b8152506139a2565b60405162461bcd60e51b81526004016107ed9190615683565b6065546001600160a01b03163314610a405760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016107ed565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16612cd55760405162461bcd60e51b81526004016107ed9061591e565b610a40614496565b600054610100900460ff16612d045760405162461bcd60e51b81526004016107ed9061591e565b610a406144c9565b600054610100900460ff16612d335760405162461bcd60e51b81526004016107ed9061591e565b610a406144f0565b612d43611735565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a863390565b600160005260d360209081527fb0a3e43c7bb3d788f8bb37bbdf867a9bb5c27b60c1c3803c8e0f152e14296a16548282015160408051808201909152601281527165786365656420616c6c6f7765642067617360701b938101939093521115612df45760405162461bcd60e51b81526004016107ed9190615683565b50604080820151600090815260d2602090815282822060608501518352815290829020548251808401909352600f83526e68617320726563656976652067617360881b9183019190915260ff1615612e5f5760405162461bcd60e51b81526004016107ed9190615683565b50604080820151600090815260d26020908152828220606085015183528152919020805460ff19166001179055815190820151612eb2919073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90613b05565b60408051600180825281830190925260009160208083019080368337019050509050816060015181600081518110612eec57612eec615696565b6020026020010181815250507fc9f1b98ce4fd29c9b2de9c4514957faa4bf8fbcad43c471530fb873726c3c286826000015183602001518460400151846040516112e69493929190615969565b80516040805180820190915260118152701a5b9d985b1a59081859185c1d1bdc9251607a1b602082015290612f815760405162461bcd60e51b81526004016107ed9190615683565b508051600090815260c960209081526040918290205482518084019093526017835276696e76616c69642061646170746f72206164647265737360481b918301919091526001600160a01b03169081612fed5760405162461bcd60e51b81526004016107ed9190615683565b5060006001600160a01b031682602001516001600160a01b031614156040518060400160405280600981526020016806164647265737320360bc1b815250906130495760405162461bcd60e51b81526004016107ed9190615683565b506040808301518151808301909252600982526806164647265737320360bc1b60208301526001600160a01b03166130945760405162461bcd60e51b81526004016107ed9190615683565b5060808201516040805180820190915260128152710616d6f756e74206d757374206265203e20360741b6020820152906130e15760405162461bcd60e51b81526004016107ed9190615683565b5060408051808201909152600081526060602082015261310e836080015184604001518560c001516133f7565b6020830181905290825260c0840152606083015134906000908190819061314d9060c081901c916001600160a01b03602083901c169163ffffffff1690565b92509250925073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031687604001516001600160a01b0316036132b5578451608088015161319690849061574d565b6131a0919061574d565b34101560405180604001604052806011815260200170696e76616c6964206d73672076616c756560781b815250906131eb5760405162461bcd60e51b81526004016107ed9190615683565b5084516131f890856156e7565b935081156132b05760ce546040516000916001600160a01b03169084908381818185875af1925050503d806000811461324d576040519150601f19603f3d011682016040523d82523d6000602084013e613252565b606091505b505090508060405180604001604052806013815260200172115512081d1c985b9cd9995c8819985a5b1959606a1b815250906132a15760405162461bcd60e51b81526004016107ed9190615683565b506132ac83866156e7565b9450505b6132ef565b81156132db5760ce5460408801516132db9133916001600160a01b039091169085614520565b6132ef338789604001518a60800151614520565b602087015160408089015160808a015160a08b01519251636f82189d60e01b81526001600160a01b038b1694636f82189d948a9461333594339485938b91600401615760565b6000604051808303818588803b15801561334e57600080fd5b505af1158015613362573d6000803e3d6000fd5b5050505050600061338784838a600001518b602001518c60a001518d60c00151613be5565b905087600001517ff6481cbc1da19356c5cb6b884be507da735b89f21dc4bbb7c9b7cc0968b03b7a338a602001518b604001518c6080015188876040516133d396959493929190615996565b60405180910390a25050505050505050565b60006133f1823061425d565b92915050565b60006060601f193601356561aefa81eaab60d11b6001600160d01b03198216016136995760408051808201909152601b81527f6572726f7220636f6d6d697373696f6e2072617465206c696d6974000000000060208201526001600160a01b0382169065ffffffffffff60a084901c169061012c82111561348b5760405162461bcd60e51b81526004016107ed9190615683565b50613498816127106156e7565b6134a2828a6159e4565b6134ac91906159fb565b945073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03881601613585576000826001600160a01b03168660405160006040518083038185875af1925050503d8060008114613520576040519150601f19603f3d011682016040523d82523d6000602084013e613525565b606091505b50509050806040518060400160405280601b81526020017f636f6d6d697373696f6e2077697468206574686572206572726f7200000000008152509061357e5760405162461bcd60e51b81526004016107ed9190615683565b5050613591565b61359133838988614520565b855161359e6020826156e7565b6001600160401b038111156135b5576135b5614bf1565b6040519080825280601f01601f1916602001820160405280156135df576020820181803683370190505b50945060005b6135f06020836156e7565b81101561364f5787818151811061360957613609615696565b602001015160f81c60f81b86828151811061362657613626615696565b60200101906001600160f81b031916908160001a90535080613647816156c2565b9150506135e5565b50604080518781526001600160a01b03851660208201527fffc60ee157a42f4d8edbd1897e6581a96d9ed04e44fb2ab53a47ce1eb8f2775b910160405180910390a150505061369d565b8391505b50935093915050565b60008083116040518060400160405280601781526020017f7772617020616d6f756e74206d757374206265203e2030000000000000000000815250906136ff5760405162461bcd60e51b81526004016107ed9190615683565b5081156138fe57306001600160a01b038616036137ac5760405163a9059cbb60e01b8152735703b683c7f928b721ca95da988d73a3299d475760048201526024810184905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29063a9059cbb906044016020604051808303816000875af1158015613782573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a69190615a1d565b506137e0565b6137e085735703b683c7f928b721ca95da988d73a3299d475773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc286614520565b604051632e1a7d4d60e01b815260048101849052735703b683c7f928b721ca95da988d73a3299d475790632e1a7d4d90602401600060405180830381600087803b15801561382d57600080fd5b505af1158015613841573d6000803e3d6000fd5b505050506001600160a01b03841630146138f9576000846001600160a01b03168460405160006040518083038185875af1925050503d80600081146138a2576040519150601f19603f3d011682016040523d82523d6000602084013e6138a7565b606091505b505090508060405180604001604052806013815260200172115512081d1c985b9cd9995c8819985a5b1959606a1b815250906138f65760405162461bcd60e51b81526004016107ed9190615683565b50505b613996565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561394d57600080fd5b505af1158015613961573d6000803e3d6000fd5b505050506001600160a01b038516301490506139965761399673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc285856145a0565b5060015b949350505050565b60606004835110613ad35760208301516001600160e01b0319811662461bcd60e51b1480156139d357506044845110155b15613a73576024848101518086018201805191929091906139f590849061574d565b6139ff919061574d565b86511015613a475760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b2103932bb32b93a103932b0b9b7b760591b60448201526064016107ed565b8481604051602001613a5a929190615a3a565b60405160208183030381529060405293505050506133f1565b6001600160e01b03198116634e487b7160e01b148015613a94575083516024145b15613ad157602484015183613aa8826145d0565b604051602001613ab9929190615a89565b604051602081830303815290604052925050506133f1565b505b81613add846145f8565b604051602001613aee929190615abe565b604051602081830303815290604052905092915050565b80156109525773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601613bd1576000836001600160a01b03168260405160006040518083038185875af1925050503d8060008114613b7d576040519150601f19603f3d011682016040523d82523d6000602084013e613b82565b606091505b505090508060405180604001604052806013815260200172115512081d1c985b9cd9995c8819985a5b1959606a1b815250906110a45760405162461bcd60e51b81526004016107ed9190615683565b6109526001600160a01b03831684836145a0565b60408051600680825260e082019092526060916020820160c0803683370190505090508660001b81600081518110613c1f57613c1f615696565b6020026020010181815250508560001b81600181518110613c4257613c42615696565b6020026020010181815250506001851480613c5d5750600285145b15613cf5576040516bffffffffffffffffffffffff19606086901b166020820152603401604051602081830303815290604052613c9990615b0f565b81600281518110613cac57613cac615696565b60209081029190910181019190915260408051600081529182019052613cd190615b0f565b81600381518110613ce457613ce4615696565b602002602001018181525050613da7565b60038503613da757600083806020019051810190613d139190615b7b565b50925050506000613d23826147df565b905080600081518110613d3857613d38615696565b602002602001015183600281518110613d5357613d53615696565b602002602001018181525050600181511115613da45780600181518110613d7c57613d7c615696565b602002602001015183600381518110613d9757613d97615696565b6020026020010181815250505b50505b815115613e5957600082806020019051810190613dc49190615bf9565b90506000613dd1826147df565b905080600081518110613de657613de6615696565b602002602001015183600481518110613e0157613e01615696565b602002602001018181525050600181511115613e525780600181518110613e2a57613e2a615696565b602002602001015183600581518110613e4557613e45615696565b6020026020010181815250505b5050613ece565b80600281518110613e6c57613e6c615696565b602002602001015181600481518110613e8757613e87615696565b60200260200101818152505080600381518110613ea657613ea6615696565b602002602001015181600581518110613ec157613ec1615696565b6020026020010181815250505b9695505050505050565b600080836101000151806020019051810190613ef49190615c2d565b91509150600080600080613f0886866148aa565b60408051808201909152600b81526a3d32b9379039b4b3b732b960a91b6020820152939750919550935091506001600160a01b038516613f5b5760405162461bcd60e51b81526004016107ed9190615683565b506001600160a01b038416600090815260d66020908152604091829020548251808401909352601083526f6e6f74206f7261636c652070726f787960801b9183019190915260ff16613fc05760405162461bcd60e51b81526004016107ed9190615683565b50600360005260d360209081527f64de0974ce81404dc9f7f680a2e3b4cfc70679cd50192b307cda861d6e23b6505460408051808201909152600c81526b195c9c8818da185a5b881a5960a21b9281019290925284146140335760405162461bcd60e51b81526004016107ed9190615683565b5060408051808201909152601681527531b7b73a3930b1ba1030b2323932b9b99032b93937b960511b60208201526001600160a01b038316301461408a5760405162461bcd60e51b81526004016107ed9190615683565b5080602001518860c001511460405180604001604052806014815260200173636c61696d206e6f206f7261636c6520696e666f60601b815250906140e15760405162461bcd60e51b81526004016107ed9190615683565b50604080820151898201518251808401909352601483527331b630b4b6903a379030b2323932b9b99032b93960611b60208401526001600160a01b039081169116146141405760405162461bcd60e51b81526004016107ed9190615683565b506060810151885160408051808201909152601781527f636c61696d20746f6b656e2061646472657373206572720000000000000000006020820152916001600160a01b039182169116146141a85760405162461bcd60e51b81526004016107ed9190615683565b506002600090815260d36020527f8f145ec1981fda056bae73a9467bf215a78583d2d921572993bc5b1783a6fe0c549060646141e4818461574d565b8460a001516141f391906159e4565b6141fd91906159fb565b9050808911156040518060400160405280601681526020017531b630b4b6903a37b5b2b71030b6b7bab73a1032b93960511b815250906142505760405162461bcd60e51b81526004016107ed9190615683565b5050505050505050505050565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146142f2576040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa1580156142c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ed9190615870565b6142fe565b816001600160a01b0316315b9392505050565b80158061437f5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061437d9190615870565b155b6143ea5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016107ed565b6040516001600160a01b03831660248201526044810182905261095290849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526149f9565b60335460ff16610a405760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016107ed565b600054610100900460ff166144bd5760405162461bcd60e51b81526004016107ed9061591e565b6033805460ff19169055565b600054610100900460ff166122c15760405162461bcd60e51b81526004016107ed9061591e565b600054610100900460ff166145175760405162461bcd60e51b81526004016107ed9061591e565b610a4033612c5c565b60405163052f523360e11b81526001600160a01b038084166004830152808616602483015284166044820152606481018290527370cbb871e8f30fc8ce23609e9e0ea87b6b222f5890630a5ea46690608401600060405180830381600087803b15801561458c57600080fd5b505af1158015612a47573d6000803e3d6000fd5b6040516001600160a01b03831660248201526044810182905261095290849063a9059cbb60e01b90606401614416565b60606133f1826040516020016145e891815260200190565b6040516020818303038152906040525b80516060906f181899199a1a9b1b9c1cb0b131b232b360811b906000906146209060026159e4565b61462b90600261574d565b6001600160401b0381111561464257614642614bf1565b6040519080825280601f01601f19166020018201604052801561466c576020820181803683370190505b509050600360fc1b8160008151811061468757614687615696565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106146b6576146b6615696565b60200101906001600160f81b031916908160001a90535060005b84518110156147d7578260048683815181106146ee576146ee615696565b01602001516001600160f81b031916901c60f81c6010811061471257614712615696565b1a60f81b826147228360026159e4565b61472d90600261574d565b8151811061473d5761473d615696565b60200101906001600160f81b031916908160001a9053508285828151811061476757614767615696565b60209101015160f81c600f166010811061478357614783615696565b1a60f81b826147938360026159e4565b61479e90600361574d565b815181106147ae576147ae615696565b60200101906001600160f81b031916908160001a905350806147cf816156c2565b9150506146d0565b509392505050565b6060600060208351601f6147f3919061574d565b6147fd91906159fb565b9050806001600160401b0381111561481757614817614bf1565b604051908082528060200260200182016040528015614840578160200160208202803683370190505b50915060005b818110156148a35760008061485c8360206159e4565b61486790602061574d565b90508086015191508185848151811061488257614882615696565b6020026020010181815250505050808061489b906156c2565b915050614846565b5050919050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101829052819081906000806000878060200190518101906148f89190615c86565b9250925092506000898051906020012060405160200161494491907f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b60408051601f1981840301815282825280516020918201206000845290830180835281905260ff8516918301919091526060820186905260808201859052915060019060a0016020604051602081039080840390855afa1580156149ac573d6000803e3d6000fd5b50505060206040510351975050505050858060200190518101906149d09190615cc5565b60a089015260808801526060870152604086015260208501528352909350915092959194509250565b6000614a4e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614ace9092919063ffffffff16565b9050805160001480614a6f575080806020019051810190614a6f9190615a1d565b6109525760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107ed565b606061399a848460008585600080866001600160a01b03168587604051614af59190615731565b60006040518083038185875af1925050503d8060008114614b32576040519150601f19603f3d011682016040523d82523d6000602084013e614b37565b606091505b5091509150614b4887838387614b53565b979650505050505050565b60608315614bc2578251600003614bbb576001600160a01b0385163b614bbb5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107ed565b508161399a565b61399a8383815115614bd75781518083602001fd5b8060405162461bcd60e51b81526004016107ed9190615683565b634e487b7160e01b600052604160045260246000fd5b60405161016081016001600160401b0381118282101715614c2a57614c2a614bf1565b60405290565b60405161012081016001600160401b0381118282101715614c2a57614c2a614bf1565b60405160e081016001600160401b0381118282101715614c2a57614c2a614bf1565b604051601f8201601f191681016001600160401b0381118282101715614c9d57614c9d614bf1565b604052919050565b60006001600160401b03821115614cbe57614cbe614bf1565b5060051b60200190565b6001600160a01b038116811461097a57600080fd5b8035614ce881614cc8565b919050565b801515811461097a57600080fd5b600082601f830112614d0c57600080fd5b81356020614d21614d1c83614ca5565b614c75565b82815260059290921b84018101918181019086841115614d4057600080fd5b8286015b84811015614d64578035614d5781614ced565b8352918301918301614d44565b509695505050505050565b60008060408385031215614d8257600080fd5b82356001600160401b0380821115614d9957600080fd5b818501915085601f830112614dad57600080fd5b81356020614dbd614d1c83614ca5565b82815260059290921b84018101918181019089841115614ddc57600080fd5b948201945b83861015614e03578535614df481614cc8565b82529482019490820190614de1565b96505086013592505080821115614e1957600080fd5b50614e2685828601614cfb565b9150509250929050565b60006001600160401b03821115614e4957614e49614bf1565b50601f01601f191660200190565b600082601f830112614e6857600080fd5b8135614e76614d1c82614e30565b818152846020838601011115614e8b57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101608284031215614ebb57600080fd5b614ec3614c07565b9050614ece82614cdd565b8152614edc60208301614cdd565b6020820152614eed60408301614cdd565b6040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e0820152610100808301356001600160401b0380821115614f4057600080fd5b614f4c86838701614e57565b83850152610120925082850135915080821115614f6857600080fd5b614f7486838701614e57565b83850152610140925082850135915080821115614f9057600080fd5b50614f9d85828601614e57565b82840152505092915050565b600060208284031215614fbb57600080fd5b81356001600160401b03811115614fd157600080fd5b61399a84828501614ea8565b60006101208284031215614ff057600080fd5b614ff8614c30565b905061500382614cdd565b815261501160208301614cdd565b602082015261502260408301614cdd565b6040820152606082013560608201526080820135608082015260a082013560a082015260c082013560c082015260e08201356001600160401b038082111561506957600080fd5b61507585838601614e57565b60e08401526101009150818401358181111561509057600080fd5b61509c86828701614e57565b8385015250505092915050565b6000602082840312156150bb57600080fd5b81356001600160401b038111156150d157600080fd5b61399a84828501614fdd565b6000806000604084860312156150f257600080fd5b83356001600160401b038082111561510957600080fd5b90850190610160828803121561511e57600080fd5b9093506020850135908082111561513457600080fd5b818601915086601f83011261514857600080fd5b81358181111561515757600080fd5b87602082850101111561516957600080fd5b6020830194508093505050509250925092565b80356001600160e01b031981168114614ce857600080fd5b6000602082840312156151a657600080fd5b6142fe8261517c565b6000602082840312156151c157600080fd5b81356142fe81614cc8565b6000602082840312156151de57600080fd5b5035919050565b600060a082840312156151f757600080fd5b60405160a081016001600160401b03828210818311171561521a5761521a614bf1565b816040528293508435915061522e82614cc8565b818352602085013560208401526040850135604084015260608501356060840152608085013591508082111561526357600080fd5b5061527085828601614e57565b6080830152505092915050565b600082601f83011261528e57600080fd5b8135602061529e614d1c83614ca5565b82815260059290921b840181019181810190868411156152bd57600080fd5b8286015b84811015614d645780356001600160401b038111156152e05760008081fd5b6152ee8986838b0101614fdd565b8452509183019183016152c1565b6000806040838503121561530f57600080fd5b82356001600160401b038082111561532657600080fd5b818501915085601f83011261533a57600080fd5b8135602061534a614d1c83614ca5565b82815260059290921b8401810191818101908984111561536957600080fd5b8286015b848110156153a1578035868111156153855760008081fd5b6153938c86838b01016151e5565b84525091830191830161536d565b50965050860135925050808211156153b857600080fd5b50614e268582860161527d565b6000602082840312156153d757600080fd5b81356001600160401b038111156153ed57600080fd5b61399a848285016151e5565b60006020828403121561540b57600080fd5b81356001600160401b038082111561542257600080fd5b9083019060e0828603121561543657600080fd5b61543e614c53565b8235815261544e60208401614cdd565b602082015261545f60408401614cdd565b6040820152606083013560608201526080830135608082015260a08301358281111561548a57600080fd5b61549687828601614e57565b60a08301525060c0830135828111156154ae57600080fd5b6154ba87828601614e57565b60c08301525095945050505050565b60008083601f8401126154db57600080fd5b5081356001600160401b038111156154f257600080fd5b6020830191508360208260051b850101111561550d57600080fd5b9250929050565b6000806000806040858703121561552a57600080fd5b84356001600160401b038082111561554157600080fd5b61554d888389016154c9565b9096509450602087013591508082111561556657600080fd5b50615573878288016154c9565b95989497509550505050565b6000806040838503121561559257600080fd5b50508035926020909101359150565b600080604083850312156155b457600080fd5b82356001600160401b03808211156155cb57600080fd5b818501915085601f8301126155df57600080fd5b813560206155ef614d1c83614ca5565b82815260059290921b8401810191818101908984111561560e57600080fd5b948201945b83861015614e03576156248661517c565b82529482019490820190615613565b60005b8381101561564e578181015183820152602001615636565b50506000910152565b6000815180845261566f816020860160208601615633565b601f01601f19169290920160200192915050565b6020815260006142fe6020830184615657565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016156d4576156d46156ac565b5060010190565b60006133f13683614ea8565b818103818111156133f1576133f16156ac565b805160208201516001600160e01b031980821692919060048310156157295780818460040360031b1b83161693505b505050919050565b60008251615743818460208701615633565b9190910192915050565b808201808211156133f1576133f16156ac565b6001600160a01b03888116825287811660208301528681166040830152851660608201526080810184905260a0810183905260e060c082018190526000906157aa90830184615657565b9998505050505050505050565b600081518084526020808501945080840160005b838110156157e7578151875295820195908201906001016157cb565b509495945050505050565b6001600160a01b03898116825288811660208301528781166040830152606082018790528516608082015260a0810184905260c0810183905261010060e08201819052600090615844838201856157b7565b9b9a5050505050505050505050565b60006020828403121561586557600080fd5b81516142fe81614cc8565b60006020828403121561588257600080fd5b5051919050565b600061012060018060a01b03808d168452808c166020850152808b166040850152508860608401528760808401528660a08401528560c08401528060e08401526158d581840186615657565b90508281036101008401526158ea81856157b7565b9c9b505050505050505050505050565b6001600160e01b031984168152818360048301376000910160040190815292915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60018060a01b0385168152836020820152826040820152608060608201526000613ece60808301846157b7565b6001600160a01b038781168252868116602083015285166040820152606081018490526080810183905260c060a082018190526000906159d8908301846157b7565b98975050505050505050565b80820281158282048414176133f1576133f16156ac565b600082615a1857634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615a2f57600080fd5b81516142fe81614ced565b60008351615a4c818460208801615633565b6508ae4e4dee4560d31b9083019081528351615a6f816006840160208801615633565b602960f81b60069290910191820152600701949350505050565b60008351615a9b818460208801615633565b650a0c2dcd2c6560d31b9083019081528351615a6f816006840160208801615633565b60008351615ad0818460208801615633565b670aadcd6dcdeeedc560c31b9083019081528351615af5816008840160208801615633565b602960f81b60089290910191820152600901949350505050565b80516020808301519190811015615b30576000198160200360031b1b821691505b50919050565b600082601f830112615b4757600080fd5b8151615b55614d1c82614e30565b818152846020838601011115615b6a57600080fd5b61399a826020830160208701615633565b60008060008060808587031215615b9157600080fd5b8451615b9c81614cc8565b60208601519094506001600160401b0380821115615bb957600080fd5b615bc588838901615b36565b94506040870151915080821115615bdb57600080fd5b50615be887828801615b36565b606096909601519497939650505050565b600060208284031215615c0b57600080fd5b81516001600160401b03811115615c2157600080fd5b61399a84828501615b36565b60008060408385031215615c4057600080fd5b82516001600160401b0380821115615c5757600080fd5b615c6386838701615b36565b93506020850151915080821115615c7957600080fd5b50614e2685828601615b36565b600080600060608486031215615c9b57600080fd5b8351925060208401519150604084015160ff81168114615cba57600080fd5b809150509250925092565b600080600080600080600080610100898b031215615ce257600080fd5b885197506020890151615cf481614cc8565b60408a015160608b015160808c015160a08d015160c08e015160e0909e01519c9f949e50929c919b909a50919850965094509250505056fea26469706673582212203e8be36b2869df4619bb105618305e70b502de8d496dc330c44a380a3914672e64736f6c63430008130033
Verified Source Code Partial Match
Compiler: v0.8.19+commit.7dd6d404
EVM: paris
Optimization: Yes (200 runs)
XBridge.sol 1026 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "./adaptor/BridgeAdaptorBase.sol";
import "./helpers/Constants.sol";
import "./helpers/Errors.sol";
import "./interfaces/IDaiLikePermit.sol";
import "./interfaces/IApproveProxy.sol";
import "./interfaces/IWNativeRelayer.sol";
import "./interfaces/IWETH.sol";
import "./libraries/Bytes.sol";
import "./libraries/RevertReasonParser.sol";
import "./libraries/CommissionLib.sol";
/**
* @title XBridge
* @notice Entrance for Bridge
* - Users can:
* # Bridge: Initiate cross-chain asset transfers.
* # Swap and bridge: Perform token swaps and initiate cross-chain transfers.
* @dev XBridge is a smart contract that serves as the entrance for cross-chain operations,
* allowing users to interact with various functionalities such as bridging assets,
* swapping and bridging tokens, and claiming assets on the destination chain.
*/
contract XBridge is PausableUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable, CommissionLib {
using SafeERC20Upgradeable for IERC20Upgradeable;
// Struct representing the information needed for a bridge transaction
struct BridgeRequestV2 {
uint256 adaptorId;
address to;
address token;
uint256 toChainId; // orderId[64bit] | gasFeeAmount[160] | target chainId[32bit]
uint256 amount;
bytes data; // router data
bytes extData;
}
// Struct representing the information needed for a swap and bridge transaction
struct SwapBridgeRequestV2 {
address fromToken; // the source token
address toToken; // the token to be bridged
address to; // the address to be bridged to
uint256 adaptorId;
uint256 toChainId; // orderId[64bit] | gasFeeAmount[160] | target chainId[32bit]
uint256 fromTokenAmount; // the source token amount
uint256 toTokenMinAmount;
uint256 toChainToTokenMinAmount;
bytes data; // router data
bytes dexData; // the call data for dexRouter
bytes extData;
}
// Struct representing the information needed for a swap transaction
struct SwapRequest {
address fromToken;
address toToken;
address to;
uint256 amount; // amount of swapped fromToken
uint256 gasFeeAmount; // tx gas fee slash from fromToken
uint256 srcChainId;
bytes32 srcTxHash;
bytes dexData;
bytes extData;
}
// Struct representing the information needed for receiving gas tokens on another chain
struct ReceiveGasRequest {
address to;
uint256 amount;
uint256 srcChainId;
bytes32 srcTxHash;
bytes extData;
}
// Struct representing a threshold configuration for a specific address
struct Threshold {
bool opened;
uint256 amount;
}
// Struct representing information related to an oracle, used for verifying certain transactions
struct OracleInfo {
uint256 srcChainId;
bytes32 txHash;
bytes32 to;
bytes32 token;
uint256 amount;
uint256 actualAmount;
}
//-------------------------------
//------- storage ---------------
//-------------------------------
mapping(uint256 => address) public adaptorInfo;
/**
* @dev This state variable is deprecated and should not be used anymore.
*/
address public approveProxy;
address public dexRouter;
address public payer;
address public receiver;
address public feeTo;
address public admin;
mapping(address => bool) public mpc;
mapping(uint256 => mapping(bytes32 => bool)) public paidTx;
mapping(uint256 => mapping(bytes32 => bool)) public receiveGasTx;
/**
* @dev Set by admin
*/
mapping(uint256 => uint256) public sysRatio;
/**
* @dev This state variable is deprecated and should not be used anymore.
*/
mapping(uint256 => address) public sysAddressConfig;
mapping(address => Threshold) public thresholdConfig;
mapping(address => bool) public proxies; // oracle proxy
mapping(bytes4 => bool) public accessSelectorId; // for swap
/**
* @notice Initializes the XBridge contract.
* @dev This function is part of the Upgradable pattern and is called once to initialize contract state.
* It sets up the initial state by invoking the initializers of the inherited contracts.
* The `admin` variable is set to the address of the account that deploys the contract.
* Note: This function is meant to be called only once during the contract deployment.
*/
function initialize() public initializer {
__Pausable_init();
__ReentrancyGuard_init();
__Ownable_init();
admin = msg.sender;
}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
//-------------------------------
//------- Events ----------------
//-------------------------------
event DexRouterChanged(address _dexRouter);
/**
* @notice Event emitted when a bridge transaction occurs
*/
event LogBridgeTo(
uint256 indexed _adaptorId,
address _from,
address _to,
address _token,
uint256 _amount,
uint256 _receiveFee,
bytes32[] ext
);
/**
* @notice Event emitted when a swap and bridge transaction occurs
*/
event LogSwapAndBridgeTo(
uint256 indexed _adaptorId,
address _from,
address _to,
address _fromToken,
uint256 _fromAmount,
address _toToken,
uint256 _toAmount,
uint256 _receiveFee,
bytes32[] ext
);
event FeeToChanged(address _feeTo);
event AdminChanged(address _newAdmin);
event GasTokenReceived(
address to,
uint256 amount,
uint256 srcChainId,
bytes32[] ext
);
/**
* @notice Event emitted when a claim transaction occurs
*/
event Claimed(
address to,
address fromToken,
address toToken,
uint256 fromTokenAmount,
uint256 toTokenAmount,
uint256 gasFeeAmount,
uint256 srcChainId,
string errInfo,
bytes32[] ext
);
event AdaptorsChanged(uint256 indexed _adaptorId, address _adaptor);
event MpcChanged(address _mpc, bool _enable);
event SysRatioChanged(uint256 _index, uint256 _ratio);
event ProxiesChanged(address _proxy, bool _enable);
event AccessSelectorIdChanged(bytes4 _selectorId, bool _enable);
//-------------------------------
//------- Modifier --------------
//-------------------------------
modifier onlyMPC() {
require(mpc[msg.sender], XBridgeErrors.ONLY_MPC);
_;
}
modifier onlyAdmin() {
require(msg.sender == admin, XBridgeErrors.ONLY_ADMIN);
_;
}
//-------------------------------
//------- Internal Functions ----
//-------------------------------
/**
* @notice Internal pure function to extract information from a packed uint256 value representing gas receive details
* @param toChainId Packed uint256 value containing order ID, gas fee amount, and chain ID
*/
function _getGasReceiveAmount(uint256 toChainId)
internal
pure
returns (
uint256 orderId,
uint256 gasFeeAmount,
uint256 chainId
)
{
orderId = (toChainId & 0xffffffffffffffff000000000000000000000000000000000000000000000000) >> 192;
gasFeeAmount = (toChainId & 0x0000000000000000ffffffffffffffffffffffffffffffffffffffff00000000) >> 32;
chainId = toChainId & 0x00000000000000000000000000000000000000000000000000000000ffffffff;
}
/**
* @notice Internal function to perform a token deposit operation.
* @dev Ensures that the caller has sufficient allowance to deposit the specified amount of tokens.
* @param from The address from which tokens are transferred.
* @param to The recipient address to receive the deposited tokens.
* @param token The address of the ERC20 token being deposited.
* @param amount The amount of tokens to be deposited.
*/
function _deposit(
address from,
address to,
address token,
uint256 amount
) internal {
IApproveProxy(XBridgeConstants.APPROVE_PROXY).claimTokens(token, from, to, amount);
}
function _getBalanceOf(address token) internal view returns (uint256) {
return _getBalanceOf(token, address(this));
}
function _getBalanceOf(address token, address who) internal view returns(uint256) {
return token == XBridgeConstants.NATIVE_TOKEN ? who.balance : IERC20Upgradeable(token).balanceOf(who);
}
/**
* @notice Internal function to transfer ERC20 tokens or native tokens (ETH) to a specified address.
* @param to The address to which tokens are transferred.
* @param token The address of the ERC20 token to be transferred.
* @param amount The amount of tokens to be transferred.
*/
function _transferToken(address to, address token, uint256 amount) internal {
if (amount > 0) {
if (token == XBridgeConstants.NATIVE_TOKEN) {
(bool success, ) = payable(to).call{value: amount}("");
require(success, XBridgeErrors.TRANSFER_ETH_FAILD);
} else {
IERC20Upgradeable(token).safeTransfer(to, amount);
}
}
}
/**
* @notice Internal pure function to construct extension data for cross-chain transaction.
* @param orderId The unique identifier for the cross-chain transaction.
* @param toChainId The identifier of the target chain.
* @param adaptorId The identifier of the cross-chain adaptor used.
* @param to The destination address on the target chain.
* @param data Additional data specific to the cross-chain adaptor.
* @param extData Additional extension data containing user-specific information.
* @return ext An array of bytes32 values representing the constructed extension data.
*/
function _constructExt(uint256 orderId, uint256 toChainId, uint256 adaptorId, address to, bytes memory data, bytes memory extData)
internal
pure
returns(bytes32[] memory ext)
{
ext = new bytes32[](6);
ext[0] = bytes32(orderId);
ext[1] = bytes32(toChainId);
if (adaptorId == XBridgeConstants.ADAPTER_ID_ANYSWAP
|| adaptorId == XBridgeConstants.ADAPTER_ID_CBRIDGE) {
ext[2] = bytes32(abi.encodePacked(to));
ext[3] = bytes32(abi.encodePacked(""));
} else if (adaptorId == XBridgeConstants.ADAPTER_ID_SWFT) {
(,,string memory destination,) = abi.decode(data, (address, string, string, uint256));
bytes32[] memory destBytes32Arr = Bytes.bytesToBytes32Array(bytes(destination));
ext[2] = destBytes32Arr[0];
if (destBytes32Arr.length > 1) {
ext[3] = destBytes32Arr[1];
}
}
if (extData.length > 0) {
(string memory userAddress) = abi.decode(extData, (string));
bytes32[] memory userAddressBytes32Arr = Bytes.bytesToBytes32Array(bytes(userAddress));
ext[4] = userAddressBytes32Arr[0];
if (userAddressBytes32Arr.length > 1) {
ext[5] = userAddressBytes32Arr[1];
}
} else {
ext[4] = ext[2];
ext[5] = ext[3];
}
return ext;
}
/**
* @notice Struct to represent the result of a commission operation.
*/
struct CommissionReturn {
uint256 commissionAmount; // commission amount
bytes extDataWithoutLast32; // extData without last 32 bytes
}
/**
* @notice Internal function to initiate a cross-chain transaction using the specified BridgeRequestV2 parameters.
* @param _request The BridgeRequestV2 struct containing transaction details.
* @dev Performs necessary validations, token transfers, and calls the outboundBridgeTo function on the selected adaptor.
*/
function _bridgeToV2Internal(BridgeRequestV2 memory _request) internal {
require(_request.adaptorId != 0, XBridgeErrors.INVALID_ADAPTOR_ID);
address adaptor = adaptorInfo[_request.adaptorId];
require(adaptor != address(0), XBridgeErrors.INVALID_ADAPTOR_ADDRESS);
require(_request.to != address(0), XBridgeErrors.ADDRESS_0);
require(_request.token != address(0), XBridgeErrors.ADDRESS_0);
require(_request.amount != 0, XBridgeErrors.AMOUNT_ZERO);
// doCommission
CommissionReturn memory vars;
(vars.commissionAmount, vars.extDataWithoutLast32) = _doCommission(_request.amount, _request.token, _request.extData);
_request.extData = vars.extDataWithoutLast32;
uint256 ethValue = msg.value;
// Extract gas fee details from toChainId
(uint256 orderId, uint256 gasFeeAmount, uint256 toChainId) = _getGasReceiveAmount(_request.toChainId);
if (_request.token == XBridgeConstants.NATIVE_TOKEN) {
require(msg.value >= _request.amount + gasFeeAmount + vars.commissionAmount, XBridgeErrors.INVALID_MSG_VALUE);
ethValue -= vars.commissionAmount; // after docommission
if (gasFeeAmount > 0) {
(bool success, ) = payable(feeTo).call{value: gasFeeAmount}("");
require(success, XBridgeErrors.TRANSFER_ETH_FAILD);
ethValue -= gasFeeAmount;
}
} else {
if (gasFeeAmount > 0) {
_deposit(msg.sender, feeTo, _request.token, gasFeeAmount);
}
_deposit(msg.sender, adaptor, _request.token, _request.amount);
}
// Call the outboundBridgeTo function on the selected adaptor
BridgeAdaptorBase(payable(adaptor)).outboundBridgeTo{value : ethValue}(
msg.sender,
_request.to,
msg.sender, // refund to msg.sender
_request.token,
_request.amount,
toChainId,
_request.data
);
// Construct extension data and emit the LogBridgeTo event
bytes32[] memory ext = _constructExt(
orderId,
toChainId,
_request.adaptorId,
_request.to,
_request.data,
_request.extData
);
emit LogBridgeTo(
_request.adaptorId,
msg.sender,
_request.to,
_request.token,
_request.amount,
gasFeeAmount,
ext
);
}
/**
* @notice Struct to represent the result of a cross-chain bridge operation.
* @dev Holds information about the adaptor, token balances, gas fee, chain ID, order ID, success status, function selector, and result data.
*/
struct BridgeVariants {
address adaptor;
uint256 toTokenBalance;
uint256 toTokenBalanceOrigin;
uint256 gasFeeAmount;
uint256 toChainId;
uint256 orderId;
bool success;
bytes4 selectorId;
bytes result;
}
/**
* @notice Internal function to perform a token swap and bridge operation using the specified SwapBridgeRequestV2 parameters.
* @param _request The SwapBridgeRequestV2 struct containing swap and bridge details.
* @dev Performs necessary validations, token swaps, bridge calls, and balance checks.
*/
function _swapBridgeToInternal(SwapBridgeRequestV2 memory _request) internal {
BridgeVariants memory vars;
require(_request.adaptorId != 0, XBridgeErrors.INVALID_ADAPTOR_ID);
vars.adaptor = adaptorInfo[_request.adaptorId];
require(vars.adaptor != address(0), XBridgeErrors.INVALID_ADAPTOR_ADDRESS);
require(_request.fromToken != address(0), XBridgeErrors.ADDRESS_0);
require(_request.toToken != address(0), XBridgeErrors.ADDRESS_0);
require(_request.fromToken != _request.toToken, XBridgeErrors.ADDRESS_EQUAL);
require(_request.to != address(0), XBridgeErrors.ADDRESS_0);
require(dexRouter != address(0), XBridgeErrors.ADDRESS_0);
require(_request.fromTokenAmount != 0, XBridgeErrors.AMOUNT_ZERO);
require(_request.toTokenMinAmount != 0, XBridgeErrors.MIN_AMOUNT_ZERO);
// Extract gas fee details from toChainId
(vars.orderId, vars.gasFeeAmount, vars.toChainId) = _getGasReceiveAmount(_request.toChainId);
vars.toTokenBalanceOrigin = _getBalanceOf(_request.toToken);
// Validate the dexData function selector
require(accessSelectorId[bytes4(_request.dexData)], XBridgeErrors.ERROR_SELECTOR_ID);
// Set payer and receiver addresses for potential refund
payer = msg.sender;
receiver = address(this);
// doCommission
(uint256 commissionAmount, bytes memory extDataWithoutLast32) = _doCommission(_request.fromTokenAmount, _request.fromToken, _request.extData);
_request.extData = extDataWithoutLast32;
// 1. prepare and swap
if (_request.fromToken == XBridgeConstants.NATIVE_TOKEN) { //FROM NATIVE
require(msg.value - commissionAmount >= _request.fromTokenAmount, XBridgeErrors.INVALID_MSG_VALUE);
if (_request.toToken == XBridgeConstants.WETH) { //ETH => WETH
vars.success = _swapWrap(address(this), address(this), _request.fromTokenAmount, false);
} else { // ETH => ERC20, use dexRouter
(vars.success, vars.result) = dexRouter.call{value : _request.fromTokenAmount}(_request.dexData);
}
} else { // FROM ERC20
if (_request.fromToken == XBridgeConstants.WETH && _request.toToken == XBridgeConstants.NATIVE_TOKEN) {
// WETH => ETH
vars.success = _swapWrap(msg.sender, address(this), _request.fromTokenAmount, true);
} else { // ERC20 => ERC20, use dexRouter
(vars.success, vars.result) = dexRouter.call(_request.dexData);
}
}
delete payer;
delete receiver;
// 2. check result and balance
require(vars.success,vars.result.length == 0 ? XBridgeErrors.INTERNAL_WRAP_FAIL : RevertReasonParser.parse(vars.result, XBridgeErrors.DEX_ROUTER_ERR));
vars.toTokenBalance = _getBalanceOf(_request.toToken) - vars.toTokenBalanceOrigin; // toToken added
require(vars.toTokenBalance >= vars.gasFeeAmount + _request.toTokenMinAmount, XBridgeErrors.MIN_AMOUNT_ERR);
// 3. Receive to token for relay gas token on target chain to user
_transferToken(feeTo, _request.toToken, vars.gasFeeAmount);
// 4. Bridge the toToken to the target chain
vars.toTokenBalance = vars.toTokenBalance - vars.gasFeeAmount;
if (_request.toToken == XBridgeConstants.NATIVE_TOKEN) {
// Internal with BridgeAdaptorBase, so it is safe to use payable
BridgeAdaptorBase(payable(vars.adaptor)).outboundBridgeTo{
value: vars.toTokenBalance + msg.value
}(
msg.sender,
_request.to,
msg.sender, // refund to msg.sender
_request.toToken,
vars.toTokenBalance,
vars.toChainId,
_request.data
);
} else {
_transferToken(vars.adaptor, _request.toToken, vars.toTokenBalance);
if (_request.fromToken == XBridgeConstants.NATIVE_TOKEN){
BridgeAdaptorBase(payable(vars.adaptor)).outboundBridgeTo{value : msg.value - commissionAmount - _request.fromTokenAmount }(
msg.sender,
_request.to,
msg.sender, // refund to msg.sender
_request.toToken,
vars.toTokenBalance,
vars.toChainId,
_request.data
);
} else {
BridgeAdaptorBase(payable(vars.adaptor)).outboundBridgeTo{value : msg.value }(
msg.sender,
_request.to,
msg.sender, // refund to msg.sender
_request.toToken,
vars.toTokenBalance,
vars.toChainId,
_request.data
);
}
}
// Construct extension data and emit the LogBridgeTo event
bytes32[] memory ext = _constructExt(
vars.orderId,
vars.toChainId,
_request.adaptorId,
_request.to,
_request.data,
_request.extData
);
emit LogSwapAndBridgeTo(
_request.adaptorId,
msg.sender,
_request.to,
_request.fromToken,
_request.fromTokenAmount,
_request.toToken,
vars.toTokenBalance,
vars.gasFeeAmount,
ext
);
// 5. Check balance
if (_request.toToken == XBridgeConstants.NATIVE_TOKEN){
// if toToken equal nativeToken, should add msg.value
require(_getBalanceOf(_request.toToken) + msg.value >= vars.toTokenBalanceOrigin, XBridgeErrors.SLASH_MUCH_TOO_MONEY);
} else {
require(_getBalanceOf(_request.toToken) >= vars.toTokenBalanceOrigin, XBridgeErrors.SLASH_MUCH_TOO_MONEY);
}
}
/**
* @notice Internal function to execute a permit on an ERC20 token if a permit data is provided.
* @param token Address of the ERC20 token.
* @param permit Permit data containing the necessary parameters for the permit function.
*/
function _permit(address token, bytes calldata permit) internal {
if (permit.length > 0) {
bool success;
bytes memory result;
if (permit.length == 32 * 7) {
// solhint-disable-next-line avoid-low-level-calls
(success, result) = token.call(abi.encodePacked(IERC20Permit.permit.selector, permit));
} else if (permit.length == 32 * 8) {
// solhint-disable-next-line avoid-low-level-calls
(success, result) = token.call(abi.encodePacked(IDaiLikePermit.permit.selector, permit));
} else {
revert("Wrong permit length");
}
if (!success) {
revert(RevertReasonParser.parse(result, "Permit failed: "));
}
}
}
/**
* @notice Internal function to receive gas tokens from the source chain and transfer them to the specified recipient.
* @param _request The ReceiveGasRequest struct containing details about the gas token receipt.
* @dev Performs necessary validations, updates state, and emits the GasTokenReceived event.
*/
function _receiveGasTokenInternal(ReceiveGasRequest memory _request) internal {
require(_request.amount <= sysRatio[XBridgeConstants.GAS_TOKEN_RECEIVE_MAX_INDEX], XBridgeErrors.EXCEED_ALLOWED_GAS);
require(!receiveGasTx[_request.srcChainId][_request.srcTxHash], XBridgeErrors.HAS_RECEIVE_GAS);
receiveGasTx[_request.srcChainId][_request.srcTxHash] = true;
_transferToken(_request.to, XBridgeConstants.NATIVE_TOKEN, _request.amount);
bytes32[] memory ext = new bytes32[](1);
ext[0] = _request.srcTxHash;
emit GasTokenReceived(_request.to, _request.amount, _request.srcChainId, ext);
}
/**
* @notice Internal function to decode a message and its signature to extract relevant information.
* @param _message The encoded message containing information about the oracle request.
* @param _signature The signature of the message for authentication.
* @return source The address of the message sender recovered from the signature.
* @return thisChainId The chain ID of this contract.
* @return thisContractAddress The address of this contract.
* @return oracleInfo An OracleInfo struct containing details of the oracle request.
* @dev Decodes the message and signature to extract source address, chain ID, contract address, and oracle request details.
*/
function _decode(bytes memory _message, bytes memory _signature)
internal
pure
returns (
address source,
uint256 thisChainId,
address thisContractAddress,
OracleInfo memory oracleInfo
)
{
{ // fix Stack too deep
(bytes32 r, bytes32 s, uint8 v) = abi.decode(_signature, (bytes32, bytes32, uint8));
bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", keccak256(_message)));
source = ecrecover(hash, v, r, s);
}
(
thisChainId,
thisContractAddress,
oracleInfo.srcChainId,
oracleInfo.txHash,
oracleInfo.to,
oracleInfo.token,
oracleInfo.amount,
oracleInfo.actualAmount
) = abi.decode(_message, (uint256, address, uint256, bytes32, bytes32, bytes32, uint256, uint256));
return (source, thisChainId, thisContractAddress, oracleInfo);
}
/**
* @notice Internal function to verify the oracle signature and details for a swap request.
* @param _request The SwapRequest struct containing swap details.
* @param _amount The amount to be verified against the oracle threshold.
* @dev Verifies the oracle signature, source address, and additional details for the swap request.
*/
function _verifyOracle(
SwapRequest memory _request,
uint256 _amount
)
view
internal
{
(bytes memory message, bytes memory signature) = abi.decode(_request.extData, (bytes, bytes));
(
address source,
uint256 thisChainId,
address thisContractAddress,
OracleInfo memory oracleInfo
) = _decode(message, signature);
// Validate the source address, oracle proxy status, chain ID, contract address, and request details
require(source != address(0), XBridgeErrors.ZERO_SIGNER);
require(proxies[source], XBridgeErrors.NOT_ORACLE_PROXY);
require(thisChainId == sysRatio[XBridgeConstants.CHAIN_ID_INDEX], XBridgeErrors.ERR_CHAIN_ID);
require(thisContractAddress == address(this), XBridgeErrors.CONTRACT_ADDRESS_ERROR);
require(_request.srcTxHash == oracleInfo.txHash, XBridgeErrors.ORACLE_NO_INFO);
require(_request.to == address(uint160(uint256(oracleInfo.to))), XBridgeErrors.ORACLE_TO_ADDRESS_ERR);
require(_request.fromToken == address(uint160(uint256(oracleInfo.token))), XBridgeErrors.ORACLE_TOKEN_ADDRESS_ERR);
// Calculate the high threshold based on the actualAmount and configured ratio
uint256 ratio = sysRatio[XBridgeConstants.CLAIM_TOKEN_RATIO_MAX_INDEX];
uint256 high = oracleInfo.actualAmount * (ratio + XBridgeConstants.DEFAULT_RATIO_BASE) / XBridgeConstants.DEFAULT_RATIO_BASE;
// Check if the requested amount is within the allowed high threshold
require(_amount <= high, XBridgeErrors.ORACLE_TOKEN_AMOUNT_ERR);
}
/**
* @notice Internal function to process the claim for a swap request, including gas fee handling and token transfer.
* @param _request The SwapRequest struct containing swap details.
* @dev Verifies the oracle, handles gas fees, performs token swap or transfer and emits the Claimed event.
*/
function _claimInternal(SwapRequest memory _request) internal {
uint256 fromTokenOriginBalance = _getBalanceOf(_request.fromToken);
// Calculate the total amount needed, including swap amount and gas fees
uint256 fromTokenNeed = _request.amount + _request.gasFeeAmount;
// Verify the oracle signature and threshold for the source token
_verifyOracle(_request, fromTokenNeed);
require(fromTokenOriginBalance >= fromTokenNeed, XBridgeErrors.NO_ENOUGH_MONEY);
require(dexRouter != address(0), XBridgeErrors.ADDRESS_0);
require(!paidTx[_request.srcChainId][_request.srcTxHash], XBridgeErrors.HAS_PAID);
paidTx[_request.srcChainId][_request.srcTxHash] = true;
// Initialize extension data for the Claimed event
bytes32[] memory ext = new bytes32[](1);
ext[0] = _request.srcTxHash;
bool success;
bytes memory result;
string memory errInfo;
// 1. Handle gas fee
_transferToken(feeTo, _request.fromToken, _request.gasFeeAmount);
// 2. Perform token swap or transfer to the user
if (_request.dexData.length > 0) {
// swap
uint256 toTokenReceiverBalance = _getBalanceOf(_request.toToken, _request.to);
// Exchange anypair using the dexRouter except WETH<=>ETH
payer = address(this);
receiver = _request.to;
if (_request.fromToken == XBridgeConstants.NATIVE_TOKEN) { // FROM NATIVE
if (_request.toToken == XBridgeConstants.WETH) { // ETH => WETH
success = _swapWrap(address(this), _request.to, _request.amount, false);
if (!success) {
errInfo = XBridgeErrors.INTERNAL_WRAP_FAIL;
}
} else { // ETH => ERC20, use dexRouter
(success, result) = dexRouter.call{value : _request.amount}(_request.dexData);
}
} else { // FROM ERC20
if (_request.fromToken == XBridgeConstants.WETH && _request.toToken == XBridgeConstants.NATIVE_TOKEN) {
// WETH => ETH
success =_swapWrap(address(this), _request.to, _request.amount, true);
if (!success) {
errInfo = XBridgeErrors.INTERNAL_WRAP_FAIL;
}
} else { // ERC20 => ERC20, use dexRouter
address tokenApprove = IApproveProxy(XBridgeConstants.APPROVE_PROXY).tokenApprove();
IERC20Upgradeable(_request.fromToken).safeApprove(tokenApprove, _request.amount);
(success, result) = dexRouter.call(_request.dexData);
if (IERC20Upgradeable(_request.fromToken).allowance(address(this), tokenApprove) != 0){
IERC20Upgradeable(_request.fromToken).safeApprove(tokenApprove, 0);
}
}
}
if (!success && result.length > 0) {
errInfo = RevertReasonParser.parse(result, XBridgeErrors.DEX_ROUTER_ERR);
}
delete payer; // payer = 0;
delete receiver;
if (!success) { // transfer fromToken if swap failed
_transferToken(_request.to, _request.fromToken, _request.amount);
emit Claimed(_request.to, _request.fromToken, _request.toToken, _request.amount, 0, _request.gasFeeAmount, _request.srcChainId, errInfo, ext);
} else {
toTokenReceiverBalance = _getBalanceOf(_request.toToken, _request.to) - toTokenReceiverBalance;
emit Claimed(_request.to, _request.fromToken, _request.toToken, 0, toTokenReceiverBalance, _request.gasFeeAmount, _request.srcChainId, errInfo, ext);
}
} else { // transfer token
errInfo = XBridgeConstants.__REFUND__;
_transferToken(_request.to, _request.fromToken, _request.amount);
emit Claimed(_request.to, _request.fromToken, _request.toToken, _request.amount, 0, _request.gasFeeAmount, _request.srcChainId, errInfo, ext);
}
// 3. Check the final balance of the source token
require(fromTokenOriginBalance - _getBalanceOf(_request.fromToken) <= fromTokenNeed, XBridgeErrors.SLASH_MUCH_TOO_MONEY);
}
/**
* @dev Internal function to swap and wrap tokens.
* @param from The address to transfer the tokens from.
* @param to The address to transfer the wrapped tokens to.
* @param amount The amount of tokens to swap and wrap.
* @param reversed Boolean indicating whether the swap is reversed (WETH => ETH).
* @return A boolean indicating the success of the swap and wrap operation.
*/
function _swapWrap(
address from,
address to,
uint256 amount,
bool reversed
) internal returns (bool) {
require(amount > 0, XBridgeErrors.WRAP_AMOUNT_ZERO);
if (reversed) {
// reversed == true: WETH => ETH
if (from == address(this)){
IWETH(address(uint160(XBridgeConstants.WETH))).transfer(XBridgeConstants.WNATIVE_RELAY, amount);
} else {
_deposit(from, XBridgeConstants.WNATIVE_RELAY, XBridgeConstants.WETH, amount);
}
IWNativeRelayer(XBridgeConstants.WNATIVE_RELAY).withdraw(amount);
if (to != address(this)){
(bool success, ) = payable(to).call{value: amount}("");
require(success, XBridgeErrors.TRANSFER_ETH_FAILD);
}
} else {
// reversed == false: ETH => WETH
IWETH(XBridgeConstants.WETH).deposit{value: amount}();
if (to != address(this)){
IERC20Upgradeable(XBridgeConstants.WETH).safeTransfer(to, amount);
}
}
return true;
}
/**
* @notice Internal function to handle commission logic
* @param inputAmount The amount of tokens to be transferred.
* @param commissionToken The address of the ERC20 token to be transferred.
* @param extData Additional extension data containing user-specific information.
* @return commissionAmount The amount of commission tokens to be transferred.
* @return extDataWithoutLast32 Additional extension data containing user-specific information without last 32 bytes.
*/
function _doCommission( uint256 inputAmount, address commissionToken, bytes memory extData) internal returns (uint256 commissionAmount, bytes memory extDataWithoutLast32) {
// Retrieve commission info from the last 32 bytes of extData
uint256 commissionInfo;
assembly {
commissionInfo := calldataload(sub(calldatasize(),0x20))
}
if ((commissionInfo & _COMMISSION_FLAG_MASK) == OKX_COMMISSION) {
// 0. decode the commissionInfo
address referrerAddress = address(uint160(commissionInfo & _REFERRER_MASK));
uint256 commissionRate = uint256((commissionInfo & _COMMISSION_FEE_MASK) >> 160);
// 1. Check the commission ratio. CommissionFeeAmount = fromTokenAmount * Rate / (10000 - Rate)
require(commissionRate <= commissionRateLimit, XBridgeErrors.COMMISSION_ERROR_RATE);
commissionAmount = (inputAmount * commissionRate) / (10000 - commissionRate);
// 2. Perform commission
if (commissionToken == XBridgeConstants.NATIVE_TOKEN) {
(bool success,) = payable(referrerAddress).call{value: commissionAmount}("");
require(success, XBridgeErrors.COMMISSION_ERROR_ETHER);
} else {
_deposit(msg.sender, referrerAddress, commissionToken, commissionAmount);
}
// 3. Restore extData
uint256 extDataSize = extData.length;
extDataWithoutLast32 = new bytes(extDataSize - 32);
for (uint256 i = 0; i < extDataSize - 32; i++) {
extDataWithoutLast32[i] = extData[i];
}
emit CommissionRecord(commissionAmount, referrerAddress);
} else {
extDataWithoutLast32 = extData;
}
}
//-------------------------------
//------- Admin functions -------
//-------------------------------
function setAdmin(address _newAdmin) external onlyOwner {
require(_newAdmin != address(0), XBridgeErrors.ADDRESS_0);
admin = _newAdmin;
emit AdminChanged(_newAdmin);
}
function setDexRouter(address _newDexRouter) external onlyAdmin {
require(_newDexRouter != address(0), XBridgeErrors.ADDRESS_0);
dexRouter = _newDexRouter;
emit DexRouterChanged(_newDexRouter);
}
function pause() external onlyAdmin {
_pause();
}
function unpause() external onlyAdmin {
_unpause();
}
function setAdaptors(uint256[] calldata _ids, address[] calldata _adaptors) external onlyAdmin {
require(_ids.length == _adaptors.length, XBridgeErrors.LENGTH_NOT_EQUAL);
for (uint256 i = 0; i < _ids.length; i++) {
adaptorInfo[_ids[i]] = _adaptors[i];
emit AdaptorsChanged(_ids[i], _adaptors[i]);
}
}
function setFeeTo(address _newFeeTo) external onlyAdmin {
require(_newFeeTo != address(0), XBridgeErrors.ADDRESS_0);
feeTo = _newFeeTo;
emit FeeToChanged(_newFeeTo);
}
function setMpc(address[] memory _mpcList, bool[] memory _v) external onlyAdmin {
require(_mpcList.length == _v.length, XBridgeErrors.LENGTH_NOT_EQUAL);
for (uint256 i = 0; i < _mpcList.length; i++) {
mpc[_mpcList[i]] = _v[i];
emit MpcChanged(_mpcList[i], _v[i]);
}
}
function setSysRatio(uint256 _index, uint256 _v) external onlyAdmin {
sysRatio[_index] = _v;
emit SysRatioChanged(_index, _v);
}
function setProxies(address[] memory proxiesList, bool[] memory values)
external
onlyAdmin
{
require(proxiesList.length == values.length, XBridgeErrors.LENGTH_NOT_EQUAL);
for (uint256 i = 0; i < proxiesList.length; i++) {
proxies[proxiesList[i]] = values[i];
emit ProxiesChanged(proxiesList[i], values[i]);
}
}
function setAccessSelectorId(bytes4[] memory selectorIds, bool[] memory values) external onlyAdmin{
require(selectorIds.length == values.length, XBridgeErrors.LENGTH_NOT_EQUAL);
for (uint256 i = 0; i < selectorIds.length; i++) {
accessSelectorId[selectorIds[i]] = values[i];
emit AccessSelectorIdChanged(selectorIds[i], values[i]);
}
}
//-------------------------------
//------- Users Functions -------
//-------------------------------
/**
* @notice Initiates the bridge operation to transfer assets to another chain using the bridge.
* @param _request The BridgeRequestV2 struct containing the details of the bridge operation.
*/
function bridgeToV2(BridgeRequestV2 memory _request)
external
payable
nonReentrant
whenNotPaused
{
_bridgeToV2Internal(_request);
}
/**
* @notice Initiates a swap and bridge operation using the bridge.
* @param _request The SwapBridgeRequestV2 struct containing the details of the swap and bridge operation.
*/
function swapBridgeToV2(SwapBridgeRequestV2 memory _request)
public
payable
nonReentrant
whenNotPaused
{
_swapBridgeToInternal(_request);
}
/**
* @notice Initiates a swap and bridge operation with permit using V2 of the bridge.
* @param _request The SwapBridgeRequestV2 struct containing the details of the swap and bridge operation.
* @param _signature The permit signature for the fromToken.
*/
function swapBridgeToWithPermit(
SwapBridgeRequestV2 calldata _request,
bytes calldata _signature
) external nonReentrant whenNotPaused {
_permit(_request.fromToken, _signature);
_swapBridgeToInternal(_request);
}
/**
* @notice Completed receiving gas tokens from the source chain.
* @param _request The ReceiveGasRequest struct containing the details of this operation.
*/
function receiveGasToken(ReceiveGasRequest memory _request)
public
payable
nonReentrant
whenNotPaused
onlyMPC
{
require(msg.value == _request.amount, XBridgeErrors.INVALID_MSG_VALUE);
_receiveGasTokenInternal(_request);
}
/**
* @notice Claims the assets on the current chain as part of the cross-chain swap.
* @param _request The SwapRequest struct containing details of the asset claiming operation.
*/
function claim(SwapRequest memory _request)
public
nonReentrant
whenNotPaused
onlyMPC
{
_claimInternal(_request);
}
/**
* @notice Performs batch operations including Gas Token receiving and asset claiming.
* @param _gasRequest Array of ReceiveGasRequest structs containing details of Gas Token receiving operations.
* @param _claimRequest Array of SwapRequest structs containing details of asset claiming operations.
*/
function doBatch(ReceiveGasRequest[] memory _gasRequest, SwapRequest[] memory _claimRequest)
public
payable
nonReentrant
whenNotPaused
onlyMPC
{
uint256 leftValue = msg.value;
for (uint256 i = 0; i < _gasRequest.length; i++) {
_receiveGasTokenInternal(_gasRequest[i]);
// DOES NOT need check, because it will overflow if less than amount
leftValue -= _gasRequest[i].amount;
}
for (uint256 i = 0; i < _claimRequest.length; i++) {
_claimInternal(_claimRequest[i]);
}
require(leftValue == 0, XBridgeErrors.LEFT_VALUE_NOT_ZERO);
}
function payerReceiver() external view returns(address, address) {
return (payer, receiver);
}
receive() external payable {}
}
Errors.sol 51 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library XBridgeErrors {
string internal constant ONLY_X_BRIDGE = "only XBridge";
string internal constant ONLY_MPC = "only mpc";
string internal constant ONLY_ADMIN = "only admin";
string internal constant ADDRESS_0 = "address 0";
string internal constant LENGTH_NOT_EQUAL = "length not equal";
string internal constant DEX_ROUTER_ERR = "dex router err : ";
string internal constant ADDRESS_EQUAL = "address equal";
string internal constant ADDRESS_NOT_EQUAL = "address not equal";
string internal constant MIN_AMOUNT_ERR = "min amount err";
string internal constant REFUND_ETH_ERROR = "refund eth err";
string internal constant REFUND_EXIST = "refund exist";
string internal constant CBRIDGE_HAS_WITHDRAW = "has withdraw";
string internal constant HAS_PAID = "has paid";
string internal constant HAS_RECEIVE_GAS = "has receive gas";
string internal constant NO_ENOUGH_MONEY = "no enough money";
string internal constant SLASH_MUCH_TOO_MONEY = "slash much too money";
string internal constant ERROR_SELECTOR_ID = "err selector id";
string internal constant EXCEED_ALLOWED_GAS = "exceed allowed gas";
string internal constant ALLOWANCE_NOT_ENOUGH = "allowance not enough";
string internal constant ORACLE_NO_INFO = "claim no oracle info";
string internal constant ORACLE_TO_ADDRESS_ERR = "claim to address err";
string internal constant ORACLE_TOKEN_ADDRESS_ERR = "claim token address err";
string internal constant ORACLE_TOKEN_AMOUNT_ERR = "claim token amount err";
string internal constant NOT_ORACLE_PROXY = "not oracle proxy";
string internal constant ERR_CHAIN_ID = "err chain id";
string internal constant ZERO_SIGNER = "zero signer";
string internal constant CONTRACT_ADDRESS_ERROR = "contract address error";
string internal constant INTERNAL_WRAP_FAIL = "internal wrap fail";
string internal constant WRAP_AMOUNT_ZERO = "wrap amount must be > 0";
string internal constant TRANSFER_ETH_FAILD = "ETH transfer failed";
string internal constant AMOUNT_ZERO = "amount must be > 0";
string internal constant MIN_AMOUNT_ZERO = "min amount must be > 0";
string internal constant LEFT_VALUE_NOT_ZERO = "left value must be 0";
string internal constant NOT_SUPPORT_CHAIN = "not support chain";
string internal constant NOT_SUPPORT_TOKEN = "not support token";
string internal constant AMOUNT_NOT_EQ_VALUE = "amount must == msg.value";
string internal constant VALUE_NOT_ENOUGH = "amount must <= msg.value";
string internal constant VALUE_MUST_ZERO = "msg.value == 0";
string internal constant INVALID_ADAPTOR_ID = "invalid adaptorID";
string internal constant INVALID_ADAPTOR_ADDRESS = "invalid adaptor address";
string internal constant INVALID_ROUTER = "invalid router";
string internal constant INVALID_MSG_VALUE = "invalid msg value";
string internal constant COMMISSION_ERROR_RATE = "error commission rate limit";
string internal constant COMMISSION_ERROR_ETHER = "commission with ether error";
}
Bytes.sol 21 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library Bytes {
function bytesToBytes32Array(bytes memory data)
internal
pure
returns (bytes32[] memory dataList)
{
uint256 N = (data.length + 31) / 32;
dataList = new bytes32[](N);
for (uint256 index = 0; index < N; index++) {
bytes32 element;
uint256 start = 32 + index * 32;
assembly {
element := mload(add(data, start))
}
dataList[index] = element;
}
}
}
IWETH.sol 26 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;
interface IWETH {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address src,
address dst,
uint256 wad
) external returns (bool);
function deposit() external payable;
function withdraw(uint256 wad) external;
}
Constants.sol 77 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library XBridgeConstants {
address public constant NATIVE_TOKEN = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
/// @dev WETH address is network-specific and needs to be changed before deployment.
/// It can not be moved to immutable as immutables are not supported in assembly
// ETH: C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
// BSC: bb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
// OEC: 8F8526dbfd6E38E3D8307702cA8469Bae6C56C15
// LOCAL: 5FbDB2315678afecb367f032d93F642f64180aa3
// LOCAL2: 02121128f1Ed0AdA5Df3a87f42752fcE4Ad63e59
// POLYGON: 0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270
// AVAX: B31f66AA3C1e785363F0875A1B74E27b85FD66c7
// FTM: 21be370D5312f44cB42ce377BC9b8a0cEF1A4C83
// ARB: 82aF49447D8a07e3bd95BD0d56f35241523fBab1
// OP: 4200000000000000000000000000000000000006
// CRO: 5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23
// CFX: 14b2D3bC65e74DAE1030EAFd8ac30c533c976A9b
// POLYZK 4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9
// MANTA 0Dc808adcE2099A9F62AA87D9670745AbA741746
// METIS 75cb093E4D61d2A2e65D8e0BBb01DE8d89b53481
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
// ETH: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58
// ETH-DEV:02D0131E5Cc86766e234EbF1eBe33444443b98a3
// BSC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98
// OEC: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF
// LOCAL: e7f1725E7734CE288F8367e1Bb143E90bb3F0512
// LOCAL2: 95D7fF1684a8F2e202097F28Dc2e56F773A55D02
// POLYGON: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f
// AVAX: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58
// FTM: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF
// ARB: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF
// ARB_DEV: eDC3a1C195591968488cA2E41E54d5Ac6c8016e2
// OP: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a
// CRO: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF
// CFX: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a
// POLYZK 1b5d39419C268b76Db06DE49e38B010fbFB5e226
// MANTA 1b5d39419C268b76Db06DE49e38B010fbFB5e226
// METIS 1b5d39419C268b76Db06DE49e38B010fbFB5e226
address public constant APPROVE_PROXY = 0x70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58;
// ETH: 5703B683c7F928b721CA95Da988d73a3299d4757
// BSC: 0B5f474ad0e3f7ef629BD10dbf9e4a8Fd60d9A48
// OEC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98
// LOCAL: D49a0e9A4CD5979aE36840f542D2d7f02C4817Be
// LOCAL2: 11457D5b1025D162F3d9B7dBeab6E1fBca20e043
// POLYGON: f332761c673b59B21fF6dfa8adA44d78c12dEF09
// AVAX: 3B86917369B83a6892f553609F3c2F439C184e31
// FTM: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f
// ARB: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98
// ARB_DEV: C183cFF4aC3B6D2b9405D856143C35a36E4C8710
// OP: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f
// CRO: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f
// CFX: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f
// POLYZK d2F0aC2012C8433F235c8e5e97F2368197DD06C7
// MANTA d2F0aC2012C8433F235c8e5e97F2368197DD06C7
// METIS d2F0aC2012C8433F235c8e5e97F2368197DD06C7
address public constant WNATIVE_RELAY = 0x5703B683c7F928b721CA95Da988d73a3299d4757;
// sysRatio
uint256 public constant GAS_TOKEN_RECEIVE_MAX_INDEX = 1;
uint256 public constant CLAIM_TOKEN_RATIO_MAX_INDEX = 2;
uint256 public constant CHAIN_ID_INDEX = 3;
// sysAddressConfig
// uint256 public constant ORACLE_ADDRESS_INDEX = 1; // deprecated
uint256 public constant DEFAULT_RATIO_BASE = 100;
uint256 public constant ADAPTER_ID_ANYSWAP = 1;
uint256 public constant ADAPTER_ID_CBRIDGE = 2;
uint256 public constant ADAPTER_ID_SWFT = 3;
string public constant __REFUND__ = string("__refund__");
}
CommissionLib.sol 21 lines
/// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
abstract contract CommissionLib {
/**
* commissionInfo uint256
* commissionInfo = flag + commissionRate + referrerAddress
* [ 48 bits | 48 bits | 160 bits ]
* [ flag | commissionRate | referrerAddress ]
* [ MSB LSB ]
*/
uint256 internal constant _REFERRER_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff;
uint256 internal constant _COMMISSION_FEE_MASK = 0x000000000000ffffffffffff0000000000000000000000000000000000000000;
uint256 internal constant _COMMISSION_FLAG_MASK = 0xffffffffffff0000000000000000000000000000000000000000000000000000;
uint256 internal constant OKX_COMMISSION = 0x3ca20afc2aaa0000000000000000000000000000000000000000000000000000;
event CommissionRecord(uint256 commissionAmount, address referrerAddress);
// set default vaule. can change when need.
uint256 public constant commissionRateLimit = 300;
}
IApproveProxy.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IApproveProxy {
function owner() external view returns (address);
function isAllowedProxy(address _proxy) external view returns (bool);
function claimTokens(
address token,
address who,
address dest,
uint256 amount
) external;
function tokenApprove() external view returns (address);
function addProxy(address _newProxy) external;
}
BridgeAdaptorBase.sol 99 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;
import "../helpers/Constants.sol";
import "../helpers/Errors.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/// @title BridgeAdaptorBase
/// @notice All Bridge adaptor must implement it
/// @dev All Bridge adaptor must implement it
abstract contract BridgeAdaptorBase is Ownable {
using SafeERC20 for IERC20;
address public immutable xBridge;
mapping(address => bool) public routers;
constructor(address _xBridge, address[] memory _routersList) {
require(_xBridge != address(0), XBridgeErrors.ADDRESS_0);
xBridge = _xBridge;
for (uint256 i = 0; i < _routersList.length; i++) {
routers[_routersList[i]] = true;
}
}
//-------------------------------
//------- Events ----------------
//-------------------------------
event LogOutboundBridgeTo(address _from, address _to, address _token, uint256 _amount, bytes32 _extraData);
event EmergencyWithdraw(address indexed _to, address _token, uint amount);
//-------------------------------
//------- Modifier --------------
//-------------------------------
modifier onlyXBridge() {
require(msg.sender == xBridge, XBridgeErrors.ONLY_X_BRIDGE);
_;
}
//-------------------------------
//------- Internal Functions ----
//-------------------------------
function _approve(address token, address spender, uint256 amount) internal {
if (IERC20(token).allowance(address(this), spender) == 0) {
IERC20(token).safeApprove(spender, amount);
} else {
IERC20(token).safeApprove(spender, 0);
IERC20(token).safeApprove(spender, amount);
}
}
function _approve2(address token, address spender, uint256 amount) internal {
uint256 preAllowance = IERC20(token).allowance(address(this), spender);
if (preAllowance == 0) {
IERC20(token).safeApprove(spender, type(uint256).max);
} else if (preAllowance < amount){
IERC20(token).safeApprove(spender, 0);
IERC20(token).safeApprove(spender, type(uint256).max);
}
}
//-------------------------------
//------- Admin functions -------
//-------------------------------
function setRouters(address[] calldata _routersList, bool[] calldata _v) public onlyOwner {
for (uint256 i = 0; i < _routersList.length; i++) {
routers[_routersList[i]] = _v[i];
}
}
// workaround for a possible solidity bug
function withdrawEmergency(address _to, address _token, uint _amount) public onlyOwner {
if (_token == XBridgeConstants.NATIVE_TOKEN) {
payable(_to).transfer(_amount);
} else {
IERC20(_token).safeTransfer(_to, _amount);
}
emit EmergencyWithdraw(_to, _token, _amount);
}
//-------------------------------
//------- Users Functions -------
//-------------------------------
function outboundBridgeTo(
address _from,
address _to,
address _refundAddress,
address _token,
uint256 _amount,
uint256 _toChainId,
bytes memory _data
) external payable virtual;
receive() external payable {}
}
IDaiLikePermit.sol 16 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Interface for DAI-style permits
interface IDaiLikePermit {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
IWNativeRelayer.sol 9 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;
interface IWNativeRelayer {
function owner() external view returns (address);
function withdraw(uint256 _amount) external;
function setCallerOk(address[] calldata whitelistedCallers, bool isOk) external;
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
Ownable.sol 83 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
RevertReasonParser.sol 84 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Library that allows to parse unsuccessful arbitrary calls revert reasons.
/// See https://solidity.readthedocs.io/en/latest/control-structures.html#revert for details.
/// Note that we assume revert reason being abi-encoded as Error(string) so it may fail to parse reason
/// if structured reverts appear in the future.
///
/// All unsuccessful parsings get encoded as Unknown(data) string
library RevertReasonParser {
bytes4 private constant _PANIC_SELECTOR =
bytes4(keccak256("Panic(uint256)"));
bytes4 private constant _ERROR_SELECTOR =
bytes4(keccak256("Error(string)"));
function parse(bytes memory data, string memory prefix)
internal
pure
returns (string memory)
{
if (data.length >= 4) {
bytes4 selector;
assembly {
// solhint-disable-line no-inline-assembly
selector := mload(add(data, 0x20))
}
// 68 = 4-byte selector + 32 bytes offset + 32 bytes length
if (selector == _ERROR_SELECTOR && data.length >= 68) {
uint256 offset;
bytes memory reason;
// solhint-disable no-inline-assembly
assembly {
// 36 = 32 bytes data length + 4-byte selector
offset := mload(add(data, 36))
reason := add(data, add(36, offset))
}
/*
revert reason is padded up to 32 bytes with ABI encoder: Error(string)
also sometimes there is extra 32 bytes of zeros padded in the end:
https://github.com/ethereum/solidity/issues/10170
because of that we can't check for equality and instead check
that offset + string length + extra 36 bytes is less than overall data length
*/
require(
data.length >= 36 + offset + reason.length,
"Invalid revert reason"
);
return string(abi.encodePacked(prefix, "Error(", reason, ")"));
}
// 36 = 4-byte selector + 32 bytes integer
else if (selector == _PANIC_SELECTOR && data.length == 36) {
uint256 code;
// solhint-disable no-inline-assembly
assembly {
// 36 = 32 bytes data length + 4-byte selector
code := mload(add(data, 36))
}
return
string(
abi.encodePacked(prefix, "Panic(", _toHex(code), ")")
);
}
}
return string(abi.encodePacked(prefix, "Unknown(", _toHex(data), ")"));
}
function _toHex(uint256 value) private pure returns (string memory) {
return _toHex(abi.encodePacked(value));
}
function _toHex(bytes memory data) private pure returns (string memory) {
bytes16 alphabet = 0x30313233343536373839616263646566;
bytes memory str = new bytes(2 + data.length * 2);
str[0] = "0";
str[1] = "x";
for (uint256 i = 0; i < data.length; i++) {
str[2 * i + 2] = alphabet[uint8(data[i] >> 4)];
str[2 * i + 3] = alphabet[uint8(data[i] & 0x0f)];
}
return string(str);
}
}
IERC20.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}
SafeERC20.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
IERC20Permit.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
AddressUpgradeable.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
ContextUpgradeable.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
OwnableUpgradeable.sol 95 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
Initializable.sol 166 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
PausableUpgradeable.sol 117 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
IERC20Upgradeable.sol 78 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}
draft-IERC20Permit.sol 8 lines
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; // EIP-2612 is Final as of 2022-11-01. This file is deprecated. import "./IERC20Permit.sol";
ReentrancyGuardUpgradeable.sol 89 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
SafeERC20Upgradeable.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));
}
}
IERC20PermitUpgradeable.sol 60 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
Read Contract
accessSelectorId 0x59605679 → bool
adaptorInfo 0xcea8ef5c → address
admin 0xf851a440 → address
approveProxy 0xf3dced3c → address
commissionRateLimit 0xca68d8f6 → uint256
dexRouter 0x0758d924 → address
feeTo 0x017e7e58 → address
mpc 0x81a52222 → bool
owner 0x8da5cb5b → address
paidTx 0xaeee23c4 → bool
paused 0x5c975abb → bool
payer 0x123119cd → address
payerReceiver 0x534015b3 → address, address
proxies 0xc4552791 → bool
receiveGasTx 0xbe75ddac → bool
receiver 0xf7260d3e → address
sysAddressConfig 0x7ae729ca → address
sysRatio 0xb796af13 → uint256
thresholdConfig 0xc1a8e6fd → bool, uint256
Write Contract 19 functions
These functions modify contract state and require a wallet transaction to execute.
bridgeToV2 0x9c81540c
tuple _request
claim 0x567ead0f
tuple _request
doBatch 0x773c30f0
tuple[] _gasRequest
tuple[] _claimRequest
initialize 0x8129fc1c
No parameters
pause 0x8456cb59
No parameters
receiveGasToken 0xb773ed3e
tuple _request
renounceOwnership 0x715018a6
No parameters
setAccessSelectorId 0xe2587da1
bytes4[] selectorIds
bool[] values
setAdaptors 0xaa0bd4de
uint256[] _ids
address[] _adaptors
setAdmin 0x704b6c02
address _newAdmin
setDexRouter 0xf72f863b
address _newDexRouter
setFeeTo 0xf46901ed
address _newFeeTo
setMpc 0x001a9f62
address[] _mpcList
bool[] _v
setProxies 0xadc927af
address[] proxiesList
bool[] values
setSysRatio 0xbb8c17d3
uint256 _index
uint256 _v
swapBridgeToV2 0xa8e1392e
tuple _request
swapBridgeToWithPermit 0x24286e28
tuple _request
bytes _signature
transferOwnership 0xf2fde38b
address newOwner
unpause 0x3f4ba83a
No parameters
Recent Transactions
This address has 1 on-chain transactions, but only 1.6% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →