Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x5ba073f65C751F419BF880d57Cf51289CbDb55fE
Balance 0 ETH
Nonce 1
Code Size 23906 bytes
Indexed Transactions 0 (1 on-chain, 1.6% indexed)
External Etherscan · Sourcify

Contract Bytecode

23906 bytes
Copy Bytecode
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 →