Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xFF031cc2563988Bc4afA29E2cD7Bcc2d389900a5
Balance 0 ETH
Nonce 1
Code Size 14771 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

14771 bytes
0x60806040526004361061014f5760003560e01c80637f5a22f9116100b6578063bce53d241161006f578063bce53d2414610402578063d7fc2da414610422578063d8b964e614610442578063d904371e14610472578063e30c397814610492578063f2fde38b146104b057600080fd5b80637f5a22f9146103185780638da5cb5b146103385780639178bd70146103565780639ccef96f14610376578063a3c573eb146103b5578063a7931169146103d557600080fd5b80633f07fe0d116101085780633f07fe0d1461026a5780634e36b11c1461028a578063536f4cfe146102ae578063715018a6146102ce57806378e3214f146102e357806379ba50971461030357600080fd5b80630babd8641461015b57806311c4b77214610198578063227c5412146101ba5780632344e655146101fa5780632c9e34211461021a5780633bbd64bc1461023a57600080fd5b3661015657005b600080fd5b34801561016757600080fd5b5060025461017b906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101a457600080fd5b506101b86101b33660046127a9565b6104d0565b005b3480156101c657600080fd5b506101ea6101d53660046127e0565b60046020526000908152604090205460ff1681565b604051901515815260200161018f565b34801561020657600080fd5b506101b861021536600461285f565b6104e6565b34801561022657600080fd5b506101b86102353660046128fd565b6107fb565b34801561024657600080fd5b506101ea6102553660046129c4565b60086020526000908152604090205460ff1681565b34801561027657600080fd5b506101b86102853660046129e1565b61098e565b34801561029657600080fd5b506102a060075481565b60405190815260200161018f565b3480156102ba57600080fd5b506101b86102c9366004612a86565b610c0c565b3480156102da57600080fd5b506101b8610c47565b3480156102ef57600080fd5b506101b86102fe366004612a9f565b610c5b565b34801561030f57600080fd5b506101b8610c6e565b34801561032457600080fd5b506101ea6103333660046129c4565b610ced565b34801561034457600080fd5b506000546001600160a01b031661017b565b34801561036257600080fd5b506101b8610371366004612acb565b610d0b565b34801561038257600080fd5b50610396610391366004612d99565b610d9e565b604080516001600160a01b03909316835260208301919091520161018f565b3480156103c157600080fd5b5060065461017b906001600160a01b031681565b3480156103e157600080fd5b506102a06103f0366004612a86565b60096020526000908152604090205481565b34801561040e57600080fd5b5061039661041d366004612e91565b610dda565b34801561042e57600080fd5b506101b861043d3660046129c4565b610e16565b34801561044e57600080fd5b506101ea61045d3660046129c4565b60036020526000908152604090205460ff1681565b34801561047e57600080fd5b506101b861048d366004612eea565b610e27565b34801561049e57600080fd5b506001546001600160a01b031661017b565b3480156104bc57600080fd5b506101b86104cb3660046129c4565b610f73565b6104d8610fe4565b6104e2828261103e565b5050565b6104ee61109b565b6006546001600160a01b03163314610519576040516303d6041760e41b815260040160405180910390fd5b60008061052883850185612f6f565b915091508051825161053a9190612fde565b60000361055a576040516312cd5ab760e11b815260040160405180910390fd5b6000610569888b8b8a8a6110f4565b905061057d816040015182600001516111ee565b6101408301526101208201526007548351156106a6576000848060200190518101906105a9919061305a565b60208101516001600160a01b0316608085015290506001825a11156106645730639ccef96f845a6105da91906131f0565b86516040808901516101408a015191516001600160e01b031960e087901b16815261060b9392908990600401613245565b604080518083038160008887f193505050508015610646575060408051601f3d908101601f1916820190925261064391810190613361565b60015b15610664576001600160a01b03909116602086015260608501525060005b80156106a3576106988e8560e00151866000015185600001518860400151876020015188606001518b61016001518d611237565b5050505050506107e7565b50505b825115610794576000838060200190518101906106c3919061338f565b60808401519091506001600160a01b03166106ec576080808201516001600160a01b0316908401525b815a1115610792573063bce53d24835a61070691906131f0565b83866020015187606001516040518563ffffffff1660e01b815260040161072f9392919061344a565b604080518083038160008887f19350505050801561076a575060408051601f3d908101601f1916820190925261076791810190613361565b60015b15610792576001600160a01b0391821660a086015260c0850152608080830151909116908401525b505b8160c00151826060015111156107ca576107ca826020015183608001518460c0015185606001516107c591906131f0565b6112d1565b6107d88261012001516113d8565b6107e28c836113f9565b505050505b6107f16001600555565b5050505050505050565b61080361109b565b3360009081526008602052604090205460ff166108335760405163f5b06b4160e01b815260040160405180910390fd5b6001600160a01b03851661084657600080fd5b60006108558a8a8a88886110f4565b6001600160a01b0387166080820181905260e082015182516040808501516101608601519151959650600095610895958e9390918b908b906020016134bb565b60408051601f19818403018152918152815160209283012060008f8152600990935291205490915081146108dc57604051635603eb5160e11b815260040160405180910390fd5b6108f38260000151836080015184604001516112d1565b600960008d81526020019081526020016000206000905581608001516001600160a01b031682600001516001600160a01b03168d7f7097a92401cb3cede25c9b17516e7ac039f9b02ac27d72e269b2aad16a4ca8f585604001518660e0015187610100015188610160015160405161096e949392919061352a565b60405180910390a450506109826001600555565b50505050505050505050565b61099661109b565b3360009081526008602052604090205460ff166109c65760405163f5b06b4160e01b815260040160405180910390fd5b60008390036109e8576040516312cd5ab760e11b815260040160405180910390fd5b60006109f78a8a8a8a8a6110f4565b90506000610a0785870187613559565b6020808201516001600160a01b03166080850181905260e0850151855184516040808901516101608a01519151979850600097610a539795969495939491939192918d918d91016134bb565b60405160208183030381529060405280519060200120905080600960008f81526020019081526020016000205414610a9e57604051635603eb5160e11b815260040160405180910390fd5b610ab0836040015184600001516111ee565b610140850181905261012085019190915283516040850151610ad29285611481565b60608501526001600160a01b031660208401528315610ba7576007546000610afc8688018861358d565b9050815a1115610ba4573063bce53d24835a610b1891906131f0565b83886020015189606001516040518563ffffffff1660e01b8152600401610b419392919061344a565b604080518083038160008887f193505050508015610b7c575060408051601f3d908101601f19168201909252610b7991810190613361565b60015b15610ba4576001600160a01b0391821660a088015260c0870152608080830151909116908601525b50505b8260c0015183606001511115610bd857610bd8836020015184608001518560c0015186606001516107c591906131f0565b610be68361012001516113d8565b60008d815260096020526040812055610bff8d846113f9565b5050506109826001600555565b610c14610fe4565b600781905560405181907ff47543a7cab136b12cca0a2ecd728c9d1943f57b923b98db48725d2b76dd4da990600090a250565b610c4f610fe4565b610c59600061154a565b565b610c63610fe4565b6104e28233836112d1565b60015433906001600160a01b03168114610ce15760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084015b60405180910390fd5b610cea8161154a565b50565b6000610cf7610fe4565b610d0082611563565b50600190505b919050565b610d13610fe4565b6001600160a01b038216610d3a5760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b038216600081815260086020908152604091829020805460ff19168515159081179091558251938452908301527fd963701e30b9d04e85bfbf92c227f5d0b832d24c25598c3fbeeae8761d6ded9591015b60405180910390a15050565b600080333014610dc157604051632ee47ea160e11b815260040160405180910390fd5b610dcd86868686611481565b9097909650945050505050565b600080333014610dfd57604051632ee47ea160e11b815260040160405180910390fd5b84519150610e0c8385876115dc565b9050935093915050565b610e1e610fe4565b610cea81611771565b610e2f610fe4565b6000829003610e5157604051630239912560e01b815260040160405180910390fd5b60005b82811015610f6d57610e95848483818110610e7157610e716135c1565b9050602002016020810190610e8691906129c4565b6001600160a01b03163b151590565b610eb2576040516308ebd80360e11b815260040160405180910390fd5b8160036000868685818110610ec957610ec96135c1565b9050602002016020810190610ede91906129c4565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055811515848483818110610f1b57610f1b6135c1565b9050602002016020810190610f3091906129c4565b6001600160a01b03167f1f478f1e5aee36a892d86e821aba410dc0934cb0ebd0241dd75370833884545360405160405180910390a3600101610e54565b50505050565b610f7b610fe4565b600180546001600160a01b0383166001600160a01b03199091168117909155610fac6000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000546001600160a01b03163314610c595760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cd8565b6001600160e01b03198216600081815260046020908152604091829020805460ff19168515159081179091558251938452908301527fc4a5aadd92b2d0e7efaf25f9d44b0e6fca6c44da8e09fc3250cc12ef954cb60e9101610d92565b6002600554036110ed5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cd8565b6002600555565b61117c60405180610180016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001606081525090565b6001600160a01b03851680825260408083018690526020808401929092526060830186905260e08301889052466101008401528051601f850183900483028101830190915283815290849084908190840183828082843760009201919091525050505061016082015295945050505050565b60008060006111fd84306117e3565b905084811015611220576040516319af26f360e31b815260040160405180910390fd5b47925061122d85826131f0565b9150509250929050565b60008888888888878760405160200161125697969594939291906135d7565b60408051601f19818403018152828252805160209182012060008e8152600990925291902081905591508a907fd457b25e0e458857e38c937f68af3100c40afd88fc5522c5820440d07b44351f906112bd908c908c908c908c908c908c908c908c9061364d565b60405180910390a250505050505050505050565b6112da83611877565b156112ee576112e982826118b0565b505050565b46632b6653dc8114801561131e575073a614f803b6fd780986a42c78ec9c7f77e6ded13c6001600160a01b038516145b156113c457604080516001600160a01b038581166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291519186169161137a91906136b9565b6000604051808303816000865af19150503d80600081146113b7576040519150601f19603f3d011682016040523d82523d6000602084013e6113bc565b606091505b505050610f6d565b610f6d6001600160a01b03851684846119c9565b80471015610cea57604051630cfbd6ed60e01b815260040160405180910390fd5b8060a001516001600160a01b031681608001516001600160a01b0316837f593e4dbcb8f7312fc3bdd77e2095da131a6e1993f37752d12576d04e1f7253b484600001518560200151866040015187606001518860c001518960e001518a61010001518b61016001516040516114759897969594939291906136d5565b60405180910390a45050565b805160006001600160a01b03808316908716036114b4576040516001624cdd6d60e11b0319815260040160405180910390fd5b60006114c48460000151306117e3565b90506114d1878786611a2c565b806114e08560000151306117e3565b6114ea91906131f0565b91508360600151821015611511576040516319af26f360e31b815260040160405180910390fd5b60008561151e89306117e3565b61152891906131f0565b9050801561153f5761153f888660400151836112d1565b505094509492505050565b600180546001600160a01b0319169055610cea81611ca5565b60006001600160a01b0382163b61158d576040516308ebd80360e11b815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0384169081179091556040517f53b7c37d01415b2804281f4684b0722e0b01fbd375bf502609f465e17ab4441e90600090a2506001919050565b60006115e883306117e3565b604083015160a08401519192509060238211156116055785828201525b83516116119082611cf5565b600061161c86611877565b1561168b5784600001516001600160a01b0316878360405161163e91906136b9565b60006040518083038185875af1925050503d806000811461167b576040519150601f19603f3d011682016040523d82523d6000602084013e611680565b606091505b505080915050611734565b86156116ab5760208501516116ab906001600160a01b0388169089611dfe565b84600001516001600160a01b03168560600151836040516116cc91906136b9565b60006040518083038185875af1925050503d8060008114611709576040519150601f19603f3d011682016040523d82523d6000602084013e61170e565b606091505b50909150508615611734576020850151611734906001600160a01b038816906000611eab565b8061175257604051637588692960e01b815260040160405180910390fd5b61175c86306117e3565b61176690856131f0565b979650505050505050565b6001600160a01b0381163b611799576040516308ebd80360e11b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040517f556b8b8772c1552cbcc67f9bb7c7fd60934af593e54ec7aa4e8b2683632675f890600090a250565b60006117ee83611877565b1561180457506001600160a01b03811631611871565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa15801561184a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186e919061371f565b90505b92915050565b60006001600160a01b038216158061187157506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b804710156119005760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610cd8565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461194d576040519150601f19603f3d011682016040523d82523d6000602084013e611952565b606091505b50509050806112e95760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610cd8565b6040516001600160a01b0383166024820152604481018290526112e990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611fc0565b6080810151516000819003611a5457604051630239912560e01b815260040160405180910390fd5b6000806000611a6886858760800151612095565b608088015192955090935091506000611a8089611877565b905060005b86811015610982578415611b7d5780600003611b0e5783611ad65784838281518110611ab357611ab36135c1565b6020026020010151606001818151611acb91906131f0565b915081815250611b08565b84838281518110611ae957611ae96135c1565b6020026020010151606001818151611b019190612fde565b9150818152505b50611b7d565b83611b495785838281518110611b2657611b266135c1565b6020026020010151606001818151611b3e91906131f0565b915081815250611b7b565b85838281518110611b5c57611b5c6135c1565b6020026020010151606001818151611b749190612fde565b9150818152505b505b81611bda57611bda838281518110611b9757611b976135c1565b602002602001015160400151848381518110611bb557611bb56135c1565b6020026020010151606001518c6001600160a01b0316611dfe9092919063ffffffff16565b611c5c838281518110611bef57611bef6135c1565b60200260200101516000015183858481518110611c0e57611c0e6135c1565b6020026020010151602001518d878681518110611c2d57611c2d6135c1565b602002602001015160600151888781518110611c4b57611c4b6135c1565b602002602001015160800151612175565b81611c9d57611c9d838281518110611c7657611c766135c1565b60200260200101516040015160008c6001600160a01b0316611eab9092919063ffffffff16565b600101611a85565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6002546001600160a01b039081169083168114801590611d2e57506001600160a01b03831660009081526003602052604090205460ff16155b15611d4c5760405163369370d960e01b815260040160405180910390fd5b6000611d5783612207565b6001600160e01b0319811660009081526004602052604090205490915060ff1615611d9557604051630d1a468960e01b815260040160405180910390fd5b816001600160a01b0316846001600160a01b031603610f6d576001600160e01b03198116632e1a7d4d60e01b14801590611de057506001600160e01b03198116630d0e30db60e41b14155b15610f6d57604051630d1a468960e01b815260040160405180910390fd5b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015611e4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e72919061371f565b9050610f6d8463095ea7b360e01b85611e8b8686612fde565b6040516001600160a01b03909216602483015260448201526064016119f5565b801580611f255750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611eff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f23919061371f565b155b611f905760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610cd8565b6040516001600160a01b0383166024820152604481018290526112e990849063095ea7b360e01b906064016119f5565b6000612015826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122229092919063ffffffff16565b90508051600014806120365750808060200190518101906120369190613738565b6112e95760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cd8565b6000808080805b868110156120d7578581815181106120b6576120b66135c1565b602002602001015160600151826120cd9190612fde565b915060010161209c565b50868111156121235760009150816120ef88836131f0565b90506120fb8782613755565b94506121078786613777565b61211190826131f0565b61211b9086612fde565b93505061216b565b8681101561216b5760019150600061213b82896131f0565b90506121478782613755565b94506121538786613777565b61215d90826131f0565b6121679086612fde565b9350505b5093509350939050565b6000600487600581111561218b5761218b613203565b036121a35761219c85848885612239565b90506121e0565b60058760058111156121b7576121b7613203565b036121c75761219c84848461237c565b6040516318f9c3a760e11b815260040160405180910390fd5b806121fe57604051636ff55bbf60e01b815260040160405180910390fd5b50505050505050565b6000815160000361221a57506000919050565b506020015190565b6060612231848460008561261a565b949350505050565b600080600083806020019051810190612252919061378e565b8151919350915060005b8181101561229a576000848281518110612278576122786135c1565b6020026020010151905060238111156122915788818501525b5060010161225c565b506122a58883611cf5565b851561231157876001600160a01b031687836040516122c491906136b9565b60006040518083038185875af1925050503d8060008114612301576040519150601f19603f3d011682016040523d82523d6000602084013e612306565b606091505b505080945050612371565b876001600160a01b03168260405161232991906136b9565b6000604051808303816000865af19150503d8060008114612366576040519150601f19603f3d011682016040523d82523d6000602084013e61236b565b606091505b50909450505b505050949350505050565b60008082806020019051810190612393919061383f565b905060005b81518110156126115780156123f1576123ce8282815181106123bc576123bc6135c1565b602002602001015160200151306117e3565b94508181815181106123e2576123e26135c1565b60200260200101516020015195505b6000828281518110612405576124056135c1565b60200260200101516080015190506000838381518110612427576124276135c1565b602002602001015160000151905060238111156124445786818301525b61246b848481518110612459576124596135c1565b60200260200101516040015183611cf5565b61247488611877565b156124fc5783838151811061248b5761248b6135c1565b6020026020010151604001516001600160a01b031687836040516124af91906136b9565b60006040518083038185875af1925050503d80600081146124ec576040519150601f19603f3d011682016040523d82523d6000602084013e6124f1565b606091505b5050809550506125fb565b821561253d5761253d848481518110612517576125176135c1565b602002602001015160600151888a6001600160a01b0316611dfe9092919063ffffffff16565b83838151811061254f5761254f6135c1565b6020026020010151604001516001600160a01b03168260405161257291906136b9565b6000604051808303816000865af19150503d80600081146125af576040519150601f19603f3d011682016040523d82523d6000602084013e6125b4565b606091505b509095505082156125fb576125fb8484815181106125d4576125d46135c1565b60200260200101516060015160008a6001600160a01b0316611eab9092919063ffffffff16565b84612607575050612611565b5050600101612398565b50509392505050565b60608247101561267b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610cd8565b600080866001600160a01b0316858760405161269791906136b9565b60006040518083038185875af1925050503d80600081146126d4576040519150601f19603f3d011682016040523d82523d6000602084013e6126d9565b606091505b5091509150611766878383876060831561275457825160000361274d576001600160a01b0385163b61274d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cd8565b5081612231565b61223183838151156127695781518083602001fd5b8060405162461bcd60e51b8152600401610cd8919061396a565b80356001600160e01b031981168114610d0657600080fd5b8015158114610cea57600080fd5b600080604083850312156127bc57600080fd5b6127c583612783565b915060208301356127d58161279b565b809150509250929050565b6000602082840312156127f257600080fd5b6127fb82612783565b9392505050565b6001600160a01b0381168114610cea57600080fd5b60008083601f84011261282957600080fd5b5081356001600160401b0381111561284057600080fd5b60208301915083602082850101111561285857600080fd5b9250929050565b60008060008060008060008060c0898b03121561287b57600080fd5b88359750602089013561288d81612802565b9650604089013595506060890135945060808901356001600160401b03808211156128b757600080fd5b6128c38c838d01612817565b909650945060a08b01359150808211156128dc57600080fd5b506128e98b828c01612817565b999c989b5096995094979396929594505050565b6000806000806000806000806000806101008b8d03121561291d57600080fd5b8a35995060208b0135985060408b013561293681612802565b975060608b0135965060808b013561294d81612802565b955060a08b013561295d81612802565b945060c08b01356001600160401b038082111561297957600080fd5b6129858e838f01612817565b909650945060e08d013591508082111561299e57600080fd5b506129ab8d828e01612817565b915080935050809150509295989b9194979a5092959850565b6000602082840312156129d657600080fd5b81356127fb81612802565b60008060008060008060008060008060e08b8d031215612a0057600080fd5b8a35995060208b0135985060408b0135612a1981612802565b975060608b0135965060808b01356001600160401b0380821115612a3c57600080fd5b612a488e838f01612817565b909850965060a08d0135915080821115612a6157600080fd5b612a6d8e838f01612817565b909650945060c08d013591508082111561299e57600080fd5b600060208284031215612a9857600080fd5b5035919050565b60008060408385031215612ab257600080fd5b8235612abd81612802565b946020939093013593505050565b60008060408385031215612ade57600080fd5b82356127c581612802565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715612b2157612b21612ae9565b60405290565b60405160c081016001600160401b0381118282101715612b2157612b21612ae9565b604051601f8201601f191681016001600160401b0381118282101715612b7157612b71612ae9565b604052919050565b60006001600160401b03821115612b9257612b92612ae9565b5060051b60200190565b60068110610cea57600080fd5b60006001600160401b03821115612bc257612bc2612ae9565b50601f01601f191660200190565b600082601f830112612be157600080fd5b8135612bf4612bef82612ba9565b612b49565b818152846020838601011115612c0957600080fd5b816020850160208301376000918101602001919091529392505050565b600060a08284031215612c3857600080fd5b612c40612aff565b90508135612c4d81612802565b8152602082810135612c5e81612802565b828201526040830135612c7081612802565b6040830152606083810135818401526080808501356001600160401b0380821115612c9a57600080fd5b818701915087601f830112612cae57600080fd5b8135612cbc612bef82612b79565b81815260059190911b8301860190868101908a831115612cdb57600080fd5b8785015b83811015612d8557803585811115612cf75760008081fd5b860160a0818e03601f19011215612d0e5760008081fd5b612d16612aff565b8a820135612d2381612b9c565b81526040820135612d3381612802565b818c0152818a0135612d4481612802565b6040820152818901358a82015260a082013587811115612d645760008081fd5b612d728f8d83860101612bd0565b828b015250845250918801918801612cdf565b506080890152509598975050505050505050565b60008060008060808587031215612daf57600080fd5b8435612dba81612802565b9350602085013592506040850135915060608501356001600160401b03811115612de357600080fd5b612def87828801612c26565b91505092959194509250565b600060c08284031215612e0d57600080fd5b612e15612b27565b90508135612e2281612802565b81526020820135612e3281612802565b8060208301525060408201356040820152606082013560608201526080820135612e5b81612802565b608082015260a08201356001600160401b03811115612e7957600080fd5b612e8584828501612bd0565b60a08301525092915050565b600080600060608486031215612ea657600080fd5b83356001600160401b03811115612ebc57600080fd5b612ec886828701612dfb565b9350506020840135612ed981612802565b929592945050506040919091013590565b600080600060408486031215612eff57600080fd5b83356001600160401b0380821115612f1657600080fd5b818601915086601f830112612f2a57600080fd5b813581811115612f3957600080fd5b8760208260051b8501011115612f4e57600080fd5b60209283019550935050840135612f648161279b565b809150509250925092565b60008060408385031215612f8257600080fd5b82356001600160401b0380821115612f9957600080fd5b612fa586838701612bd0565b93506020850135915080821115612fbb57600080fd5b5061122d85828601612bd0565b634e487b7160e01b600052601160045260246000fd5b8082018082111561187157611871612fc8565b60005b8381101561300c578181015183820152602001612ff4565b50506000910152565b600082601f83011261302657600080fd5b8151613034612bef82612ba9565b81815284602083860101111561304957600080fd5b612231826020830160208701612ff1565b6000602080838503121561306d57600080fd5b82516001600160401b038082111561308457600080fd5b9084019060a0828703121561309857600080fd5b6130a0612aff565b82516130ab81612802565b8152828401516130ba81612802565b8185015260408301516130cc81612802565b604082015260608381015190820152608080840151838111156130ee57600080fd5b80850194505087601f85011261310357600080fd5b8351613111612bef82612b79565b81815260059190911b8501860190868101908a83111561313057600080fd5b8787015b838110156131dc5780518781111561314c5760008081fd5b880160a0818e03601f190112156131635760008081fd5b61316b612aff565b8a82015161317881612b9c565b8152604082015161318881612802565b818c0152606082015161319a81612802565b604082015281870151606082015260a0820151898111156131bb5760008081fd5b6131c98f8d83860101613015565b8289015250845250918801918801613134565b506080850152509198975050505050505050565b8181038181111561187157611871612fc8565b634e487b7160e01b600052602160045260246000fd5b60008151808452613231816020860160208601612ff1565b601f01601f19169290920160200192915050565b6000608060018060a01b03808816845260208781860152604087604087015260606080606088015261012087018489511660808901528389015160a086821660a08b01528660408c01511660c08b015260608b015160e08b015260808b0151915060a06101008b01528282518085526101409450848c019150848160051b8d0101945087840193506000805b82811015613349578d870361013f19018452855180516006811061330357634e487b7160e01b84526021600452602484fd5b8852808b01518c168b890152898101518c168a89015288810151898901528c01518c880186905261333686890182613219565b97505094890194928901926001016132d1565b50505050505080965050505050505095945050505050565b6000806040838503121561337457600080fd5b825161337f81612802565b6020939093015192949293505050565b6000602082840312156133a157600080fd5b81516001600160401b03808211156133b857600080fd5b9083019060c082860312156133cc57600080fd5b6133d4612b27565b82516133df81612802565b815260208301516133ef81612802565b806020830152506040830151604082015260608301516060820152608083015161341881612802565b608082015260a08301518281111561342f57600080fd5b61343b87828601613015565b60a08301525095945050505050565b60608152600060018060a01b03808651166060840152806020870151166080840152604086015160a0840152606086015160c08401528060808701511660e084015260a086015160c06101008501526134a7610120850182613219565b959091166020840152505060400152919050565b88815260006bffffffffffffffffffffffff19808a60601b166020840152808960601b166034840152876048840152808760601b16606884015250845161350981607c850160208901612ff1565b82018385607c83013760009301607c01928352509098975050505050505050565b84815283602082015282604082015260806060820152600061354f6080830184613219565b9695505050505050565b60006020828403121561356b57600080fd5b81356001600160401b0381111561358157600080fd5b61223184828501612c26565b60006020828403121561359f57600080fd5b81356001600160401b038111156135b557600080fd5b61223184828501612dfb565b634e487b7160e01b600052603260045260246000fd5b87815260006bffffffffffffffffffffffff19808960601b166020840152808860601b166034840152866048840152808660601b16606884015250835161362581607c850160208801612ff1565b83519083019061363c81607c840160208801612ff1565b01607c019998505050505050505050565b8881526001600160a01b0388811660208301528781166040830152606082018790528516608082015260a0810184905261010060c0820181905260009061369683820186613219565b905082810360e08401526136aa8185613219565b9b9a5050505050505050505050565b600082516136cb818460208701612ff1565b9190910192915050565b600061010060018060a01b03808c168452808b166020850152508860408401528760608401528660808401528560a08401528460c08401528060e08401526136aa81840185613219565b60006020828403121561373157600080fd5b5051919050565b60006020828403121561374a57600080fd5b81516127fb8161279b565b60008261377257634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761187157611871612fc8565b600080604083850312156137a157600080fd5b82516001600160401b03808211156137b857600080fd5b818501915085601f8301126137cc57600080fd5b815160206137dc612bef83612b79565b82815260059290921b840181019181810190898411156137fb57600080fd5b948201945b8386101561381957855182529482019490820190613800565b9188015191965090935050508082111561383257600080fd5b5061122d85828601613015565b6000602080838503121561385257600080fd5b82516001600160401b038082111561386957600080fd5b818501915085601f83011261387d57600080fd5b815161388b612bef82612b79565b81815260059190911b830184019084810190888311156138aa57600080fd5b8585015b8381101561395d578051858111156138c65760008081fd5b860160a0818c03601f19018113156138de5760008081fd5b6138e6612aff565b8983015181526040808401516138fb81612802565b828c015260608481015161390e81612802565b808385015250608091508185015161392581612802565b9083015291830151918883111561393c5760008081fd5b61394a8e8c85870101613015565b90820152855250509186019186016138ae565b5098975050505050505050565b6020815260006127fb602083018461321956fea26469706673582212200945cd72fa8444fcfa9ab4968d0693ae88f4c28bc5dc5f7d0b5fbd779a89f67564736f6c63430008190033

Verified Source Code Full Match

Compiler: v0.8.25+commit.b61c2a91 EVM: london Optimization: Yes (200 runs)
IButterReceiver.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IButterReceiver {
    //_srcToken received token (wtoken or erc20 token)
    function onReceived(
        bytes32 _orderId,
        address _srcToken,
        uint256 _amount,
        uint256 _fromChain,
        bytes calldata _from,
        bytes calldata _payload
    ) external;
}
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);
    }
}
Ownable2Step.sol 57 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;

import "./Ownable.sol";

/**
 * @dev Contract module which provides 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} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

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

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }
}
ReentrancyGuard.sol 77 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

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 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;
    }
}
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);
}
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));
    }
}
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;
    }
}
SwapCall.sol 329 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "../lib/Errors.sol";

abstract contract SwapCall {
    using SafeERC20 for IERC20;
    using Address for address;

    address internal constant ZERO_ADDRESS = address(0);
    address internal constant NATIVE_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    address public wToken;
    // uint256 internal nativeBalanceBeforeExec;
    // uint256 internal initInputTokenBalance;
    mapping(address => bool) public approved;
    mapping(bytes4 => bool) public funcBlackList;
    event EditFuncBlackList(bytes4 _func, bool flag);
    event SetWrappedToken(address indexed _wToken);

    enum DexType {
        AGG,
        UNIV2,
        UNIV3,
        CURVE,
        FILL,
        MIX
    }

    struct CallbackParam {
        address target;
        address approveTo;
        uint256 offset;
        uint256 extraNativeAmount;
        address receiver;
        bytes data;
    }

    struct SwapParam {
        address dstToken;
        address receiver;
        address leftReceiver;
        uint256 minAmount;
        SwapData[] swaps;
    }

    struct SwapData {
        DexType dexType;
        address callTo;
        address approveTo;
        uint256 fromAmount;
        bytes callData;
    }

    constructor(address _wToken) payable {
        _setWToken(_wToken);
        //| a9059cbb | transfer(address,uint256)
        funcBlackList[bytes4(0xa9059cbb)] = true;
        //| 095ea7b3 | approve(address,uint256) |
        funcBlackList[bytes4(0x095ea7b3)] = true;
        //| 23b872dd | transferFrom(address,address,uint256) |
        funcBlackList[bytes4(0x23b872dd)] = true;
        //| 39509351 | increaseAllowance(address,uint256)
        funcBlackList[bytes4(0x39509351)] = true;
        //| a22cb465 | setApprovalForAll(address,bool) |
        funcBlackList[bytes4(0xa22cb465)] = true;
        //| 42842e0e | safeTransferFrom(address,address,uint256) |
        funcBlackList[bytes4(0x42842e0e)] = true;
        //| b88d4fde | safeTransferFrom(address,address,uint256,bytes) |
        funcBlackList[bytes4(0xb88d4fde)] = true;
        //| 9bd9bbc6 | send(address,uint256,bytes) |
        funcBlackList[bytes4(0x9bd9bbc6)] = true;
        //| fe9d9303 | burn(uint256,bytes) |
        funcBlackList[bytes4(0xfe9d9303)] = true;
        //| 959b8c3f | authorizeOperator
        funcBlackList[bytes4(0x959b8c3f)] = true;
        //| f242432a | safeTransferFrom(address,address,uint256,uint256,bytes) |
        funcBlackList[bytes4(0xf242432a)] = true;
        //| 2eb2c2d6 | safeBatchTransferFrom(address,address,uint256[],uint256[],bytes) |
        funcBlackList[bytes4(0x2eb2c2d6)] = true;
    }

    function _editFuncBlackList(bytes4 _func, bool _flag) internal {
        funcBlackList[_func] = _flag;
        emit EditFuncBlackList(_func, _flag);
    }

    function _setWToken(address _wToken) internal {
        if (!_wToken.isContract()) revert Errors.NOT_CONTRACT();
        wToken = _wToken;
        emit SetWrappedToken(_wToken);
    }

    function _afterCheck(uint256 nativeBalanceBeforeExec) internal view {
        if (address(this).balance < nativeBalanceBeforeExec) revert Errors.NATIVE_VALUE_OVERSPEND();
    }

    function _swap(
        address _token,
        uint256 _amount,
        uint256 _initBalance,
        SwapParam memory swapParam
    ) internal returns (address _dstToken, uint256 _dstAmount) {
        _dstToken = swapParam.dstToken;
        if (_token == _dstToken) revert Errors.SWAP_SAME_TOKEN();

        uint256 finalTokenAmount = _getBalance(swapParam.dstToken, address(this));
        _doSwap(_token, _amount, swapParam);
        _dstAmount = _getBalance(swapParam.dstToken, address(this)) - finalTokenAmount;
        if (_dstAmount < swapParam.minAmount) revert Errors.RECEIVE_LOW();
        uint256 left = _getBalance(_token, address(this)) - _initBalance;
        if (left != 0) {
            _transfer(_token, swapParam.leftReceiver, left);
        }
    }

    function _callBack(
        uint256 _amount,
        address _token,
        CallbackParam memory callParam
    ) internal returns (uint256 _callAmount) {
        _callAmount = _getBalance(_token, address(this));
        uint256 offset = callParam.offset;
        bytes memory callPayload = callParam.data;
        if (offset > 35) {
            //32 length + 4 funcSig
            assembly {
                mstore(add(callPayload, offset), _amount)
            }
        }
        _checkApprove(callParam.target, callPayload);
        bool _result;
        if (_isNative(_token)) {
            (_result, ) = callParam.target.call{value: _amount}(callPayload);
        } else {
            if (_amount != 0) IERC20(_token).safeIncreaseAllowance(callParam.approveTo, _amount);
            // this contract not save money make sure send value can cover this
            (_result, ) = callParam.target.call{value: callParam.extraNativeAmount}(callPayload);
            if (_amount != 0) IERC20(_token).safeApprove(callParam.approveTo, 0);
        }
        if (!_result) revert Errors.CALL_BACK_FAIL();
        _callAmount = _callAmount - _getBalance(_token, address(this));
    }

    function _checkApprove(address _callTo, bytes memory _calldata) private view {
        address wTokenAddr = wToken;
        if (_callTo != wTokenAddr && (!approved[_callTo])) revert Errors.NO_APPROVE();

        bytes4 sig = _getFirst4Bytes(_calldata);
        if (funcBlackList[sig]) revert Errors.CALL_FUNC_BLACK_LIST();

        if (_callTo == wTokenAddr) {
            if (sig != bytes4(0x2e1a7d4d) && sig != bytes4(0xd0e30db0)) revert Errors.CALL_FUNC_BLACK_LIST();
        }
    }

    function _doSwap(address _token, uint256 _amount, SwapParam memory swapParam) internal {
        uint256 len = swapParam.swaps.length;
        if (len == 0) revert Errors.EMPTY();
        (uint256 amountAdjust, uint256 firstAdjust, bool isUp) = _rebuildSwaps(_amount, len, swapParam.swaps);
        SwapData[] memory _swaps = swapParam.swaps;
        bool isNative = _isNative(_token);
        for (uint i = 0; i < len; ) {
            if (firstAdjust != 0) {
                if (i == 0) {
                    isUp ? _swaps[i].fromAmount += firstAdjust : _swaps[i].fromAmount -= firstAdjust;
                } else {
                    isUp ? _swaps[i].fromAmount += amountAdjust : _swaps[i].fromAmount -= amountAdjust;
                }
            }
            if (!isNative) {
                IERC20(_token).safeIncreaseAllowance(_swaps[i].approveTo, _swaps[i].fromAmount);
            }
            _execute(_swaps[i].dexType, isNative, _swaps[i].callTo, _token, _swaps[i].fromAmount, _swaps[i].callData);
            if (!isNative) {
                IERC20(_token).safeApprove(_swaps[i].approveTo, 0);
            }
            unchecked {
                i++;
            }
        }
    }

    function _rebuildSwaps(
        uint256 _amount,
        uint256 _len,
        SwapData[] memory _swaps
    ) private pure returns (uint256 amountAdjust, uint256 firstAdjust, bool isUp) {
        uint256 total = 0;
        for (uint256 i = 0; i < _len; i++) {
            total += _swaps[i].fromAmount;
        }
        if (total > _amount) {
            isUp = false;
            uint256 margin = total - _amount;
            amountAdjust = margin / _len;
            firstAdjust = amountAdjust + (margin - amountAdjust * _len);
        } else if (total < _amount) {
            isUp = true;
            uint256 margin = _amount - total;
            amountAdjust = margin / _len;
            firstAdjust = amountAdjust + (margin - amountAdjust * _len);
        }
    }

    function _execute(
        DexType _dexType,
        bool _native,
        address _router,
        address _srcToken,
        uint256 _amount,
        bytes memory _swapData
    ) internal {
        bool _result;
        if (_dexType == DexType.FILL) {
            (_result) = _makeAggFill(_router, _amount, _native, _swapData);
        } else if (_dexType == DexType.MIX) {
            (_result) = _makeMixSwap(_srcToken, _amount, _swapData);
        } else {
            revert Errors.UNSUPPORT_DEX_TYPE();
        }
        if (!_result) revert Errors.SWAP_FAIL();
    }

    struct MixSwap {
        uint256 offset;
        address srcToken;
        address callTo;
        address approveTo;
        bytes callData;
    }

    function _makeMixSwap(address _srcToken, uint256 _amount, bytes memory _swapData) internal returns (bool _result) {
        MixSwap[] memory mixSwaps = abi.decode(_swapData, (MixSwap[]));
        for (uint256 i = 0; i < mixSwaps.length; i++) {
            if (i != 0) {
                _amount = _getBalance(mixSwaps[i].srcToken, address(this));
                _srcToken = mixSwaps[i].srcToken;
            }
            bytes memory callData = mixSwaps[i].callData;
            uint256 offset = mixSwaps[i].offset;
            if (offset > 35) {
                //32 length + 4 funcSig
                assembly {
                    mstore(add(callData, offset), _amount)
                }
            }
            _checkApprove(mixSwaps[i].callTo, callData);
            if (_isNative(_srcToken)) {
                (_result, ) = mixSwaps[i].callTo.call{value: _amount}(callData);
            } else {
                if (i != 0) {
                    IERC20(_srcToken).safeIncreaseAllowance(mixSwaps[i].approveTo, _amount);
                }

                (_result, ) = mixSwaps[i].callTo.call(callData);

                if (i != 0) {
                    IERC20(_srcToken).safeApprove(mixSwaps[i].approveTo, 0);
                }
            }
            if (!_result) {
                break;
            }
        }
    }

    function _makeAggFill(
        address _router,
        uint256 _amount,
        bool native,
        bytes memory _swapData
    ) internal returns (bool _result) {
        (uint256[] memory offsets, bytes memory callData) = abi.decode(_swapData, (uint256[], bytes));
        uint256 len = offsets.length;
        for (uint i = 0; i < len; i++) {
            uint256 offset = offsets[i];
            if (offset > 35) {
                //32 length + 4 funcSig
                assembly {
                    mstore(add(callData, offset), _amount)
                }
            }
        }
        _checkApprove(_router, callData);
        if (native) {
            (_result, ) = _router.call{value: _amount}(callData);
        } else {
            (_result, ) = _router.call(callData);
        }
    }

    function _isNative(address token) internal pure returns (bool) {
        return (token == ZERO_ADDRESS || token == NATIVE_ADDRESS);
    }

    function _getBalance(address _token, address _account) internal view returns (uint256) {
        if (_isNative(_token)) {
            return _account.balance;
        } else {
            return IERC20(_token).balanceOf(_account);
        }
    }

    function _transfer(address _token, address _to, uint256 _amount) internal {
        if (_isNative(_token)) {
            Address.sendValue(payable(_to), _amount);
        } else {
            uint256 _chainId = block.chainid;
            if (_chainId == 728126428 && _token == 0xa614f803B6FD780986A42c78Ec9c7f77e6DeD13C) {
                // Tron USDT
                _token.call(abi.encodeWithSelector(0xa9059cbb, _to, _amount));
            } else {
                IERC20(_token).safeTransfer(_to, _amount);
            }
        }
    }

    function _getFirst4Bytes(bytes memory data) internal pure returns (bytes4 outBytes4) {
        if (data.length == 0) {
            return 0x0;
        }
        assembly {
            outBytes4 := mload(add(data, 32))
        }
    }
}
Errors.sol 24 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

library Errors {
    error NOT_CONTRACT();
    error SWAP_FAIL();
    error CALL_BACK_FAIL();
    error ZERO_IN();
    error FEE_MISMATCH();
    error FEE_LOWER();
    error ZERO_ADDRESS();
    error RECEIVE_LOW();
    error CALL_AMOUNT_INVALID();
    error BRIDGE_ONLY();
    error DATA_EMPTY();
    error NO_APPROVE();
    error NATIVE_VALUE_OVERSPEND();
    error EMPTY();
    error UNSUPPORT_DEX_TYPE();
    error SWAP_SAME_TOKEN();
    error CANNOT_ADJUST();
    error SELF_ONLY();
    error CALL_FUNC_BLACK_LIST();
}
Receiver.sol 387 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;

import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@butternetwork/bridge/contracts/interface/IButterReceiver.sol";
import "./abstract/SwapCall.sol";

contract Receiver is Ownable2Step, SwapCall, ReentrancyGuard, IButterReceiver {
    using SafeERC20 for IERC20;
    using Address for address;

    address public bridgeAddress;
    uint256 public gasForReFund = 80000;

    mapping(address => bool) public keepers;
    mapping(bytes32 => bytes32) public storedFailedSwap;

    error ONLY_KEEPER();
    error INVALID_EXEC_PARAM();

    // use to solve deep stack
    struct SwapTemp {
        address srcToken;
        address swapToken;
        uint256 srcAmount;
        uint256 swapAmount;
        address receiver;
        address target;
        uint256 callAmount;
        uint256 fromChain;
        uint256 toChain;
        uint256 nativeBalance;
        uint256 inputBalance;
        bytes from;
    }

    event RemoteSwapAndCall(
        bytes32 indexed orderId,
        address indexed receiver,
        address indexed target,
        address originToken,
        address swapToken,
        uint256 originAmount,
        uint256 swapAmount,
        uint256 callAmount,
        uint256 fromChain,
        uint256 toChain,
        bytes from
    );

    event SwapRescueFunds(
        bytes32 indexed orderId,
        address indexed token,
        address indexed receiver,
        uint256 amount,
        uint256 fromChain,
        uint256 toChain,
        bytes from
    );

    event Approve(address indexed executor, bool indexed flag);
    event SetBridgeAddress(address indexed _bridgeAddress);
    event SetGasForReFund(uint256 indexed _gasForReFund);
    event UpdateKeepers(address _keeper, bool _flag);

    constructor(address _owner, address _wToken, address _bridgeAddress) payable SwapCall(_wToken) {
        if (_owner == address(0)) revert Errors.ZERO_ADDRESS();
        _setBridgeAddress(_bridgeAddress);
        _transferOwnership(_owner);
    }

    function setAuthorization(address[] calldata _executors, bool _flag) external onlyOwner {
        if (_executors.length == 0) revert Errors.EMPTY();
        for (uint i = 0; i < _executors.length; i++) {
            if (!_executors[i].isContract()) revert Errors.NOT_CONTRACT();
            approved[_executors[i]] = _flag;
            emit Approve(_executors[i], _flag);
        }
    }

    function updateKeepers(address _keeper, bool _flag) external onlyOwner {
        if (_keeper == address(0)) revert Errors.ZERO_ADDRESS();
        keepers[_keeper] = _flag;
        emit UpdateKeepers(_keeper, _flag);
    }

    function setBridgeAddress(address _bridgeAddress) public onlyOwner returns (bool) {
        _setBridgeAddress(_bridgeAddress);
        return true;
    }

    function setGasForReFund(uint256 _gasForReFund) external onlyOwner {
        gasForReFund = _gasForReFund;
        emit SetGasForReFund(_gasForReFund);
    }

    function setWToken(address _wToken) external onlyOwner {
        _setWToken(_wToken);
    }

    function editFuncBlackList(bytes4 _func, bool _flag) external onlyOwner {
        _editFuncBlackList(_func, _flag);
    }

    // _srcToken must erc20 Token or wToken
    function onReceived(
        bytes32 _orderId,
        address _srcToken,
        uint256 _amount,
        uint256 _fromChain,
        bytes calldata _from,
        bytes calldata _swapAndCall
    ) external override nonReentrant {
        if (msg.sender != bridgeAddress) revert Errors.BRIDGE_ONLY();

        (bytes memory _swapData, bytes memory _callbackData) = abi.decode(_swapAndCall, (bytes, bytes));
        if ((_swapData.length + _callbackData.length) == 0) revert Errors.DATA_EMPTY();

        SwapTemp memory swapTemp = _assignment(_fromChain, _srcToken, _amount, _from);
        (swapTemp.nativeBalance, swapTemp.inputBalance) = _checkBalance(swapTemp.srcAmount, swapTemp.srcToken);

        uint256 minExecGas = gasForReFund;
        if (_swapData.length > 0) {
            SwapParam memory swap = abi.decode(_swapData, (SwapParam));
            swapTemp.receiver = swap.receiver;
            bool needStore = true;
            if (gasleft() > minExecGas) {
                try
                    this.remoteSwap{gas: (gasleft() - minExecGas)}(
                        swapTemp.srcToken,
                        swapTemp.srcAmount,
                        swapTemp.inputBalance,
                        swap
                    )
                returns (address dstToken, uint256 dstAmount) {
                    swapTemp.swapToken = dstToken;
                    swapTemp.swapAmount = dstAmount;
                    needStore = false;
                } catch {}
            }
            if (needStore) {
                _store(
                    _orderId,
                    swapTemp.fromChain,
                    swapTemp.srcToken,
                    swap.dstToken,
                    swapTemp.srcAmount,
                    swap.receiver,
                    swap.minAmount,
                    swapTemp.from,
                    _callbackData
                );
                return;
            }
        }

        if (_callbackData.length > 0) {
            CallbackParam memory callParam = abi.decode(_callbackData, (CallbackParam));
            if (swapTemp.receiver == address(0)) {
                swapTemp.receiver = callParam.receiver;
            }
            if (gasleft() > minExecGas) {
                try
                    this.remoteCall{gas: (gasleft() - minExecGas)}(callParam, swapTemp.swapToken, swapTemp.swapAmount)
                returns (address target, uint256 callAmount) {
                    swapTemp.target = target;
                    swapTemp.callAmount = callAmount;
                    swapTemp.receiver = callParam.receiver;
                } catch {}
            }
        }

        if (swapTemp.swapAmount > swapTemp.callAmount) {
            _transfer(swapTemp.swapToken, swapTemp.receiver, (swapTemp.swapAmount - swapTemp.callAmount));
        }

        _afterCheck(swapTemp.nativeBalance);
        _emitRemoteSwapAndCall(_orderId, swapTemp);
    }

    function swapRescueFunds(
        bytes32 _orderId,
        uint256 _fromChain,
        address _srcToken,
        uint256 _amount,
        address _dscToken,
        address _receiver,
        bytes calldata _from,
        bytes calldata _callbackData
    ) external nonReentrant {
        if (!keepers[msg.sender]) revert ONLY_KEEPER();
        require(_receiver != address(0));
        SwapTemp memory swapTemp = _assignment(_fromChain, _srcToken, _amount, _from);
        swapTemp.receiver = _receiver;
        bytes32 hash = keccak256(
            abi.encodePacked(
                swapTemp.fromChain,
                swapTemp.srcToken,
                _dscToken,
                swapTemp.srcAmount,
                swapTemp.receiver,
                swapTemp.from,
                _callbackData
            )
        );
        if (storedFailedSwap[_orderId] != hash) revert INVALID_EXEC_PARAM();
        _transfer(swapTemp.srcToken, swapTemp.receiver, swapTemp.srcAmount);
        delete storedFailedSwap[_orderId];
        emit SwapRescueFunds(
            _orderId,
            swapTemp.srcToken,
            swapTemp.receiver,
            swapTemp.srcAmount,
            swapTemp.fromChain,
            swapTemp.toChain,
            swapTemp.from
        );
    }

    function execSwap(
        bytes32 _orderId,
        uint256 _fromChain,
        address _srcToken,
        uint256 _amount,
        bytes calldata _from,
        bytes calldata _swapData,
        bytes calldata _callbackData
    ) external nonReentrant {
        if (!keepers[msg.sender]) revert ONLY_KEEPER();
        if (_swapData.length == 0) revert Errors.DATA_EMPTY();

        SwapTemp memory swapTemp = _assignment(_fromChain, _srcToken, _amount, _from);

        SwapParam memory swap = abi.decode(_swapData, (SwapParam));
        swapTemp.receiver = swap.receiver;

        bytes32 hash = keccak256(
            abi.encodePacked(
                swapTemp.fromChain,
                swapTemp.srcToken,
                swap.dstToken,
                swapTemp.srcAmount,
                swapTemp.receiver,
                swapTemp.from,
                _callbackData
            )
        );
        if (storedFailedSwap[_orderId] != hash) revert INVALID_EXEC_PARAM();

        (swapTemp.nativeBalance, swapTemp.inputBalance) = _checkBalance(swapTemp.srcAmount, swapTemp.srcToken);

        (swapTemp.swapToken, swapTemp.swapAmount) = _swap(
            swapTemp.srcToken,
            swapTemp.srcAmount,
            swapTemp.inputBalance,
            swap
        );

        if (_callbackData.length > 0) {
            uint256 minExecGas = gasForReFund;
            CallbackParam memory callParam = abi.decode(_callbackData, (CallbackParam));
            if (gasleft() > minExecGas) {
                try
                    this.remoteCall{gas: (gasleft() - minExecGas)}(callParam, swapTemp.swapToken, swapTemp.swapAmount)
                returns (address target, uint256 callAmount) {
                    swapTemp.target = target;
                    swapTemp.callAmount = callAmount;
                    swapTemp.receiver = callParam.receiver;
                } catch {}
            }
        }

        if (swapTemp.swapAmount > swapTemp.callAmount) {
            _transfer(swapTemp.swapToken, swapTemp.receiver, (swapTemp.swapAmount - swapTemp.callAmount));
        }
        _afterCheck(swapTemp.nativeBalance);
        delete storedFailedSwap[_orderId];
        _emitRemoteSwapAndCall(_orderId, swapTemp);
    }

    function _assignment(
        uint256 _fromChain,
        address _srcToken,
        uint256 _amount,
        bytes calldata _from
    ) private view returns (SwapTemp memory swapTemp) {
        swapTemp.srcToken = _srcToken;
        swapTemp.srcAmount = _amount;
        swapTemp.swapToken = _srcToken;
        swapTemp.swapAmount = _amount;
        swapTemp.fromChain = _fromChain;
        swapTemp.toChain = block.chainid;
        swapTemp.from = _from;
    }

    function _emitRemoteSwapAndCall(bytes32 _orderId, SwapTemp memory swapTemp) private {
        emit RemoteSwapAndCall(
            _orderId,
            swapTemp.receiver,
            swapTemp.target,
            swapTemp.srcToken,
            swapTemp.swapToken,
            swapTemp.srcAmount,
            swapTemp.swapAmount,
            swapTemp.callAmount,
            swapTemp.fromChain,
            swapTemp.toChain,
            swapTemp.from
        );
    }

    function _checkBalance(
        uint256 _amount,
        address _srcToken
    ) private view returns (uint256 nativeBalance, uint256 inputBalance) {
        uint256 balance = _getBalance(_srcToken, address(this));
        if (balance < _amount) revert Errors.RECEIVE_LOW();
        nativeBalance = address(this).balance;
        inputBalance = balance - _amount;
    }

    function remoteSwap(
        address _srcToken,
        uint256 _amount,
        uint256 _initBalance,
        SwapParam memory swapParam
    ) external returns (address dstToken, uint256 dstAmount) {
        if (msg.sender != address(this)) revert Errors.SELF_ONLY();
        (dstToken, dstAmount) = _swap(_srcToken, _amount, _initBalance, swapParam);
    }

    function remoteCall(
        CallbackParam memory _callbackParam,
        address _callToken,
        uint256 _amount
    ) external returns (address target, uint256 callAmount) {
        if (msg.sender != address(this)) revert Errors.SELF_ONLY();
        target = _callbackParam.target;
        callAmount = _callBack(_amount, _callToken, _callbackParam);
    }

    event SwapFailed(
        bytes32 indexed _orderId,
        uint256 _fromChain,
        address _srcToken,
        address _dscToken,
        uint256 _amount,
        address _receiver,
        uint256 _minReceived,
        bytes _from,
        bytes _callData
    );

    function _store(
        bytes32 _orderId,
        uint256 _fromChain,
        address _srcToken,
        address _dstToken,
        uint256 _amount,
        address _receiver,
        uint256 _minReceived,
        bytes memory _from,
        bytes memory _callbackData
    ) private {
        bytes32 hash = keccak256(
            abi.encodePacked(_fromChain, _srcToken, _dstToken, _amount, _receiver, _from, _callbackData)
        );
        storedFailedSwap[_orderId] = hash;
        emit SwapFailed(_orderId, _fromChain, _srcToken, _dstToken, _amount, _receiver, _minReceived, _from, _callbackData);
    }

    function _setBridgeAddress(address _bridgeAddress) internal returns (bool) {
        if (!_bridgeAddress.isContract()) revert Errors.NOT_CONTRACT();
        bridgeAddress = _bridgeAddress;
        emit SetBridgeAddress(_bridgeAddress);
        return true;
    }

    function rescueFunds(address _token, uint256 _amount) external onlyOwner {
        _transfer(_token, msg.sender, _amount);
    }

    receive() external payable {}
}

Read Contract

approved 0xd8b964e6 → bool
bridgeAddress 0xa3c573eb → address
funcBlackList 0x227c5412 → bool
gasForReFund 0x4e36b11c → uint256
keepers 0x3bbd64bc → bool
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
storedFailedSwap 0xa7931169 → bytes32
wToken 0x0babd864 → address

Write Contract 15 functions

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

acceptOwnership 0x79ba5097
No parameters
editFuncBlackList 0x11c4b772
bytes4 _func
bool _flag
execSwap 0x3f07fe0d
bytes32 _orderId
uint256 _fromChain
address _srcToken
uint256 _amount
bytes _from
bytes _swapData
bytes _callbackData
onReceived 0x2344e655
bytes32 _orderId
address _srcToken
uint256 _amount
uint256 _fromChain
bytes _from
bytes _swapAndCall
remoteCall 0x74da61de
tuple _callbackParam
address _callToken
uint256 _amount
returns: address, uint256
remoteSwap 0xea4e58ec
address _srcToken
uint256 _amount
uint256 _initBalance
tuple swapParam
returns: address, uint256
renounceOwnership 0x715018a6
No parameters
rescueFunds 0x78e3214f
address _token
uint256 _amount
setAuthorization 0xd904371e
address[] _executors
bool _flag
setBridgeAddress 0x7f5a22f9
address _bridgeAddress
returns: bool
setGasForReFund 0x536f4cfe
uint256 _gasForReFund
setWToken 0xd7fc2da4
address _wToken
swapRescueFunds 0x2c9e3421
bytes32 _orderId
uint256 _fromChain
address _srcToken
uint256 _amount
address _dscToken
address _receiver
bytes _from
bytes _callbackData
transferOwnership 0xf2fde38b
address newOwner
updateKeepers 0x9178bd70
address _keeper
bool _flag

Recent Transactions

No transactions found for this address