Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x6406DF225a87D7ec187E11044257FEc2Ca0a354C
Balance 0 ETH
Nonce 1
Code Size 11430 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

11430 bytes
0x60806040526004361061010d5760003560e01c80637412099f1161009557806395d89b411161006457806395d89b41146102d6578063a7a76cd4146102eb578063a8dc486b1461030b578063d9caed121461031e578063f2fde38b1461033e57600080fd5b80637412099f146102585780638705fcd414610278578063885b2ed8146102985780638da5cb5b146102b857600080fd5b8063429f879e116100dc578063429f879e146101dd5780634782f779146101f0578063548ed52a146102105780636f2f265c14610223578063715018a61461024357600080fd5b806306fdde03146101195780630adba875146101445780631fd88cd41461016657806341275358146101a557600080fd5b3661011457005b600080fd5b34801561012557600080fd5b5061012e61035e565b60405161013b91906123e4565b60405180910390f35b34801561015057600080fd5b5061016461015f366004612417565b6103ec565b005b34801561017257600080fd5b50610186610181366004612417565b610496565b604080516001600160a01b03909316835290151560208301520161013b565b3480156101b157600080fd5b506002546101c5906001600160a01b031681565b6040516001600160a01b03909116815260200161013b565b6101646101eb36600461251f565b6104cb565b3480156101fc57600080fd5b5061016461020b3660046125b0565b61084b565b61016461021e3660046125dc565b610900565b34801561022f57600080fd5b5061018661023e366004612417565b610f94565b34801561024f57600080fd5b50610164610fa4565b34801561026457600080fd5b5061016461027336600461261b565b610fda565b34801561028457600080fd5b50610164610293366004612633565b6110ff565b3480156102a457600080fd5b506101646102b3366004612417565b611177565b3480156102c457600080fd5b506000546001600160a01b03166101c5565b3480156102e257600080fd5b5061012e61120d565b3480156102f757600080fd5b5061016461030636600461261b565b61121a565b610164610319366004612657565b611310565b34801561032a57600080fd5b50610164610339366004612696565b61177c565b34801561034a57600080fd5b50610164610359366004612633565b611842565b6003805461036b906126d7565b80601f0160208091040260200160405190810160405280929190818152602001828054610397906126d7565b80156103e45780601f106103b9576101008083540402835291602001916103e4565b820191906000526020600020905b8154815290600101906020018083116103c757829003601f168201915b505050505081565b6000546001600160a01b0316331461041f5760405162461bcd60e51b81526004016104169061270c565b60405180910390fd5b60006005828154811061043457610434612741565b60009182526020909120018054911515600160a01b0260ff60a01b199092169190911790556040517fdd4de8f8907f60a0546026e914631c75af904f1082b308514d18f270696ddbaa9061048b9083815260200190565b60405180910390a150565b600581815481106104a657600080fd5b6000918252602090912001546001600160a01b0381169150600160a01b900460ff1682565b8160800135428110156104f05760405162461bcd60e51b815260040161041690612757565b600260015414156105135760405162461bcd60e51b81526004016104169061277e565b600260015561053b8261053561053061052b87612824565b6118dd565b6119c7565b90611a1b565b6001600160a01b03166105566000546001600160a01b031690565b6001600160a01b0316146040518060400160405280601e81526020017f43414c4c5f444154415f4d5553545f5349474e45445f42595f4f574e45520000815250906105b45760405162461bcd60e51b815260040161041691906123e4565b5060006105c46020850185612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c31833981519152815250906106115760405162461bcd60e51b815260040161041691906123e4565b50604080518082018252600b81526a1253959053125117d0535560aa1b6020820152908401356106545760405162461bcd60e51b815260040161041691906123e4565b50600061066460608501856128ba565b610675906060810190604001612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c31833981519152815250906106c25760405162461bcd60e51b815260040161041691906123e4565b50600060066106d460608601866128ba565b60000135815481106106e8576106e8612741565b6000918252602091829020604080518082019091529101546001600160a01b038116808352600160a01b90910460ff16151592820192909252915015801590610732575080602001515b6040518060400160405280600f81526020016e11115617d393d517d0531313d5d151608a1b815250906107785760405162461bcd60e51b815260040161041691906123e4565b5080516001600160a01b0316638f979a64343361079860608901896128ba565b6107a9906060810190604001612633565b60408901356107bb60208b018b612633565b60208b01356107cd60608d018d6128ba565b6107db9060608101906128da565b6002546040516001600160e01b031960e08c901b16815261080f98979695949392916001600160a01b03169060040161294a565b6000604051808303818588803b15801561082857600080fd5b505af115801561083c573d6000803e3d6000fd5b50506001805550505050505050565b6000546001600160a01b031633146108755760405162461bcd60e51b81526004016104169061270c565b6040805180820190915260128152600080516020612c3183398151915260208201526001600160a01b0383166108be5760405162461bcd60e51b815260040161041691906123e4565b506108c98282611a3f565b6040518181527f94effa14ea3a1ef396fa2fd829336d1597f1d76b548c26bfa2332869706638af9060200160405180910390a15050565b8160a00135428110156109255760405162461bcd60e51b815260040161041690612757565b600260015414156109485760405162461bcd60e51b81526004016104169061277e565b600260015561096582610535610530610960876129a1565b611b0d565b6001600160a01b03166109806000546001600160a01b031690565b6001600160a01b0316146040518060400160405280601e81526020017f43414c4c5f444154415f4d5553545f5349474e45445f42595f4f574e45520000815250906109de5760405162461bcd60e51b815260040161041691906123e4565b5060006109ee6020850185612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c3183398151915281525090610a3b5760405162461bcd60e51b815260040161041691906123e4565b50604080518082018252600b81526a1253959053125117d0535560aa1b602082015290840135610a7e5760405162461bcd60e51b815260040161041691906123e4565b506000610a8e60608501856128ba565b610a9f906060810190604001612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c3183398151915281525090610aec5760405162461bcd60e51b815260040161041691906123e4565b506000610afc60808501856128ba565b610b0d906060810190604001612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c3183398151915281525090610b5a5760405162461bcd60e51b815260040161041691906123e4565b5060006005610b6c60608601866128ba565b6000013581548110610b8057610b80612741565b6000918252602091829020604080518082019091529101546001600160a01b038116808352600160a01b90910460ff16151592820192909252915015801590610bca575080602001515b6040518060400160405280600f81526020016e11115617d393d517d0531313d5d151608a1b81525090610c105760405162461bcd60e51b815260040161041691906123e4565b5060006006610c2260808701876128ba565b6000013581548110610c3657610c36612741565b6000918252602091829020604080518082019091529101546001600160a01b038116808352600160a01b90910460ff16151592820192909252915015801590610c80575080602001515b6040518060400160405280600f81526020016e11115617d393d517d0531313d5d151608a1b81525090610cc65760405162461bcd60e51b815260040161041691906123e4565b50600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee610ceb60608801886128ba565b610cfc906060810190604001612633565b6001600160a01b031614610d2057610d1760608701876128ba565b60200135610d3f565b610d2d60608701876128ba565b610d3f90602001356040880135612a3e565b83519091506000906001600160a01b031663c6cddf748333610d6460608c018c6128ba565b610d75906060810190604001612633565b60408c013530610d8860608f018f6128ba565b610d969060608101906128da565b6002546040516001600160e01b031960e08b901b168152610dc9979695949392916001600160a01b031690600401612a64565b6020604051808303818588803b158015610de257600080fd5b505af1158015610df6573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610e1b9190612ab4565b90506000610e2c60808901896128ba565b60200135905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee610e5460808a018a6128ba565b610e65906060810190604001612633565b6001600160a01b031614610ea157610e9c610e8360808a018a6128ba565b610e94906060810190604001612633565b855184611c39565b610ebf565b610eae60808901896128ba565b610ebc906020013583612a3e565b90505b83516001600160a01b0316638f979a648230610ede60808d018d6128ba565b610eef906060810190604001612633565b86610efd60208f018f612633565b8e602001358f8060800190610f1291906128ba565b610f209060608101906128da565b6002546040516001600160e01b031960e08c901b168152610f5498979695949392916001600160a01b03169060040161294a565b6000604051808303818588803b158015610f6d57600080fd5b505af1158015610f81573d6000803e3d6000fd5b5050600180555050505050505050505050565b600681815481106104a657600080fd5b6000546001600160a01b03163314610fce5760405162461bcd60e51b81526004016104169061270c565b610fd86000611d54565b565b6000546001600160a01b031633146110045760405162461bcd60e51b81526004016104169061270c565b60006110136020830183612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c31833981519152815250906110605760405162461bcd60e51b815260040161041691906123e4565b506005805460018101825560009190915281907f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00161109f8282612adb565b507f8c437f741c3da970572d5d28cfa8138b39c125ac34f8b1bfa2c5ca0dfb7e29db90506110d06020830183612633565b6110e06040840160208501612b34565b604080516001600160a01b03909316835290151560208301520161048b565b6000546001600160a01b031633146111295760405162461bcd60e51b81526004016104169061270c565b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527ffcb8a963756b148f85a52537b63147b6c4b40af694099c901ac3b99d317a2db89060200161048b565b6000546001600160a01b031633146111a15760405162461bcd60e51b81526004016104169061270c565b6000600682815481106111b6576111b6612741565b60009182526020909120018054911515600160a01b0260ff60a01b199092169190911790556040517fd2a4684924a53b2f62da8c5929cb5eca6b719236bea99d917312d7219a1726489061048b9083815260200190565b6004805461036b906126d7565b6000546001600160a01b031633146112445760405162461bcd60e51b81526004016104169061270c565b60006112536020830183612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c31833981519152815250906112a05760405162461bcd60e51b815260040161041691906123e4565b506006805460018101825560009190915281907ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f016112df8282612adb565b507f38b23b225157207db1570815b751a9ebd0b36b2fd1b307aac57e54a2c277a4cf90506110d06020830183612633565b8160600135428110156113355760405162461bcd60e51b815260040161041690612757565b600260015414156113585760405162461bcd60e51b81526004016104169061277e565b60026001556113758261053561053061137087612b51565b611da4565b6001600160a01b03166113906000546001600160a01b031690565b6001600160a01b0316146040518060400160405280601e81526020017f43414c4c5f444154415f4d5553545f5349474e45445f42595f4f574e45520000815250906113ee5760405162461bcd60e51b815260040161041691906123e4565b5060006113fe6020850185612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c318339815191528152509061144b5760405162461bcd60e51b815260040161041691906123e4565b508260200135600014156040518060400160405280600b81526020016a1253959053125117d0535560aa1b815250906114975760405162461bcd60e51b815260040161041691906123e4565b5060006114a760408501856128ba565b6114b8906060810190604001612633565b6001600160a01b03161415604051806040016040528060128152602001600080516020612c31833981519152815250906115055760405162461bcd60e51b815260040161041691906123e4565b506000600561151760408601866128ba565b600001358154811061152b5761152b612741565b6000918252602091829020604080518082019091529101546001600160a01b038116808352600160a01b90910460ff16151592820192909252915015801590611575575080602001515b6040518060400160405280600f81526020016e11115617d393d517d0531313d5d151608a1b815250906115bb5760405162461bcd60e51b815260040161041691906123e4565b50600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6115e060408701876128ba565b6115f1906060810190604001612633565b6001600160a01b0316146116155761160c60408601866128ba565b60200135611635565b61162260408601866128ba565b6020013585602001356116359190612a3e565b90508034146040518060400160405280601981526020017f56414c55455f4e4f545f455155414c5f544f5f414d4f554e54000000000000008152509061168e5760405162461bcd60e51b815260040161041691906123e4565b5081516001600160a01b031663c6cddf7482336116ae60408a018a6128ba565b6116bf906060810190604001612633565b60208a018035906116d0908c612633565b6116dd60408d018d6128ba565b6116eb9060608101906128da565b6002546040516001600160e01b031960e08b901b16815261171e979695949392916001600160a01b031690600401612a64565b6020604051808303818588803b15801561173757600080fd5b505af115801561174b573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906117709190612ab4565b50506001805550505050565b6000546001600160a01b031633146117a65760405162461bcd60e51b81526004016104169061270c565b6040805180820190915260128152600080516020612c3183398151915260208201526001600160a01b0383166117ef5760405162461bcd60e51b815260040161041691906123e4565b506117fb838383611e66565b604080516001600160a01b0385168152602081018390527f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364910160405180910390a1505050565b6000546001600160a01b0316331461186c5760405162461bcd60e51b81526004016104169061270c565b6001600160a01b0381166118d15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610416565b6118da81611d54565b50565b805160208083015160408085015160608087015180518187015182860151929093015180519088012094516000987f9e93f730da056ae2d949820c6e44c75510a74da28e0b4320740334619e9c0f619890979661194e95600080516020612c51833981519152959093909201612bbf565b6040516020818303038152906040528051906020012086608001516040516020016119aa969594939291909586526001600160a01b0394909416602086015260408501929092526060840152608083015260a082015260c00190565b604051602081830303815290604052805190602001209050919050565b6000611a156119d4611f7a565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b92915050565b6000806000611a2a858561206d565b91509150611a37816120dd565b509392505050565b604080516000808252602082019092526001600160a01b038416908390604051611a699190612beb565b60006040518083038185875af1925050503d8060008114611aa6576040519150601f19603f3d011682016040523d82523d6000602084013e611aab565b606091505b5050905080611b085760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610416565b505050565b805160208083015160408085015160608087015180518187015182860151929093015180519088012094516000987f90d478e410f4f47431c1d516c26f6d287680c2bea038eb89067a9d71fb67499798909796611b7e95600080516020612c51833981519152959093909201612bbf565b60408051601f19818403018152828252805160209182012060808a0151805181840151948201516060909201518051908501209295611bd495600080516020612c51833981519152959294909392909101612bbf565b604051602081830303815290604052805190602001208760a001516040516020016119aa97969594939291909687526001600160a01b0395909516602087015260408601939093526060850191909152608084015260a083015260c082015260e00190565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b1790529151600092839290871691611c959190612beb565b6000604051808303816000865af19150503d8060008114611cd2576040519150601f19603f3d011682016040523d82523d6000602084013e611cd7565b606091505b5091509150818015611d01575080511580611d01575080806020019051810190611d019190612bfd565b611d4d5760405162461bcd60e51b815260206004820152601e60248201527f5472616e7366657248656c7065723a20415050524f56455f4641494c454400006044820152606401610416565b5050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516020808301516040808501518051818501518284015160609093015180519087012093516000977f216a63d6bc40952ad2032dfdb62c4ef952ccfea5acb75529010137d42b8594e297909695611e1095600080516020612c51833981519152959493909201612bbf565b6040516020818303038152906040528051906020012085606001516040516020016119aa9594939291909485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611ec29190612beb565b6000604051808303816000865af19150503d8060008114611eff576040519150601f19603f3d011682016040523d82523d6000602084013e611f04565b606091505b5091509150818015611f2e575080511580611f2e575080806020019051810190611f2e9190612bfd565b611d4d5760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610416565b60007f0000000000000000000000000000000000000000000000000000000000000001461415611fc957507f3d48431cb125b1e42e438e63479da7d2c7a96d7e5cb9dd0d4816fb6cc08d604890565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f7e5b6f0a61b79f433a02e1f081f25a7d6f688bc324f39182f3442568d6db3b1b828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000808251604114156120a45760208301516040840151606085015160001a61209887828585612298565b945094505050506120d6565b8251604014156120ce57602083015160408401516120c3868383612385565b9350935050506120d6565b506000905060025b9250929050565b60008160048111156120f1576120f1612c1a565b14156120fa5750565b600181600481111561210e5761210e612c1a565b141561215c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610416565b600281600481111561217057612170612c1a565b14156121be5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610416565b60038160048111156121d2576121d2612c1a565b141561222b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610416565b600481600481111561223f5761223f612c1a565b14156118da5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610416565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156122cf575060009050600361237c565b8460ff16601b141580156122e757508460ff16601c14155b156122f8575060009050600461237c565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561234c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166123755760006001925092505061237c565b9150600090505b94509492505050565b6000806001600160ff1b03831660ff84901c601b016123a687828885612298565b935093505050935093915050565b60005b838110156123cf5781810151838201526020016123b7565b838111156123de576000848401525b50505050565b60208152600082518060208401526124038160408501602087016123b4565b601f01601f19169190910160400192915050565b60006020828403121561242957600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff8111828210171561246957612469612430565b60405290565b60405160c0810167ffffffffffffffff8111828210171561246957612469612430565b600082601f8301126124a357600080fd5b813567ffffffffffffffff808211156124be576124be612430565b604051601f8301601f19908116603f011681019082821181831017156124e6576124e6612430565b816040528381528660208588010111156124ff57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561253257600080fd5b823567ffffffffffffffff8082111561254a57600080fd5b9084019060a0828703121561255e57600080fd5b9092506020840135908082111561257457600080fd5b5061258185828601612492565b9150509250929050565b6001600160a01b03811681146118da57600080fd5b80356125ab8161258b565b919050565b600080604083850312156125c357600080fd5b82356125ce8161258b565b946020939093013593505050565b600080604083850312156125ef57600080fd5b823567ffffffffffffffff8082111561260757600080fd5b9084019060c0828703121561255e57600080fd5b60006040828403121561262d57600080fd5b50919050565b60006020828403121561264557600080fd5b81356126508161258b565b9392505050565b6000806040838503121561266a57600080fd5b823567ffffffffffffffff8082111561268257600080fd5b908401906080828703121561255e57600080fd5b6000806000606084860312156126ab57600080fd5b83356126b68161258b565b925060208401356126c68161258b565b929592945050506040919091013590565b600181811c908216806126eb57607f821691505b6020821081141561262d57634e487b7160e01b600052602260045260246000fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6020808252600d908201526c11db1d594e8811561412549151609a1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000608082840312156127c757600080fd5b6127cf612446565b9050813581526020820135602082015260408201356127ed8161258b565b6040820152606082013567ffffffffffffffff81111561280c57600080fd5b61281884828501612492565b60608301525092915050565b600060a0823603121561283657600080fd5b60405160a0810167ffffffffffffffff828210818311171561285a5761285a612430565b816040528435915061286b8261258b565b8183526020850135602084015260408501356040840152606085013591508082111561289657600080fd5b506128a3368286016127b5565b606083015250608092830135928101929092525090565b60008235607e198336030181126128d057600080fd5b9190910192915050565b6000808335601e198436030181126128f157600080fd5b83018035915067ffffffffffffffff82111561290c57600080fd5b6020019150368190038213156120d657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600060018060a01b03808b168352808a166020840152886040840152808816606084015286608084015260e060a084015261298960e084018688612921565b915080841660c0840152509998505050505050505050565b600060c082360312156129b357600080fd5b6129bb61246f565b6129c4836125a0565b81526020830135602082015260408301356040820152606083013567ffffffffffffffff808211156129f557600080fd5b612a01368387016127b5565b60608401526080850135915080821115612a1a57600080fd5b50612a27368286016127b5565b60808301525060a092830135928101929092525090565b60008219821115612a5f57634e487b7160e01b600052601160045260246000fd5b500190565b600060018060a01b03808a1683528089166020840152876040840152808716606084015260c06080840152612a9d60c084018688612921565b915080841660a08401525098975050505050505050565b600060208284031215612ac657600080fd5b5051919050565b80151581146118da57600080fd5b8135612ae68161258b565b81546001600160a01b031981166001600160a01b039290921691821783556020840135612b1281612acd565b6001600160a81b03199190911690911790151560a01b60ff60a01b1617905550565b600060208284031215612b4657600080fd5b813561265081612acd565b600060808236031215612b6357600080fd5b612b6b612446565b8235612b768161258b565b815260208381013590820152604083013567ffffffffffffffff811115612b9c57600080fd5b612ba8368286016127b5565b604083015250606092830135928101929092525090565b948552602085019390935260408401919091526001600160a01b03166060830152608082015260a00190565b600082516128d08184602087016123b4565b600060208284031215612c0f57600080fd5b815161265081612acd565b634e487b7160e01b600052602160045260246000fdfe414444524553535f305f50524f56494445440000000000000000000000000000206bff3ac05c2e5e1d980b06745bf09ad11b9dd8f0fa7aced4b346af5d9470bfa264697066735822122064f24e48be0048f972c88bd70d4a50114a0ef5b0f82f6e825b1a4bc5d975f5f064736f6c63430008090033

Verified Source Code Partial Match

Compiler: v0.8.9+commit.e5eed63a EVM: london Optimization: Yes (200 runs)
SwapBase.sol 45 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./helpers/Errors.sol";
import "./helpers/TransferHelper.sol";


abstract contract SwapBase is Ownable {
    address public immutable router;

    constructor(address _router) Ownable() {
        router = _router;
    }

    event WithdrawETH(uint256 amount);

    event Withdraw(address token, uint256 amount);

    modifier onlyRouter {
        require(msg.sender == router, Errors.INVALID_SENDER);
        _;
    }

    function swap(
        address _fromAddress,
        address _fromToken,
        uint256 _amount,
        address _receiverAddress,
        bytes memory _extraData,
        address feeAddress
    ) external payable virtual returns (uint256);

    function withdraw(address _token, address _receiverAddress, uint256 _amount) external onlyOwner {
        require(_receiverAddress != address(0), Errors.ADDRESS_0_PROVIDED);
        TransferHelper.safeTransfer(_token, _receiverAddress, _amount);
        emit Withdraw(_token, _amount);
    }

    function withdrawETH(address _receiverAddress, uint256 _amount) external onlyOwner {
        require(_receiverAddress != address(0), Errors.ADDRESS_0_PROVIDED);
        TransferHelper.safeTransferETH(_receiverAddress, _amount);
        emit WithdrawETH(_amount);
    }
}
BridgeBase.sol 57 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./helpers/Errors.sol";
import "./helpers/TransferHelper.sol";


abstract contract BridgeBase is Ownable {
    address public router;
    address public constant NATIVE_TOKEN_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
    

    constructor(address _router) Ownable() {
        router = _router;
    }

    event UpdateRouterAddress(address indexed routerAddress);

    event WithdrawETH(uint256 amount);

    event Withdraw(address token, uint256 amount);

    modifier onlyRouter() {
        require(msg.sender == router, Errors.INVALID_SENDER);
        _;
    }

    function updateRouterAddress(address newRouter) external onlyOwner {
        router = newRouter;
        emit UpdateRouterAddress(newRouter);
    }

    function bridge(
        address _fromAddress,
        address _fromToken,
        uint256 _amount,
        address _receiverAddress,
        uint256 _toChainId,
        bytes memory _extraData,
        address feeAddress
    ) external payable virtual;


    function withdraw(address _token, address _receiverAddress, uint256 _amount) external onlyOwner {
        require(_receiverAddress != address(0), Errors.ADDRESS_0_PROVIDED);
        TransferHelper.safeTransfer(_token, _receiverAddress, _amount);
        emit Withdraw(_token, _amount);
    }

    function withdrawETH(address _receiverAddress, uint256 _amount) external onlyOwner {
        require(_receiverAddress != address(0), Errors.ADDRESS_0_PROVIDED);
        TransferHelper.safeTransferETH(_receiverAddress, _amount);
        emit WithdrawETH(_amount);
    }

}
GlueRouter.sol 359 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import "./helpers/Errors.sol";
import "./helpers/TransferHelper.sol";
import "./BridgeBase.sol";
import "./SwapBase.sol";

contract GlueRouter is Ownable, ReentrancyGuard, EIP712 {
    using ECDSA for bytes32;
    address private constant NATIVE_TOKEN_ADDRESS =
        address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);

    address public feeAddress;
    string public name;
    string public symbol;

    string private constant SIGNING_DOMAIN = "Glue";
    string private constant SIGNATURE_VERSION = "1";

    constructor() EIP712(SIGNING_DOMAIN, SIGNATURE_VERSION) {
        name = "Glue Router";
        symbol = "GLUE";
    }


    modifier ensure(uint256 deadline) {
        require(deadline >= block.timestamp, "Glue: EXPIRED");
        _;
    }

    struct SwapBridgeDex {
        address dex;
        bool isEnabled;
    }

    SwapBridgeDex[] public swapDexs;
    SwapBridgeDex[] public bridgeDexs;

    receive() external payable {}

    event NewSwapDexAdded(address dex, bool isEnabled);
    event NewBridgeDexAdded(address dex, bool isEnabled);
    event SwapDexDisabled(uint256 dexID);
    event BridgeDexDisabled(uint256 dexID);
    event SetFeeAddress(address feeAddress);
    event WithdrawETH(uint256 amount);
    event Withdraw(address token, uint256 amount);
    
    struct SwapBridgeRequest {
        uint256 id;
        uint256 nativeAmount;
        address inputToken;
        bytes data;
    }

    // **** USER REQUEST ****
    struct UserSwapRequest {
        address receiverAddress;
        uint256 amount;
        SwapBridgeRequest swapRequest;
        uint256 deadline;
    }

    struct UserBridgeRequest {
        address receiverAddress;
        uint256 toChainId;
        uint256 amount;
        SwapBridgeRequest bridgeRequest;
        uint256 deadline;
    }

    struct UserSwapBridgeRequest {
        address receiverAddress;
        uint256 toChainId;
        uint256 amount;
        SwapBridgeRequest swapRequest;
        SwapBridgeRequest bridgeRequest;
        uint256 deadline;
    }

    bytes32 private constant SWAP_REQUEST_TYPE =
        keccak256(
            "UserSwapRequest(address receiverAddress,uint256 amount,SwapBridgeRequest swapRequest,uint256 deadline)SwapBridgeRequest(uint256 id,uint256 nativeAmount,address inputToken,bytes data)"
        );
    bytes32 private constant BRIDGE_REQUEST_TYPE =
        keccak256(
            "UserBridgeRequest(address receiverAddress,uint256 toChainId,uint256 amount,SwapBridgeRequest bridgeRequest,uint256 deadline)SwapBridgeRequest(uint256 id,uint256 nativeAmount,address inputToken,bytes data)"
        );
    bytes32 private constant SWAP_AND_BRIDGE_REQUEST_TYPE =
        keccak256(
            "UserSwapBridgeRequest(address receiverAddress,uint256 toChainId,uint256 amount,SwapBridgeRequest swapRequest,SwapBridgeRequest bridgeRequest,uint256 deadline)SwapBridgeRequest(uint256 id,uint256 nativeAmount,address inputToken,bytes data)"
        );
    bytes32 private constant REQUEST_TYPE =
        keccak256(
            "SwapBridgeRequest(uint256 id,uint256 nativeAmount,address inputToken,bytes data)"
        );

    function _hashSwapRequest(UserSwapRequest memory _userRequest) private pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    SWAP_REQUEST_TYPE,
                    _userRequest.receiverAddress,
                    _userRequest.amount,
                    keccak256(abi.encode(REQUEST_TYPE, _userRequest.swapRequest.id, _userRequest.swapRequest.nativeAmount, _userRequest.swapRequest.inputToken, keccak256(_userRequest.swapRequest.data))),
                    _userRequest.deadline
                )
            );
    }
    function _hashBridgeRequest(UserBridgeRequest memory _userRequest) private pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    BRIDGE_REQUEST_TYPE,
                    _userRequest.receiverAddress,
                    _userRequest.toChainId,
                    _userRequest.amount,
                    keccak256(abi.encode(REQUEST_TYPE, _userRequest.bridgeRequest.id, _userRequest.bridgeRequest.nativeAmount, _userRequest.bridgeRequest.inputToken, keccak256(_userRequest.bridgeRequest.data))),
                    _userRequest.deadline
                )
            );
    }
    function _hashSwapAndBridgeRequest(UserSwapBridgeRequest memory _userRequest) private pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    SWAP_AND_BRIDGE_REQUEST_TYPE,
                    _userRequest.receiverAddress,
                    _userRequest.toChainId,
                    _userRequest.amount,
                    keccak256(abi.encode(REQUEST_TYPE, _userRequest.swapRequest.id, _userRequest.swapRequest.nativeAmount, _userRequest.swapRequest.inputToken, keccak256(_userRequest.swapRequest.data))),
                    keccak256(abi.encode(REQUEST_TYPE, _userRequest.bridgeRequest.id, _userRequest.bridgeRequest.nativeAmount, _userRequest.bridgeRequest.inputToken, keccak256(_userRequest.bridgeRequest.data))),
                    _userRequest.deadline
                )
            );
    }

    // **** SWAP ****
    function swap(UserSwapRequest calldata _userRequest, bytes memory _sign)
        external
        payable
        ensure(_userRequest.deadline)
        nonReentrant
    {
        require(
            owner() == _hashTypedDataV4(_hashSwapRequest(_userRequest)).recover(_sign),
            Errors.CALL_DATA_MUST_SIGNED_BY_OWNER
        );
        require(
            _userRequest.receiverAddress != address(0),
            Errors.ADDRESS_0_PROVIDED
        );
        require(_userRequest.amount != 0, Errors.INVALID_AMT);
        require(
            _userRequest.swapRequest.inputToken != address(0),
            Errors.ADDRESS_0_PROVIDED
        );

        SwapBridgeDex memory swapInfo = swapDexs[_userRequest.swapRequest.id];

        require(
            swapInfo.dex != address(0) && swapInfo.isEnabled,
            Errors.DEX_NOT_ALLOWED
        );
        uint256 nativeSwapAmount = _userRequest.swapRequest.inputToken ==
            NATIVE_TOKEN_ADDRESS
            ? _userRequest.amount + _userRequest.swapRequest.nativeAmount
            : _userRequest.swapRequest.nativeAmount;
        require(
            msg.value == nativeSwapAmount,
            Errors.VALUE_NOT_EQUAL_TO_AMOUNT
        );

        // swap
        SwapBase(swapInfo.dex).swap{value: nativeSwapAmount}(
            msg.sender,
            _userRequest.swapRequest.inputToken,
            _userRequest.amount,
            _userRequest.receiverAddress,
            _userRequest.swapRequest.data,
            feeAddress
        );
    }

    // **** BRIDGE ****
    function bridge(UserBridgeRequest calldata _userRequest, bytes memory _sign)
        external
        payable
        ensure(_userRequest.deadline)
        nonReentrant
    {
        require(
            owner() == _hashTypedDataV4(_hashBridgeRequest(_userRequest)).recover(_sign),
            Errors.CALL_DATA_MUST_SIGNED_BY_OWNER
        );
        require(
            _userRequest.receiverAddress != address(0),
            Errors.ADDRESS_0_PROVIDED
        );
        require(_userRequest.amount != 0, Errors.INVALID_AMT);
        require(
            _userRequest.bridgeRequest.inputToken != address(0),
            Errors.ADDRESS_0_PROVIDED
        );

        SwapBridgeDex memory bridgeInfo = bridgeDexs[
            _userRequest.bridgeRequest.id
        ];

        require(
            bridgeInfo.dex != address(0) && bridgeInfo.isEnabled,
            Errors.DEX_NOT_ALLOWED
        );

        // bridge
        BridgeBase(bridgeInfo.dex).bridge{value: msg.value}(
            msg.sender,
            _userRequest.bridgeRequest.inputToken,
            _userRequest.amount,
            _userRequest.receiverAddress,
            _userRequest.toChainId,
            _userRequest.bridgeRequest.data,
            feeAddress
        );
    }

    // **** SWAP AND BRIDGE ****
    function swapAndBridge(UserSwapBridgeRequest calldata _userRequest, bytes memory _sign)
        external
        payable
        ensure(_userRequest.deadline)
        nonReentrant
    {
        require(
            owner() == _hashTypedDataV4(_hashSwapAndBridgeRequest(_userRequest)).recover(_sign),
            Errors.CALL_DATA_MUST_SIGNED_BY_OWNER
        );
        require(
            _userRequest.receiverAddress != address(0),
            Errors.ADDRESS_0_PROVIDED
        );
        require(_userRequest.amount != 0, Errors.INVALID_AMT);

        require(
            _userRequest.swapRequest.inputToken != address(0),
            Errors.ADDRESS_0_PROVIDED
        );

        require(
            _userRequest.bridgeRequest.inputToken != address(0),
            Errors.ADDRESS_0_PROVIDED
        );

        SwapBridgeDex memory swapInfo = swapDexs[_userRequest.swapRequest.id];

        require(
            swapInfo.dex != address(0) && swapInfo.isEnabled,
            Errors.DEX_NOT_ALLOWED
        );

        SwapBridgeDex memory bridgeInfo = bridgeDexs[
            _userRequest.bridgeRequest.id
        ];
        require(
            bridgeInfo.dex != address(0) && bridgeInfo.isEnabled,
            Errors.DEX_NOT_ALLOWED
        );

        uint256 nativeSwapAmount = _userRequest.swapRequest.inputToken ==
            NATIVE_TOKEN_ADDRESS
            ? _userRequest.amount + _userRequest.swapRequest.nativeAmount
            : _userRequest.swapRequest.nativeAmount;
        uint256 _amountOut = SwapBase(swapInfo.dex).swap{
            value: nativeSwapAmount
        }(
            msg.sender,
            _userRequest.swapRequest.inputToken,
            _userRequest.amount,
            address(this),
            _userRequest.swapRequest.data,
            feeAddress
        );

        uint256 nativeInput = _userRequest.bridgeRequest.nativeAmount;

        if (_userRequest.bridgeRequest.inputToken != NATIVE_TOKEN_ADDRESS) {
            TransferHelper.safeApprove(
                _userRequest.bridgeRequest.inputToken,
                bridgeInfo.dex,
                _amountOut
            );
        } else {
            nativeInput = _amountOut + _userRequest.bridgeRequest.nativeAmount;
        }

        BridgeBase(bridgeInfo.dex).bridge{value: nativeInput}(
            address(this),
            _userRequest.bridgeRequest.inputToken,
            _amountOut,
            _userRequest.receiverAddress,
            _userRequest.toChainId,
            _userRequest.bridgeRequest.data,
            feeAddress
        );
    }

    // **** ONLY OWNER ****
    function addSwapDexs(SwapBridgeDex calldata _dex) external onlyOwner {
        require(_dex.dex != address(0), Errors.ADDRESS_0_PROVIDED);
        swapDexs.push(_dex);
        emit NewSwapDexAdded(_dex.dex, _dex.isEnabled);
    }

    function addBridgeDexs(SwapBridgeDex calldata _dex) external onlyOwner {
        require(_dex.dex != address(0), Errors.ADDRESS_0_PROVIDED);
        bridgeDexs.push(_dex);
        emit NewBridgeDexAdded(_dex.dex, _dex.isEnabled);
    }

    function disableSwapDex(uint256 _dexId) external onlyOwner {
        swapDexs[_dexId].isEnabled = false;
        emit SwapDexDisabled(_dexId);
    }

    function disableBridgeDex(uint256 _dexId) external onlyOwner {
        bridgeDexs[_dexId].isEnabled = false;
        emit BridgeDexDisabled(_dexId);
    }

    function setFeeAddress(address _newFeeAddress) external onlyOwner {
        feeAddress = _newFeeAddress;
        emit SetFeeAddress(_newFeeAddress);
    }

    function withdraw(
        address _token,
        address _receiverAddress,
        uint256 _amount
    ) external onlyOwner {
        require(_receiverAddress != address(0), Errors.ADDRESS_0_PROVIDED);
        TransferHelper.safeTransfer(_token, _receiverAddress, _amount);
        emit Withdraw(_token, _amount);
    }

    function withdrawETH(address _receiverAddress, uint256 _amount)
        external
        onlyOwner
    {
        require(_receiverAddress != address(0), Errors.ADDRESS_0_PROVIDED);
        TransferHelper.safeTransferETH(_receiverAddress, _amount);
        emit WithdrawETH(_amount);
    }
}
Errors.sol 20 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

library Errors {
    string internal constant ADDRESS_0_PROVIDED = "ADDRESS_0_PROVIDED";
    string internal constant DEX_NOT_ALLOWED = "DEX_NOT_ALLOWED";
    string internal constant TOKEN_NOT_SUPPORTED = "TOKEN_NOT_SUPPORTED";
    string internal constant SWAP_FAILED = "SWAP_FAILED";
    string internal constant VALUE_SHOULD_BE_ZERO = "VALUE_SHOULD_BE_ZERO";
    string internal constant VALUE_SHOULD_NOT_BE_ZERO = "VALUE_SHOULD_NOT_BE_ZERO";
    string internal constant VALUE_NOT_EQUAL_TO_AMOUNT = "VALUE_NOT_EQUAL_TO_AMOUNT";

    string internal constant INVALID_AMT = "INVALID_AMT";
    string internal constant INVALID_ADDRESS = "INVALID_ADDRESS";
    string internal constant INVALID_SENDER = "INVALID_SENDER";

    string internal constant UNKNOWN_TRANSFER_ID = "UNKNOWN_TRANSFER_ID";
    string internal constant CALL_DATA_MUST_SIGNED_BY_OWNER = "CALL_DATA_MUST_SIGNED_BY_OWNER";

}
Context.sol 23 lines
// SPDX-License-Identifier: MIT

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;
    }
}
TransferHelper.sol 28 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}
Ownable.sol 71 lines
// SPDX-License-Identifier: MIT

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() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _setOwner(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");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
ReentrancyGuard.sol 62 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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 ReentrancyGuard {
    // 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;

    constructor() {
        _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 make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}
ECDSA.sol 219 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s;
        uint8 v;
        assembly {
            s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            v := add(shr(255, vs), 27)
        }
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}
draft-EIP712.sol 101 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./ECDSA.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 */
abstract contract EIP712 {
    /* solhint-disable var-name-mixedcase */
    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    uint256 private immutable _CACHED_CHAIN_ID;

    bytes32 private immutable _HASHED_NAME;
    bytes32 private immutable _HASHED_VERSION;
    bytes32 private immutable _TYPE_HASH;

    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        bytes32 typeHash = keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
        );
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
        _CACHED_CHAIN_ID = block.chainid;
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
        _TYPE_HASH = typeHash;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (block.chainid == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
        }
    }

    function _buildDomainSeparator(
        bytes32 typeHash,
        bytes32 nameHash,
        bytes32 versionHash
    ) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
    }
}

Read Contract

bridgeDexs 0x6f2f265c → address, bool
feeAddress 0x41275358 → address
name 0x06fdde03 → string
owner 0x8da5cb5b → address
swapDexs 0x1fd88cd4 → address, bool
symbol 0x95d89b41 → string

Write Contract 12 functions

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

addBridgeDexs 0x675e1cc0
tuple _dex
addSwapDexs 0x6c6fdea3
tuple _dex
bridge 0x69e63d3a
tuple _userRequest
bytes _sign
disableBridgeDex 0x885b2ed8
uint256 _dexId
disableSwapDex 0x0adba875
uint256 _dexId
renounceOwnership 0x715018a6
No parameters
setFeeAddress 0x8705fcd4
address _newFeeAddress
swap 0xd52126e2
tuple _userRequest
bytes _sign
swapAndBridge 0x44797d92
tuple _userRequest
bytes _sign
transferOwnership 0xf2fde38b
address newOwner
withdraw 0xd9caed12
address _token
address _receiverAddress
uint256 _amount
withdrawETH 0x4782f779
address _receiverAddress
uint256 _amount

Recent Transactions

No transactions found for this address