From a8e3537fc7a52c904884c7af87ca49b0a1fff4c9 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Thu, 16 Nov 2023 15:22:41 +0800 Subject: [PATCH] feat: new bridge-history apis --- bridge-history-api/README.md | 14 +- bridge-history-api/abi/backend_abi.go | 373 +++++--------- .../cmd/backend_server/app/app.go | 11 +- .../cmd/cross_msg_fetcher/app/app.go | 94 +--- bridge-history-api/config.json | 23 +- bridge-history-api/config/config.go | 51 +- .../messagefetcher/l1_message_fetcher.go | 231 +++++++++ .../messagefetcher/l2_message_fetcher.go | 237 +++++++++ .../controller}/messageproof/withdraw_trie.go | 0 .../messageproof/withdraw_trie_test.go | 0 .../crossmessage/logic/event_parser.go | 464 ++++++++++++++++++ .../crossmsg/batch_info_fetcher.go | 116 ----- .../crossmsg/block_timestamp_fetcher.go | 85 ---- .../crossmsg/cross_msg_fetcher.go | 215 -------- .../crossmsg/fetch_missing_event.go | 213 -------- .../messageproof/msg_proof_updater.go | 249 ---------- .../crossmsg/msg_fetcher_test.go | 65 --- bridge-history-api/crossmsg/reorg_handle.go | 108 ---- bridge-history-api/go.mod | 5 +- bridge-history-api/go.sum | 9 +- .../internal/controller/batch_controller.go | 37 -- .../internal/controller/controller.go | 8 +- .../internal/controller/history_controller.go | 343 +++++++++++-- .../internal/logic/batch_logic.go | 35 -- .../internal/logic/history_logic.go | 224 +++------ bridge-history-api/internal/route/route.go | 4 +- .../types/{history_types.go => types.go} | 67 ++- bridge-history-api/orm/batch.go | 114 ----- bridge-history-api/orm/cross_message.go | 340 +++++++++++++ bridge-history-api/orm/cross_msg.go | 381 -------------- bridge-history-api/orm/l2_sent_msg.go | 268 ---------- bridge-history-api/orm/l2_sent_msg_test.go | 77 --- .../migrations/00001_cross_message.sql | 44 ++ .../migrate/migrations/00001_cross_msg.sql | 57 --- .../migrate/migrations/00002_relayed_msg.sql | 41 -- .../migrate/migrations/00003_l2_sent_msg.sql | 47 -- .../migrate/migrations/00004_rollup_batch.sql | 40 -- bridge-history-api/orm/relayed_msg.go | 155 ------ ...db322e58ff5579c502219c8024acaea74cf311.txt | 1 - bridge-history-api/utils/parse_event.go | 383 --------------- bridge-history-api/utils/utils.go | 14 +- bridge-history-api/utils/utils_test.go | 8 +- 42 files changed, 1938 insertions(+), 3313 deletions(-) create mode 100644 bridge-history-api/crossmessage/controller/messagefetcher/l1_message_fetcher.go create mode 100644 bridge-history-api/crossmessage/controller/messagefetcher/l2_message_fetcher.go rename bridge-history-api/{crossmsg => crossmessage/controller}/messageproof/withdraw_trie.go (100%) rename bridge-history-api/{crossmsg => crossmessage/controller}/messageproof/withdraw_trie_test.go (100%) create mode 100644 bridge-history-api/crossmessage/logic/event_parser.go delete mode 100644 bridge-history-api/crossmsg/batch_info_fetcher.go delete mode 100644 bridge-history-api/crossmsg/block_timestamp_fetcher.go delete mode 100644 bridge-history-api/crossmsg/cross_msg_fetcher.go delete mode 100644 bridge-history-api/crossmsg/fetch_missing_event.go delete mode 100644 bridge-history-api/crossmsg/messageproof/msg_proof_updater.go delete mode 100644 bridge-history-api/crossmsg/msg_fetcher_test.go delete mode 100644 bridge-history-api/crossmsg/reorg_handle.go delete mode 100644 bridge-history-api/internal/controller/batch_controller.go delete mode 100644 bridge-history-api/internal/logic/batch_logic.go rename bridge-history-api/internal/types/{history_types.go => types.go} (54%) delete mode 100644 bridge-history-api/orm/batch.go create mode 100644 bridge-history-api/orm/cross_message.go delete mode 100644 bridge-history-api/orm/cross_msg.go delete mode 100644 bridge-history-api/orm/l2_sent_msg.go delete mode 100644 bridge-history-api/orm/l2_sent_msg_test.go create mode 100644 bridge-history-api/orm/migrate/migrations/00001_cross_message.sql delete mode 100644 bridge-history-api/orm/migrate/migrations/00001_cross_msg.sql delete mode 100644 bridge-history-api/orm/migrate/migrations/00002_relayed_msg.sql delete mode 100644 bridge-history-api/orm/migrate/migrations/00003_l2_sent_msg.sql delete mode 100644 bridge-history-api/orm/migrate/migrations/00004_rollup_batch.sql delete mode 100644 bridge-history-api/orm/relayed_msg.go delete mode 100644 bridge-history-api/testdata/commit-batches-0x3095e91db7ba4a6fbf4654d607db322e58ff5579c502219c8024acaea74cf311.txt delete mode 100644 bridge-history-api/utils/parse_event.go diff --git a/bridge-history-api/README.md b/bridge-history-api/README.md index 27f9bb5a88..9d6dcf42dc 100644 --- a/bridge-history-api/README.md +++ b/bridge-history-api/README.md @@ -59,7 +59,7 @@ can change this port thru modify `config.json` // @Router /api/txsbyhashes [post] ``` -3. `/claimable` +3. `/claimablewithdrawals` ``` // @Summary get all claimable txs under given address // @Accept plain @@ -68,15 +68,5 @@ can change this port thru modify `config.json` // @Param page_size query int true "page size" // @Param page query int true "page" // @Success 200 -// @Router /api/claimable [get] +// @Router /api/claimablewithdrawals [get] ``` - -4. `/withdraw_root` -``` -// @Summary get withdraw_root of given batch index -// @Accept plain -// @Produce plain -// @Param batch_index query string true "batch_index" -// @Success 200 -// @Router /api/withdraw_root [get] -``` \ No newline at end of file diff --git a/bridge-history-api/abi/backend_abi.go b/bridge-history-api/abi/backend_abi.go index 940cd2df10..467295e4c5 100644 --- a/bridge-history-api/abi/backend_abi.go +++ b/bridge-history-api/abi/backend_abi.go @@ -9,251 +9,155 @@ import ( ) var ( - // L1ETHGatewayABI holds information about L1ETHGateway's context and available invokable methods. - L1ETHGatewayABI *abi.ABI - // L1StandardERC20GatewayABI holds information about L1StandardERC20Gateway's context and available invokable methods. - L1StandardERC20GatewayABI *abi.ABI - L1WETHGatewayABI *abi.ABI - L1CustomERC20GatewayABI *abi.ABI - L1ERC721GatewayABI *abi.ABI - L1ERC1155GatewayABI *abi.ABI - L2CustomERC20GatewayABI *abi.ABI - L2ERC721GatewayABI *abi.ABI - // L2ETHGatewayABI holds information about L2ETHGateway contract's context and available invokable methods. - L2ETHGatewayABI *abi.ABI - L2WETHGatewayABI *abi.ABI - // L2StandardERC20GatewayABI holds information about L2StandardERC20Gateway's context and available invokable methods. - L2StandardERC20GatewayABI *abi.ABI - L2ERC1155GatewayABI *abi.ABI + IL1ETHGatewayABI *abi.ABI + IL1ERC20GatewayABI *abi.ABI + IL1ERC721GatewayABI *abi.ABI + IL1ERC1155GatewayABI *abi.ABI + + IL2ETHGatewayABI *abi.ABI + IL2ERC20GatewayABI *abi.ABI + IL2ERC721GatewayABI *abi.ABI + IL2ERC1155GatewayABI *abi.ABI + + IL1ScrollMessengerABI *abi.ABI + IL2ScrollMessengerABI *abi.ABI + + IScrollChainABI *abi.ABI + + IL1MessageQueueABI *abi.ABI L1DepositETHSig common.Hash - L1DepositWETHSig common.Hash L1DepositERC20Sig common.Hash - L1DepositERC1155Sig common.Hash - L2WithdrawETHSig common.Hash - L2WithdrawWETHSig common.Hash - L2WithdrawERC20Sig common.Hash - L1DepositCustomERC20Sig common.Hash L1DepositERC721Sig common.Hash - L2WithdrawCustomERC20Sig common.Hash - L2WithdrawERC721Sig common.Hash - L2WithdrawERC1155Sig common.Hash + L1DepositERC1155Sig common.Hash + L1BatchDepositERC721Sig common.Hash + L1BatchDepositERC1155Sig common.Hash - // batch nft sigs - L1BatchDepositERC721Sig common.Hash - L1BatchDepositERC1155Sig common.Hash + L2WithdrawETHSig common.Hash + L2WithdrawERC20Sig common.Hash + L2WithdrawERC721Sig common.Hash + L2WithdrawERC1155Sig common.Hash L2BatchWithdrawERC721Sig common.Hash L2BatchWithdrawERC1155Sig common.Hash - // scroll mono repo - - // ScrollChainABI holds information about ScrollChain's context and available invokable methods. - ScrollChainABI *abi.ABI - // ScrollChainV2ABI holds information about ScrollChainV2's context and available invokable methods. - ScrollChainV2ABI *abi.ABI - // L1ScrollMessengerABI holds information about L1ScrollMessenger's context and available invokable methods. - L1ScrollMessengerABI *abi.ABI - // L1MessageQueueABI holds information about L1MessageQueue contract's context and available invokable methods. - L1MessageQueueABI *abi.ABI - // L2GasPriceOracleABI holds information about L2GasPriceOracle's context and available invokable methods. - L2GasPriceOracleABI *abi.ABI - - // L2ScrollMessengerABI holds information about L2ScrollMessenger's context and available invokable methods. - L2ScrollMessengerABI *abi.ABI - // L1BlockContainerABI holds information about L1BlockContainer contract's context and available invokable methods. - L1BlockContainerABI *abi.ABI - // L1GasPriceOracleABI holds information about L1GasPriceOracle's context and available invokable methods. - L1GasPriceOracleABI *abi.ABI - // L2MessageQueueABI holds information about L2MessageQueue contract's context and available invokable methods. - L2MessageQueueABI *abi.ABI - - // L1SentMessageEventSignature = keccak256("SentMessage(address,address,uint256,uint256,uint256,bytes)") - L1SentMessageEventSignature common.Hash - // L1RelayedMessageEventSignature = keccak256("RelayedMessage(bytes32)") - L1RelayedMessageEventSignature common.Hash - // L1FailedRelayedMessageEventSignature = keccak256("FailedRelayedMessage(bytes32)") - L1FailedRelayedMessageEventSignature common.Hash - - // L1CommitBatchEventSignature = keccak256("CommitBatch(uint256,bytes32)") - L1CommitBatchEventSignature common.Hash - // L1FinalizeBatchEventSignature = keccak256("FinalizeBatch(uint256,bytes32)") - L1FinalizeBatchEventSignature common.Hash - - // L1QueueTransactionEventSignature = keccak256("QueueTransaction(address,address,uint256,uint256,uint256,bytes)") - L1QueueTransactionEventSignature common.Hash - - // L2SentMessageEventSignature = keccak256("SentMessage(address,address,uint256,uint256,uint256,bytes,uint256,uint256)") - L2SentMessageEventSignature common.Hash - // L2RelayedMessageEventSignature = keccak256("RelayedMessage(bytes32)") - L2RelayedMessageEventSignature common.Hash - // L2FailedRelayedMessageEventSignature = keccak256("FailedRelayedMessage(bytes32)") - L2FailedRelayedMessageEventSignature common.Hash - - // L2AppendMessageEventSignature = keccak256("AppendMessage(uint256,bytes32)") - L2AppendMessageEventSignature common.Hash + L1SentMessageEventSig common.Hash + L1RelayedMessageEventSig common.Hash + L1FailedRelayedMessageEventSig common.Hash + L2SentMessageEventSig common.Hash + L2RelayedMessageEventSig common.Hash + L2FailedRelayedMessageEventSig common.Hash + + L1CommitBatchEventSig common.Hash + L1RevertBatchEventSig common.Hash + L1FinalizeBatchEventSig common.Hash + + L1QueueTransactionEventSig common.Hash + L1DequeueTransactionEventSig common.Hash + L1DropTransactionEventSig common.Hash ) func init() { - L1ETHGatewayABI, _ = L1ETHGatewayMetaData.GetAbi() - L1DepositETHSig = L1ETHGatewayABI.Events["DepositETH"].ID - L1WETHGatewayABI, _ = L1WETHGatewayMetaData.GetAbi() - L1DepositWETHSig = L1WETHGatewayABI.Events["DepositERC20"].ID - L1StandardERC20GatewayABI, _ = L1StandardERC20GatewayMetaData.GetAbi() - L1DepositERC20Sig = L1StandardERC20GatewayABI.Events["DepositERC20"].ID - L1CustomERC20GatewayABI, _ = L1CustomERC20GatewayMetaData.GetAbi() - L1DepositCustomERC20Sig = L1CustomERC20GatewayABI.Events["DepositERC20"].ID - L1ERC721GatewayABI, _ = L1ERC721GatewayMetaData.GetAbi() - L1DepositERC721Sig = L1ERC721GatewayABI.Events["DepositERC721"].ID - L1ERC1155GatewayABI, _ = L1ERC1155GatewayMetaData.GetAbi() - L1DepositERC1155Sig = L1ERC1155GatewayABI.Events["DepositERC1155"].ID - L2ETHGatewayABI, _ = L2ETHGatewayMetaData.GetAbi() - L2WithdrawETHSig = L2ETHGatewayABI.Events["WithdrawETH"].ID - L2WETHGatewayABI, _ = L2WETHGatewayMetaData.GetAbi() - L2WithdrawWETHSig = L2WETHGatewayABI.Events["WithdrawERC20"].ID - L2StandardERC20GatewayABI, _ = L2StandardERC20GatewayMetaData.GetAbi() - L2WithdrawERC20Sig = L2StandardERC20GatewayABI.Events["WithdrawERC20"].ID - L2CustomERC20GatewayABI, _ = L2CustomERC20GatewayMetaData.GetAbi() - L2WithdrawCustomERC20Sig = L2CustomERC20GatewayABI.Events["WithdrawERC20"].ID - L2ERC721GatewayABI, _ = L2ERC721GatewayMetaData.GetAbi() - L2WithdrawERC721Sig = L2ERC721GatewayABI.Events["WithdrawERC721"].ID - L2ERC1155GatewayABI, _ = L2ERC1155GatewayMetaData.GetAbi() - L2WithdrawERC1155Sig = L2ERC1155GatewayABI.Events["WithdrawERC1155"].ID - - // batch nft events - L1BatchDepositERC721Sig = L1ERC721GatewayABI.Events["BatchDepositERC721"].ID - L1BatchDepositERC1155Sig = L1ERC1155GatewayABI.Events["BatchDepositERC1155"].ID - L2BatchWithdrawERC721Sig = L2ERC721GatewayABI.Events["BatchWithdrawERC721"].ID - L2BatchWithdrawERC1155Sig = L2ERC1155GatewayABI.Events["BatchWithdrawERC1155"].ID - - // scroll monorepo - ScrollChainABI, _ = ScrollChainMetaData.GetAbi() - ScrollChainV2ABI, _ = ScrollChainV2MetaData.GetAbi() - L1ScrollMessengerABI, _ = L1ScrollMessengerMetaData.GetAbi() - L1MessageQueueABI, _ = L1MessageQueueMetaData.GetAbi() - L2GasPriceOracleABI, _ = L2GasPriceOracleMetaData.GetAbi() - - L2ScrollMessengerABI, _ = L2ScrollMessengerMetaData.GetAbi() - L1BlockContainerABI, _ = L1BlockContainerMetaData.GetAbi() - L2MessageQueueABI, _ = L2MessageQueueMetaData.GetAbi() - L1GasPriceOracleABI, _ = L1GasPriceOracleMetaData.GetAbi() - - L1SentMessageEventSignature = L1ScrollMessengerABI.Events["SentMessage"].ID - L1RelayedMessageEventSignature = L1ScrollMessengerABI.Events["RelayedMessage"].ID - L1FailedRelayedMessageEventSignature = L1ScrollMessengerABI.Events["FailedRelayedMessage"].ID - - L1CommitBatchEventSignature = ScrollChainABI.Events["CommitBatch"].ID - L1FinalizeBatchEventSignature = ScrollChainABI.Events["FinalizeBatch"].ID - - L1QueueTransactionEventSignature = L1MessageQueueABI.Events["QueueTransaction"].ID - - L2SentMessageEventSignature = L2ScrollMessengerABI.Events["SentMessage"].ID - L2RelayedMessageEventSignature = L2ScrollMessengerABI.Events["RelayedMessage"].ID - L2FailedRelayedMessageEventSignature = L2ScrollMessengerABI.Events["FailedRelayedMessage"].ID - - L2AppendMessageEventSignature = L2MessageQueueABI.Events["AppendMessage"].ID + IL1ETHGatewayABI, _ = IL1ETHGatewayMetaData.GetAbi() + IL1ERC20GatewayABI, _ = IL1ERC20GatewayMetaData.GetAbi() + IL1ERC721GatewayABI, _ = IL1ERC721GatewayMetaData.GetAbi() + IL1ERC1155GatewayABI, _ = IL1ERC1155GatewayMetaData.GetAbi() -} + L1DepositETHSig = IL1ETHGatewayABI.Events["DepositETH"].ID + L1DepositERC20Sig = IL1ERC20GatewayABI.Events["DepositERC20"].ID + L1DepositERC721Sig = IL1ERC721GatewayABI.Events["DepositERC721"].ID + L1BatchDepositERC721Sig = IL1ERC721GatewayABI.Events["BatchDepositERC721"].ID + L1DepositERC1155Sig = IL1ERC1155GatewayABI.Events["DepositERC1155"].ID + L1BatchDepositERC1155Sig = IL1ERC1155GatewayABI.Events["BatchDepositERC1155"].ID -var L1ETHGatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DepositETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeWithdrawETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositETHAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", -} + IL2ETHGatewayABI, _ = IL2ETHGatewayMetaData.GetAbi() + IL2ERC20GatewayABI, _ = IL2ERC20GatewayMetaData.GetAbi() + IL2ERC721GatewayABI, _ = IL2ERC721GatewayMetaData.GetAbi() + IL2ERC1155GatewayABI, _ = IL2ERC1155GatewayMetaData.GetAbi() -var L1WETHGatewayMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_WETH\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2WETH\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeWithdrawERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"WETH\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2WETH\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", -} + L2WithdrawETHSig = IL2ETHGatewayABI.Events["WithdrawETH"].ID + L2WithdrawERC20Sig = IL2ERC20GatewayABI.Events["WithdrawERC20"].ID + L2WithdrawERC721Sig = IL2ERC721GatewayABI.Events["WithdrawERC721"].ID + L2BatchWithdrawERC721Sig = IL2ERC721GatewayABI.Events["BatchWithdrawERC721"].ID + L2WithdrawERC1155Sig = IL2ERC1155GatewayABI.Events["WithdrawERC1155"].ID + L2BatchWithdrawERC1155Sig = IL2ERC1155GatewayABI.Events["BatchWithdrawERC1155"].ID -var L1StandardERC20GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeWithdrawERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2TokenImplementation\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2TokenFactory\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2TokenFactory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2TokenImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", -} + IL1ScrollMessengerABI, _ = IL1ScrollMessengerMetaData.GetAbi() -var L2ETHGatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeDepositETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"WithdrawETH\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeDepositETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawETHAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", -} + L1SentMessageEventSig = IL1ScrollMessengerABI.Events["SentMessage"].ID + L1RelayedMessageEventSig = IL1ScrollMessengerABI.Events["RelayedMessage"].ID + L1FailedRelayedMessageEventSig = IL1ScrollMessengerABI.Events["FailedRelayedMessage"].ID -var L2WETHGatewayMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_WETH\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1WETH\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeDepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"WithdrawERC20\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"WETH\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeDepositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"getL1ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1WETH\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", -} + IL2ScrollMessengerABI, _ = IL2ScrollMessengerMetaData.GetAbi() -var L2StandardERC20GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeDepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"WithdrawERC20\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeDepositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"getL1ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_tokenFactory\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tokenFactory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", -} + L2SentMessageEventSig = IL2ScrollMessengerABI.Events["SentMessage"].ID + L2RelayedMessageEventSig = IL2ScrollMessengerABI.Events["RelayedMessage"].ID + L2FailedRelayedMessageEventSig = IL2ScrollMessengerABI.Events["FailedRelayedMessage"].ID -var L1CustomERC20GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeWithdrawERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"UpdateTokenMapping\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"updateTokenMapping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", -} + IScrollChainABI, _ = IScrollChainMetaData.GetAbi() -var L1ERC721GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeWithdrawERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"UpdateTokenMapping\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"updateTokenMapping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", -} + L1CommitBatchEventSig = IScrollChainABI.Events["CommitBatch"].ID + L1RevertBatchEventSig = IScrollChainABI.Events["RevertBatch"].ID + L1FinalizeBatchEventSig = IScrollChainABI.Events["FinalizeBatch"].ID + + IL1MessageQueueABI, _ = IL1MessageQueueMetaData.GetAbi() -var L1ERC1155GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"BatchDepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"DepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"FinalizeBatchWithdrawERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"FinalizeWithdrawERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"UpdateTokenMapping\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchDepositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchDepositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"finalizeBatchWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"finalizeWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC1155BatchReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC1155Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"updateTokenMapping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + L1QueueTransactionEventSig = IL1MessageQueueABI.Events["QueueTransaction"].ID + L1DequeueTransactionEventSig = IL1MessageQueueABI.Events["DequeueTransaction"].ID + L1DropTransactionEventSig = IL1MessageQueueABI.Events["DropTransaction"].ID } -var L2CustomERC20GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeDepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"UpdateTokenMapping\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"WithdrawERC20\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeDepositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"}],\"name\":\"getL1ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"updateTokenMapping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", +var IL1ETHGatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DepositETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeWithdrawETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RefundETH\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositETHAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", } -var L2ERC721GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"BatchWithdrawERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"FinalizeBatchDepositERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"FinalizeDepositERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"UpdateTokenMapping\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"WithdrawERC721\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"finalizeBatchDepositERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"finalizeDepositERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC721Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"updateTokenMapping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", +var IL1ERC20GatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"DepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeWithdrawERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RefundERC20\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } -var L2ERC1155GatewayMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"BatchWithdrawERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"FinalizeBatchDepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FinalizeDepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"UpdateTokenMapping\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawERC1155\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"finalizeBatchDepositERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"finalizeDepositERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC1155BatchReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC1155Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"updateTokenMapping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", +var IL1ERC721GatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"BatchDepositERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"BatchRefundERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"DepositERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"FinalizeBatchWithdrawERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"FinalizeWithdrawERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"RefundERC721\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchDepositERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchDepositERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"finalizeBatchWithdrawERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"finalizeWithdrawERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } -// scroll monorepo -// ScrollChainMetaData contains all meta data concerning the ScrollChain contract. -var ScrollChainMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldMaxNumL2TxInChunk\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newMaxNumL2TxInChunk\",\"type\":\"uint256\"}],\"name\":\"UpdateMaxNumL2TxInChunk\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateProver\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateSequencer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"_chunks\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"_skippedL1MessageBitmap\",\"type\":\"bytes\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"_postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"_withdrawRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"_aggrProof\",\"type\":\"bytes\"}],\"name\":\"finalizeBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"_stateRoot\",\"type\":\"bytes32\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_maxNumL2TxInChunk\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isProver\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isSequencer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"layer2ChainId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxNumL2TxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxNumL2TxInChunk\",\"type\":\"uint256\"}],\"name\":\"updateMaxNumL2TxInChunk\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"updateProver\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"updateSequencer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +var IL1ERC1155GatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"BatchDepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"BatchRefundERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"DepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"FinalizeBatchWithdrawERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"FinalizeWithdrawERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"RefundERC1155\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchDepositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchDepositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"depositERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"_amounts\",\"type\":\"uint256[]\"}],\"name\":\"finalizeBatchWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"finalizeWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } -// ScrollChainV2MetaData contains all meta data concerning the ScrollChain contract. -var ScrollChainV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_chainId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldMaxNumL2TxInChunk\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newMaxNumL2TxInChunk\",\"type\":\"uint256\"}],\"name\":\"UpdateMaxNumL2TxInChunk\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateProver\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"UpdateSequencer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldVerifier\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newVerifier\",\"type\":\"address\"}],\"name\":\"UpdateVerifier\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"_chunks\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"_skippedL1MessageBitmap\",\"type\":\"bytes\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"_prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"_postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"_withdrawRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"_aggrProof\",\"type\":\"bytes\"}],\"name\":\"finalizeBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"_stateRoot\",\"type\":\"bytes32\"}],\"name\":\"importGenesisBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_messageQueue\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifier\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_maxNumL2TxInChunk\",\"type\":\"uint256\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isProver\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isSequencer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"layer2ChainId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxNumL2TxInChunk\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageQueue\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxNumL2TxInChunk\",\"type\":\"uint256\"}],\"name\":\"updateMaxNumL2TxInChunk\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"updateProver\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_account\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_status\",\"type\":\"bool\"}],\"name\":\"updateSequencer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newVerifier\",\"type\":\"address\"}],\"name\":\"updateVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"verifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"withdrawRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +var IL2ETHGatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeDepositETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"WithdrawETH\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeDepositETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawETHAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", } -// L1ScrollMessengerMetaData contains all meta data concerning the L1ScrollMessenger contract. -var L1ScrollMessengerMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"FailedRelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"RelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"SentMessage\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"merkleProof\",\"type\":\"bytes\"}],\"internalType\":\"structIL1ScrollMessenger.L2MessageProof\",\"name\":\"proof\",\"type\":\"tuple\"}],\"name\":\"relayMessageWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"queueIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"oldGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"newGasLimit\",\"type\":\"uint32\"}],\"name\":\"replayMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"sendMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"xDomainMessageSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +var IL2ERC20GatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"FinalizeDepositERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"WithdrawERC20\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"finalizeDepositERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"}],\"name\":\"getL1ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"getL2ERC20Address\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20AndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", } -// L1MessageQueueMetaData contains all meta data concerning the L1MessageQueue contract. -var L1MessageQueueMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"queueIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"QueueTransaction\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"appendCrossDomainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"appendEnforcedTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"estimateCrossDomainMessageFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"queueIndex\",\"type\":\"uint256\"}],\"name\":\"getCrossDomainMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextCrossDomainMessageIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +var IL2ERC721GatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"BatchWithdrawERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"FinalizeBatchDepositERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"FinalizeDepositERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"UpdateTokenMapping\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"WithdrawERC721\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpart\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"_tokenIds\",\"type\":\"uint256[]\"}],\"name\":\"finalizeBatchDepositERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"finalizeDepositERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_counterpart\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"onERC721Received\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tokenMapping\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"}],\"name\":\"updateTokenMapping\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC721\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", } -// L2GasPriceOracleMetaData contains all meta data concerning the L2GasPriceOracle contract. -var L2GasPriceOracleMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l2BaseFee\",\"type\":\"uint256\"}],\"name\":\"L2BaseFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"overhead\",\"type\":\"uint256\"}],\"name\":\"OverheadUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"scalar\",\"type\":\"uint256\"}],\"name\":\"ScalarUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gasLimit\",\"type\":\"uint256\"}],\"name\":\"estimateCrossDomainMessageFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1GasUsed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1BaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2BaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l2BaseFee\",\"type\":\"uint256\"}],\"name\":\"setL2BaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"}],\"name\":\"setOverhead\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"}],\"name\":\"setScalar\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +var IL2ERC1155GatewayMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"BatchWithdrawERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"FinalizeBatchDepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FinalizeDepositERC1155\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawERC1155\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"batchWithdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"tokenIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"finalizeBatchDepositERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l2Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"finalizeDepositERC1155\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"withdrawERC1155\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", } -// L2ScrollMessengerMetaData contains all meta data concerning the L2ScrollMessenger contract. -var L2ScrollMessengerMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"FailedRelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"RelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"SentMessage\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"stateRootProof\",\"type\":\"bytes\"}],\"internalType\":\"structIL2ScrollMessenger.L1MessageProof\",\"name\":\"proof\",\"type\":\"tuple\"}],\"name\":\"retryMessageWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"sendMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"xDomainMessageSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +var IL1ScrollMessengerMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"FailedRelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"RelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"SentMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldMaxReplayTimes\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newMaxReplayTimes\",\"type\":\"uint256\"}],\"name\":\"UpdateMaxReplayTimes\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"dropMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"merkleProof\",\"type\":\"bytes\"}],\"internalType\":\"structIL1ScrollMessenger.L2MessageProof\",\"name\":\"proof\",\"type\":\"tuple\"}],\"name\":\"relayMessageWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"newGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"refundAddress\",\"type\":\"address\"}],\"name\":\"replayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"refundAddress\",\"type\":\"address\"}],\"name\":\"sendMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"sendMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"xDomainMessageSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } -// L1BlockContainerMetaData contains all meta data concerning the L1BlockContainer contract. -var L1BlockContainerMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockHeight\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"blockTimestamp\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"baseFee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"name\":\"ImportBlock\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"name\":\"getBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"name\":\"getStateRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"blockHeaderRLP\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"updateGasPriceOracle\",\"type\":\"bool\"}],\"name\":\"importBlockHeader\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestBaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +var IL2ScrollMessengerMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"FailedRelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"RelayedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"SentMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldMaxFailedExecutionTimes\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newMaxFailedExecutionTimes\",\"type\":\"uint256\"}],\"name\":\"UpdateMaxFailedExecutionTimes\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"refundAddress\",\"type\":\"address\"}],\"name\":\"sendMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"sendMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"xDomainMessageSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } -// L2MessageQueueMetaData contains all meta data concerning the L2MessageQueue contract. -var L2MessageQueueMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"messageHash\",\"type\":\"bytes32\"}],\"name\":\"AppendMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_messageHash\",\"type\":\"bytes32\"}],\"name\":\"appendMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"branches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messenger\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextMessageIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_messenger\",\"type\":\"address\"}],\"name\":\"updateMessenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +var IScrollChainMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"CommitBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"}],\"name\":\"FinalizeBatch\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"batchHash\",\"type\":\"bytes32\"}],\"name\":\"RevertBatch\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"parentBatchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"chunks\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"skippedL1MessageBitmap\",\"type\":\"bytes\"}],\"name\":\"commitBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"committedBatches\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"prevStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"postStateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"withdrawRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"aggrProof\",\"type\":\"bytes\"}],\"name\":\"finalizeBatchWithProof\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"finalizedStateRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"isBatchFinalized\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFinalizedBatchIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"batchHeader\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"}],\"name\":\"revertBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchIndex\",\"type\":\"uint256\"}],\"name\":\"withdrawRoots\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } -// L1GasPriceOracleMetaData contains all meta data concerning the L1GasPriceOracle contract. -var L1GasPriceOracleMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"L1BaseFeeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"overhead\",\"type\":\"uint256\"}],\"name\":\"OverheadUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"scalar\",\"type\":\"uint256\"}],\"name\":\"ScalarUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getL1GasUsed\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l1BaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"overhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"scalar\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l1BaseFee\",\"type\":\"uint256\"}],\"name\":\"setL1BaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_overhead\",\"type\":\"uint256\"}],\"name\":\"setOverhead\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_scalar\",\"type\":\"uint256\"}],\"name\":\"setScalar\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +var IL1MessageQueueMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"skippedBitmap\",\"type\":\"uint256\"}],\"name\":\"DequeueTransaction\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"DropTransaction\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"queueIndex\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"QueueTransaction\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"appendCrossDomainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"appendEnforcedTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_calldata\",\"type\":\"bytes\"}],\"name\":\"calculateIntrinsicGasFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"queueIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"computeTransactionHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"dropCrossDomainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"estimateCrossDomainMessageFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"queueIndex\",\"type\":\"uint256\"}],\"name\":\"getCrossDomainMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"queueIndex\",\"type\":\"uint256\"}],\"name\":\"isMessageDropped\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"queueIndex\",\"type\":\"uint256\"}],\"name\":\"isMessageSkipped\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextCrossDomainMessageIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pendingQueueIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"count\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"skippedBitmap\",\"type\":\"uint256\"}],\"name\":\"popCrossDomainMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } -// DepositETH represents a DepositETH event type DepositETH struct { From common.Address To common.Address Amount *big.Int - Data []byte } type ERC20MessageEvent struct { @@ -262,7 +166,6 @@ type ERC20MessageEvent struct { From common.Address To common.Address Amount *big.Int - Data []byte } type ERC721MessageEvent struct { @@ -270,8 +173,6 @@ type ERC721MessageEvent struct { L2Token common.Address From common.Address To common.Address - Amount *big.Int - Data []byte TokenID *big.Int } @@ -301,9 +202,6 @@ type BatchERC1155MessageEvent struct { TokenAmounts []*big.Int } -// scroll monorepo - -// L1SentMessageEvent represents a SentMessage event raised by the L1ScrollMessenger contract. type L1SentMessageEvent struct { Sender common.Address Target common.Address @@ -313,32 +211,14 @@ type L1SentMessageEvent struct { Message []byte } -// L1FailedRelayedMessageEvent represents a FailedRelayedMessage event raised by the L1ScrollMessenger contract. -type L1FailedRelayedMessageEvent struct { - MessageHash common.Hash -} - -// L1RelayedMessageEvent represents a RelayedMessage event raised by the L1ScrollMessenger contract. type L1RelayedMessageEvent struct { MessageHash common.Hash } -// L2AppendMessageEvent represents a AppendMessage event raised by the L2MessageQueue contract. -type L2AppendMessageEvent struct { - Index *big.Int +type L1FailedRelayedMessageEvent struct { MessageHash common.Hash } -// L2ImportBlockEvent represents a ImportBlock event raised by the L1BlockContainer contract. -type L2ImportBlockEvent struct { - BlockHash common.Hash - BlockHeight *big.Int - BlockTimestamp *big.Int - BaseFee *big.Int - StateRoot common.Hash -} - -// L2SentMessageEvent represents a SentMessage event raised by the L2ScrollMessenger contract. type L2SentMessageEvent struct { Sender common.Address Target common.Address @@ -348,41 +228,42 @@ type L2SentMessageEvent struct { Message []byte } -// L2FailedRelayedMessageEvent represents a FailedRelayedMessage event raised by the L2ScrollMessenger contract. -type L2FailedRelayedMessageEvent struct { - MessageHash common.Hash -} - -// L2RelayedMessageEvent represents a RelayedMessage event raised by the L2ScrollMessenger contract. type L2RelayedMessageEvent struct { MessageHash common.Hash } -// IScrollChainBatch is an auto generated low-level Go binding around an user-defined struct. -type IScrollChainBatch struct { - Blocks []IScrollChainBlockContext - PrevStateRoot common.Hash - NewStateRoot common.Hash - WithdrawTrieRoot common.Hash - BatchIndex uint64 - ParentBatchHash common.Hash - L2Transactions []byte +type L1CommitBatchEvent struct { + BatchIndex *big.Int + BatchHash common.Hash } -// L1CommitBatchEvent represents a CommitBatch event raised by the ScrollChain contract. -type L1CommitBatchEvent struct { +type L1RevertBatchEvent struct { BatchIndex *big.Int BatchHash common.Hash } -// IScrollChainBlockContext is an auto generated low-level Go binding around an user-defined struct. -type IScrollChainBlockContext struct { - BlockHash common.Hash - ParentHash common.Hash - BlockNumber uint64 - Timestamp uint64 - BaseFee *big.Int - GasLimit uint64 - NumTransactions uint16 - NumL1Messages uint16 +type L1FinalizeBatchEvent struct { + BatchIndex *big.Int + BatchHash common.Hash + StateRoot common.Hash + WithdrawRoot common.Hash +} + +type L1QueueTransactionEvent struct { + Sender common.Address + Target common.Address + Value *big.Int + QueueIndex uint64 + GasLimit *big.Int + Data []byte +} + +type L1DequeueTransactionEvent struct { + StartIndex *big.Int + Count *big.Int + SkippedBitmap *big.Int +} + +type L1DropTransactionEvent struct { + Index *big.Int } diff --git a/bridge-history-api/cmd/backend_server/app/app.go b/bridge-history-api/cmd/backend_server/app/app.go index 790a7c3c30..18463071aa 100644 --- a/bridge-history-api/cmd/backend_server/app/app.go +++ b/bridge-history-api/cmd/backend_server/app/app.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/gin-gonic/gin" + "github.com/go-redis/redis/v8" "github.com/prometheus/client_golang/prometheus" "github.com/urfave/cli/v2" @@ -51,16 +52,20 @@ func action(ctx *cli.Context) error { log.Error("failed to close db", "err", err) } }() + redis := redis.NewClient(&redis.Options{ + Addr: cfg.Redis.Address, + Password: cfg.Redis.Password, + DB: cfg.Redis.DB, + }) // init Prover Stats API - port := cfg.Server.HostPort + controller.InitController(db, redis) router := gin.Default() - controller.InitController(db) - registry := prometheus.DefaultRegisterer route.Route(router, cfg, registry) go func() { + port := cfg.Server.HostPort if runServerErr := router.Run(fmt.Sprintf(":%s", port)); runServerErr != nil { log.Crit("run http server failure", "error", runServerErr) } diff --git a/bridge-history-api/cmd/cross_msg_fetcher/app/app.go b/bridge-history-api/cmd/cross_msg_fetcher/app/app.go index d4dfde2519..df6dc018d7 100644 --- a/bridge-history-api/cmd/cross_msg_fetcher/app/app.go +++ b/bridge-history-api/cmd/cross_msg_fetcher/app/app.go @@ -6,15 +6,12 @@ import ( "os" "os/signal" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" "github.com/urfave/cli/v2" "bridge-history-api/config" - "bridge-history-api/crossmsg" - "bridge-history-api/crossmsg/messageproof" - "bridge-history-api/orm" + "bridge-history-api/crossmessage/controller/messagefetcher" "bridge-history-api/utils" ) @@ -37,7 +34,6 @@ func init() { } func action(ctx *cli.Context) error { - // Load config file. cfgFile := ctx.String(utils.ConfigFileFlag.Name) cfg, err := config.NewConfig(cfgFile) if err != nil { @@ -46,13 +42,14 @@ func action(ctx *cli.Context) error { subCtx, cancel := context.WithCancel(ctx.Context) defer cancel() - l1client, err := ethclient.Dial(cfg.L1.Endpoint) + l1Client, err := ethclient.Dial(cfg.L1.Endpoint) if err != nil { - log.Crit("failed to connect l1 geth", "config file", cfgFile, "error", err) + log.Crit("failed to connect to l1 geth", "endpoint", cfg.L1.Endpoint, "err", err) } - l2client, err := ethclient.Dial(cfg.L2.Endpoint) + + l2Client, err := ethclient.Dial(cfg.L2.Endpoint) if err != nil { - log.Crit("failed to connect l2 geth", "config file", cfgFile, "error", err) + log.Crit("failed to connect to l2 geth", "endpoint", cfg.L2.Endpoint, "err", err) } db, err := utils.InitDB(cfg.DB) @@ -68,86 +65,17 @@ func action(ctx *cli.Context) error { log.Crit("failed to connect to db", "config file", cfgFile, "error", err) } - l1worker := &crossmsg.FetchEventWorker{F: crossmsg.L1FetchAndSaveEvents, G: crossmsg.GetLatestL1ProcessedHeight, Name: "L1 events fetch Worker"} - - l2worker := &crossmsg.FetchEventWorker{F: crossmsg.L2FetchAndSaveEvents, G: crossmsg.GetLatestL2ProcessedHeight, Name: "L2 events fetch Worker"} - - l1AddressList := []common.Address{ - common.HexToAddress(cfg.L1.CustomERC20GatewayAddr), - common.HexToAddress(cfg.L1.ERC721GatewayAddr), - common.HexToAddress(cfg.L1.ERC1155GatewayAddr), - common.HexToAddress(cfg.L1.MessengerAddr), - common.HexToAddress(cfg.L1.ETHGatewayAddr), - common.HexToAddress(cfg.L1.StandardERC20Gateway), - common.HexToAddress(cfg.L1.WETHGatewayAddr), - } - - if cfg.L1.USDCGatewayAddr != "" { - l1AddressList = append(l1AddressList, common.HexToAddress(cfg.L1.USDCGatewayAddr)) - } - - if cfg.L1.LIDOGatewayAddr != "" { - l1AddressList = append(l1AddressList, common.HexToAddress(cfg.L1.LIDOGatewayAddr)) - } - - if cfg.L2.DAIGatewayAddr != "" { - l1AddressList = append(l1AddressList, common.HexToAddress(cfg.L1.DAIGatewayAddr)) - } - - l2AddressList := []common.Address{ - common.HexToAddress(cfg.L2.CustomERC20GatewayAddr), - common.HexToAddress(cfg.L2.ERC721GatewayAddr), - common.HexToAddress(cfg.L2.ERC1155GatewayAddr), - common.HexToAddress(cfg.L2.MessengerAddr), - common.HexToAddress(cfg.L2.ETHGatewayAddr), - common.HexToAddress(cfg.L2.StandardERC20Gateway), - common.HexToAddress(cfg.L2.WETHGatewayAddr), - } - - if cfg.L2.USDCGatewayAddr != "" { - l2AddressList = append(l2AddressList, common.HexToAddress(cfg.L2.USDCGatewayAddr)) - } - - if cfg.L2.LIDOGatewayAddr != "" { - l2AddressList = append(l2AddressList, common.HexToAddress(cfg.L2.LIDOGatewayAddr)) - } - - if cfg.L2.DAIGatewayAddr != "" { - l2AddressList = append(l2AddressList, common.HexToAddress(cfg.L2.DAIGatewayAddr)) - } - - l1crossMsgFetcher, err := crossmsg.NewMsgFetcher(subCtx, cfg.L1, db, l1client, l1worker, l1AddressList, crossmsg.L1ReorgHandling) + l1MessageFetcher, err := messagefetcher.NewL1MessageFetcher(subCtx, cfg.L1, db, l1Client) if err != nil { log.Crit("failed to create l1 cross message fetcher", "error", err) } + go l1MessageFetcher.Start() - go l1crossMsgFetcher.Start() - defer l1crossMsgFetcher.Stop() - - l2crossMsgFetcher, err := crossmsg.NewMsgFetcher(subCtx, cfg.L2, db, l2client, l2worker, l2AddressList, crossmsg.L2ReorgHandling) + l2MessageFetcher, err := messagefetcher.NewL2MessageFetcher(subCtx, cfg.L2, db, l2Client) if err != nil { - log.Crit("failed to create l2 cross message fetcher", "error", err) + log.Crit("failed to create l1 cross message fetcher", "error", err) } - - go l2crossMsgFetcher.Start() - defer l2crossMsgFetcher.Stop() - - CrossMsgOrm := orm.NewCrossMsg(db) - - // BlockTimestamp fetcher for l1 and l2 - l1BlockTimeFetcher := crossmsg.NewBlockTimestampFetcher(subCtx, cfg.L1.Confirmation, int(cfg.L1.BlockTime), l1client, CrossMsgOrm.UpdateL1BlockTimestamp, CrossMsgOrm.GetL1EarliestNoBlockTimestampHeight) - go l1BlockTimeFetcher.Start() - defer l1BlockTimeFetcher.Stop() - - l2BlockTimeFetcher := crossmsg.NewBlockTimestampFetcher(subCtx, cfg.L2.Confirmation, int(cfg.L2.BlockTime), l2client, CrossMsgOrm.UpdateL2BlockTimestamp, CrossMsgOrm.GetL2EarliestNoBlockTimestampHeight) - go l2BlockTimeFetcher.Start() - defer l2BlockTimeFetcher.Stop() - - // Proof updater and batch fetcher - l2msgProofUpdater := messageproof.NewMsgProofUpdater(subCtx, cfg.L1.Confirmation, cfg.BatchInfoFetcher.BatchIndexStartBlock, db) - batchFetcher := crossmsg.NewBatchInfoFetcher(subCtx, common.HexToAddress(cfg.BatchInfoFetcher.ScrollChainAddr), cfg.BatchInfoFetcher.BatchIndexStartBlock, cfg.L1.Confirmation, int(cfg.L1.BlockTime), l1client, db, l2msgProofUpdater) - go batchFetcher.Start() - defer batchFetcher.Stop() + go l2MessageFetcher.Start() // Catch CTRL-C to ensure a graceful shutdown. interrupt := make(chan os.Signal, 1) diff --git a/bridge-history-api/config.json b/bridge-history-api/config.json index 65876314f8..07aed9c282 100644 --- a/bridge-history-api/config.json +++ b/bridge-history-api/config.json @@ -1,13 +1,11 @@ { - "batchInfoFetcher": { - "batchIndexStartBlock": 9091265, - "ScrollChainAddr": "0x1799c3Df650caB9DFBb228C971016707D8f8721D" - }, "l1": { + "chain_id": 1, "confirmation": 64, "endpoint": "https://rpc.ankr.com/eth", "startHeight": 18310747, "blockTime": 10, + "fetchLimit": 30, "MessengerAddr": "0x7318152B19c3c97c886D5ee6C2525E62ce8e2abA", "ETHGatewayAddr": "0xd165b42d857eae2915625819464a2a1f91E5d0A5", "WETHGatewayAddr": "0xb0255e4C1a919619D1CafBA51021d638c4F71b89", @@ -17,13 +15,18 @@ "ERC1155GatewayAddr": "0xCeE721789FAA05c7F4463efB664520656aB7C7d5", "USDCGatewayAddr": "0x37ba659D6CC380D12Fb96567CC52FC8e1DF4E334", "LIDOGatewayAddr": "0x892dDB2899325aBBA1fD00FDA8249B40Cbbc33F9", - "DAIGatewayAddr": "0xD8dD7787f89c7E6243AD32E0d0cCf460243C8130" + "DAIGatewayAddr": "0xD8dD7787f89c7E6243AD32E0d0cCf460243C8130", + "ScrollChainAddr": "0x1799c3Df650caB9DFBb228C971016707D8f8721D", + "GatewayRouterAddr": "0xF8B1378579659D8F7EE5f3C929c2f3E332E41Fd6", + "MessageQueueAddr": "0xF0B2293F5D834eAe920c6974D50957A1732de763" }, "l2": { + "chain_id": 534352, "confirmation": 1, "endpoint": "http://mainnet-l2geth-internal-1.mainnet.scroll.tech:8545", - "blockTime": 3, "startHeight": 0, + "blockTime": 3, + "fetchLimit": 100, "MessengerAddr": "0xda7c91Ed60DACD28Cb97B180108958c9ACC7698a", "ETHGatewayAddr": "0x567671187b5FFbcDFe0B6EcF3e56C05508a31A87", "WETHGatewayAddr": "0x3b03aE2F27d62E0B2b6740CA20Fc07Af4338B791", @@ -33,7 +36,8 @@ "ERC1155GatewayAddr": "0xfF14870512e42BFb85a9B7bEfDc06e9aB5A37269", "USDCGatewayAddr": "0x97D5799CDC8eE2A7452913d7548c7cEE285719FA", "LIDOGatewayAddr": "0xE9c5C9f67ec7B773fC76440845751F657bb953FF", - "DAIGatewayAddr": "0xC5034eB8F682b73F93C9246aa95A8eBbF82793aA" + "DAIGatewayAddr": "0xC5034eB8F682b73F93C9246aa95A8eBbF82793aA", + "GatewayRouterAddr": "0x4C0926FF5252A435FD19e10ED15e5a249Ba19d79" }, "db": { "dsn": "postgres://postgres:1234@localhost:5444/test?sslmode=disable", @@ -41,6 +45,11 @@ "maxOpenNum": 200, "maxIdleNum": 20 }, + "redis": { + "address": "localhost:6379", + "password": "", + "db": 0 + }, "server": { "hostPort": "20006" } diff --git a/bridge-history-api/config/config.go b/bridge-history-api/config/config.go index 0cc97e1f56..40f05ce79d 100644 --- a/bridge-history-api/config/config.go +++ b/bridge-history-api/config/config.go @@ -6,28 +6,14 @@ import ( "path/filepath" ) -// BatchInfoFetcherConfig is the configuration of BatchInfoFetcher -type BatchInfoFetcherConfig struct { - BatchIndexStartBlock uint64 `json:"batchIndexStartBlock"` - ScrollChainAddr string `json:"ScrollChainAddr"` -} - -// DBConfig db config -type DBConfig struct { - // data source name - DSN string `json:"dsn"` - DriverName string `json:"driverName"` - - MaxOpenNum int `json:"maxOpenNum"` - MaxIdleNum int `json:"maxIdleNum"` -} - // LayerConfig is the configuration of Layer1/Layer2 type LayerConfig struct { + ChainID uint64 `json:"chain_id"` Confirmation uint64 `json:"confirmation"` Endpoint string `json:"endpoint"` StartHeight uint64 `json:"startHeight"` BlockTime int64 `json:"blockTime"` + FetchLimit uint64 `json:"fetchLimit"` MessengerAddr string `json:"MessengerAddr"` ETHGatewayAddr string `json:"ETHGatewayAddr"` WETHGatewayAddr string `json:"WETHGatewayAddr"` @@ -35,9 +21,27 @@ type LayerConfig struct { LIDOGatewayAddr string `json:"LIDOGatewayAddr"` DAIGatewayAddr string `json:"DAIGatewayAddr"` StandardERC20Gateway string `json:"StandardERC20Gateway"` + CustomERC20GatewayAddr string `json:"CustomERC20GatewayAddr"` ERC721GatewayAddr string `json:"ERC721GatewayAddr"` ERC1155GatewayAddr string `json:"ERC1155GatewayAddr"` - CustomERC20GatewayAddr string `json:"CustomERC20GatewayAddr"` + ScrollChainAddr string `json:"ScrollChainAddr"` + GatewayRouterAddr string `json:"GatewayRouterAddr"` + MessageQueueAddr string `json:"MessageQueueAddr"` +} + +// DBConfig db config +type DBConfig struct { + DSN string `json:"dsn"` + DriverName string `json:"driverName"` + MaxOpenNum int `json:"maxOpenNum"` + MaxIdleNum int `json:"maxIdleNum"` +} + +// RedisConfig redis config +type RedisConfig struct { + Address string `json:"address"` + Password string `json:"password"` + DB int `json:"db"` } // ServerConfig is the configuration of the bridge history backend server port @@ -47,14 +51,11 @@ type ServerConfig struct { // Config is the configuration of the bridge history backend type Config struct { - // chain config - L1 *LayerConfig `json:"l1"` - L2 *LayerConfig `json:"l2"` - - // data source name - DB *DBConfig `json:"db"` - Server *ServerConfig `json:"server"` - BatchInfoFetcher *BatchInfoFetcherConfig `json:"batchInfoFetcher"` + L1 *LayerConfig `json:"l1"` + L2 *LayerConfig `json:"l2"` + DB *DBConfig `json:"db"` + Redis *RedisConfig `json:"redis"` + Server *ServerConfig `json:"server"` } // NewConfig returns a new instance of Config. diff --git a/bridge-history-api/crossmessage/controller/messagefetcher/l1_message_fetcher.go b/bridge-history-api/crossmessage/controller/messagefetcher/l1_message_fetcher.go new file mode 100644 index 0000000000..3f6e029a51 --- /dev/null +++ b/bridge-history-api/crossmessage/controller/messagefetcher/l1_message_fetcher.go @@ -0,0 +1,231 @@ +package messagefetcher + +import ( + "context" + "math/big" + "time" + + geth "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "gorm.io/gorm" + + backendabi "bridge-history-api/abi" + "bridge-history-api/config" + "bridge-history-api/crossmessage/logic" + "bridge-history-api/orm" + "bridge-history-api/utils" +) + +// L1MessageFetcher fetches cross message events from L1 and saves them to database. +type L1MessageFetcher struct { + ctx context.Context + cfg *config.LayerConfig + db *gorm.DB + crossMessageOrm *orm.CrossMessage + client *ethclient.Client + addressList []common.Address +} + +// NewL1MessageFetcher creates a new L1MessageFetcher instance. +func NewL1MessageFetcher(ctx context.Context, cfg *config.LayerConfig, db *gorm.DB, client *ethclient.Client) (*L1MessageFetcher, error) { + addressList := []common.Address{ + common.HexToAddress(cfg.CustomERC20GatewayAddr), + common.HexToAddress(cfg.ERC721GatewayAddr), + common.HexToAddress(cfg.ERC1155GatewayAddr), + common.HexToAddress(cfg.MessengerAddr), + common.HexToAddress(cfg.ETHGatewayAddr), + common.HexToAddress(cfg.StandardERC20Gateway), + common.HexToAddress(cfg.WETHGatewayAddr), + common.HexToAddress(cfg.ScrollChainAddr), + common.HexToAddress(cfg.MessageQueueAddr), + } + + if cfg.USDCGatewayAddr != "" { + addressList = append(addressList, common.HexToAddress(cfg.USDCGatewayAddr)) + } + + if cfg.LIDOGatewayAddr != "" { + addressList = append(addressList, common.HexToAddress(cfg.LIDOGatewayAddr)) + } + + if cfg.DAIGatewayAddr != "" { + addressList = append(addressList, common.HexToAddress(cfg.DAIGatewayAddr)) + } + + return &L1MessageFetcher{ + ctx: ctx, + cfg: cfg, + db: db, + crossMessageOrm: orm.NewCrossMessage(db), + client: client, + addressList: addressList, + }, nil +} + +// Start starts the l1 message fetching process. +func (c *L1MessageFetcher) Start() { + tick := time.NewTicker(time.Duration(c.cfg.BlockTime) * time.Second) + go func() { + for { + select { + case <-c.ctx.Done(): + tick.Stop() + return + case <-tick.C: + c.fetchAndSaveEvents(c.cfg.Confirmation) + } + } + }() +} + +func (c *L1MessageFetcher) fetchAndSaveEvents(confirmation uint64) { + endHeight, err := utils.GetBlockNumber(c.ctx, c.client, confirmation) + if err != nil { + log.Error("failed to get L1 safe block number", "err", err) + return + } + + message, err := c.crossMessageOrm.GetLatestMessage(c.ctx, orm.MessageTypeL1) + if err != nil { + log.Error("failed to get L1 cross message processed height", "err", err) + return + } + startHeight := c.cfg.StartHeight + if message != nil && message.L1BlockNumber+1 > startHeight { + startHeight = message.L1BlockNumber + 1 + } + log.Info("fetch and save missing L1 events", "start height", startHeight) + + for from := startHeight; from <= endHeight; from += c.cfg.FetchLimit { + to := from + c.cfg.FetchLimit - 1 + if to > endHeight { + to = endHeight + } + err = c.doFetchAndSaveEvents(c.ctx, from, to, c.addressList) + if err != nil { + log.Error("failed to fetch and save L1 events", "err", err) + return + } + } +} + +func (c *L1MessageFetcher) doFetchAndSaveEvents(ctx context.Context, from uint64, to uint64, addrList []common.Address) error { + var l1FailedGatewayRouterTxs []*orm.CrossMessage + blockTimestampsMap := make(map[uint64]uint64) + for number := from; number <= to; number++ { + blockNumber := new(big.Int).SetUint64(number) + block, err := c.client.BlockByNumber(context.Background(), blockNumber) + if err != nil { + log.Error("failed to get block by number", "number", blockNumber.String(), "err", err) + return err + } + blockTimestampsMap[block.NumberU64()] = block.Time() + + for _, tx := range block.Transactions() { + to := tx.To() + if to == nil { + continue + } + toAddress := to.String() + if toAddress == c.cfg.GatewayRouterAddr { + receipt, err := c.client.TransactionReceipt(ctx, tx.Hash()) + if err != nil { + log.Error("Failed to get transaction receipt", "txHash", tx.Hash(), "err", err) + return err + } + + signer := types.NewLondonSigner(new(big.Int).SetUint64(c.cfg.ChainID)) + sender, err := signer.Sender(tx) + if err != nil { + log.Error("get sender failed", "chain id", c.cfg.ChainID, "tx hash", tx.Hash().String(), "err", err) + return err + } + + // Check if the transaction failed + if receipt.Status == types.ReceiptStatusFailed { + l1FailedGatewayRouterTxs = append(l1FailedGatewayRouterTxs, &orm.CrossMessage{ + MessageHash: tx.Hash().String(), + MessageType: int(orm.MessageTypeL1), + Sender: sender.String(), + Receiver: (*tx.To()).String(), + BlockTimestamp: block.Time(), + TxStatus: int(orm.TxStatusTypeSentFailed), + }) + } + } + } + } + + query := geth.FilterQuery{ + FromBlock: new(big.Int).SetUint64(from), // inclusive + ToBlock: new(big.Int).SetUint64(to), // inclusive + Addresses: addrList, + Topics: make([][]common.Hash, 1), + } + query.Topics[0] = make([]common.Hash, 13) + query.Topics[0][0] = backendabi.L1DepositETHSig + query.Topics[0][1] = backendabi.L1DepositERC20Sig + query.Topics[0][2] = backendabi.L1DepositERC721Sig + query.Topics[0][3] = backendabi.L1DepositERC1155Sig + query.Topics[0][4] = backendabi.L1SentMessageEventSig + query.Topics[0][5] = backendabi.L1RelayedMessageEventSig + query.Topics[0][6] = backendabi.L1FailedRelayedMessageEventSig + query.Topics[0][7] = backendabi.L1CommitBatchEventSig + query.Topics[0][8] = backendabi.L1RevertBatchEventSig + query.Topics[0][9] = backendabi.L1FinalizeBatchEventSig + query.Topics[0][10] = backendabi.L1QueueTransactionEventSig + query.Topics[0][11] = backendabi.L1DequeueTransactionEventSig + query.Topics[0][12] = backendabi.L1DropTransactionEventSig + + logs, err := c.client.FilterLogs(ctx, query) + if err != nil { + log.Error("failed to filter l1 event logs", "from", from, "to", to, "err", err) + return err + } + l1DepositMessages, l1RelayedMessages, err := logic.ParseL1CrossChainEventLogs(ctx, logs, blockTimestampsMap, c.client) + if err != nil { + log.Error("failed to parse l1 cross chain event logs", "from", from, "to", to, "err", err) + return err + } + l1BatchEvents, err := logic.ParseL1BatchEventLogs(ctx, logs, blockTimestampsMap, c.client) + if err != nil { + log.Error("failed to parse l1 batch event logs", "from", from, "to", to, "err", err) + return err + } + l1MessageQueueEvents, err := logic.ParseL1MessageQueueEventLogs(ctx, logs, blockTimestampsMap, c.client) + if err != nil { + log.Error("failed to parse l1 message queue event logs", "from", from, "to", to, "err", err) + return err + } + err = c.db.Transaction(func(tx *gorm.DB) error { + if txErr := c.crossMessageOrm.InsertMessages(ctx, l1DepositMessages, tx); txErr != nil { + log.Error("failed to insert l1 deposit messages", "from", from, "to", to, "err", txErr) + return txErr + } + if txErr := c.crossMessageOrm.UpdateL1RelayedMessagesOfL2Withdrawals(ctx, l1RelayedMessages, tx); txErr != nil { + log.Error("failed to update l1 relayed messages of l2 withdrawals", "from", from, "to", to, "err", txErr) + return txErr + } + if txErr := c.crossMessageOrm.UpdateBatchIndexOfL2Withdrawals(ctx, l1BatchEvents, tx); txErr != nil { + log.Error("failed to update batch index of l2 withdrawals", "from", from, "to", to, "err", txErr) + return txErr + } + if txErr := c.crossMessageOrm.UpdateL1MessageQueueEventsInfo(ctx, l1MessageQueueEvents, tx); txErr != nil { + log.Error("failed to insert l1 message queue events", "from", from, "to", to, "err", txErr) + return txErr + } + if txErr := c.crossMessageOrm.InsertMessages(ctx, l1FailedGatewayRouterTxs, tx); txErr != nil { + log.Error("failed to insert l1 failed gateway router transactions", "from", from, "to", to, "err", txErr) + return txErr + } + return nil + }) + if err != nil { + log.Error("failed to update db of l1 events", "from", from, "to", to, "err", err) + return err + } + return nil +} diff --git a/bridge-history-api/crossmessage/controller/messagefetcher/l2_message_fetcher.go b/bridge-history-api/crossmessage/controller/messagefetcher/l2_message_fetcher.go new file mode 100644 index 0000000000..2c32447627 --- /dev/null +++ b/bridge-history-api/crossmessage/controller/messagefetcher/l2_message_fetcher.go @@ -0,0 +1,237 @@ +package messagefetcher + +import ( + "context" + "fmt" + "math/big" + "time" + + geth "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "gorm.io/gorm" + + backendabi "bridge-history-api/abi" + "bridge-history-api/config" + "bridge-history-api/crossmessage/controller/messageproof" + "bridge-history-api/crossmessage/logic" + "bridge-history-api/orm" + "bridge-history-api/utils" +) + +// L2MessageFetcher fetches cross message events from L2 and saves them to database. +type L2MessageFetcher struct { + ctx context.Context + cfg *config.LayerConfig + db *gorm.DB + crossMessageOrm *orm.CrossMessage + client *ethclient.Client + addressList []common.Address +} + +// NewL2MessageFetcher creates a new L2MessageFetcher instance. +func NewL2MessageFetcher(ctx context.Context, cfg *config.LayerConfig, db *gorm.DB, client *ethclient.Client) (*L2MessageFetcher, error) { + addressList := []common.Address{ + common.HexToAddress(cfg.CustomERC20GatewayAddr), + common.HexToAddress(cfg.ERC721GatewayAddr), + common.HexToAddress(cfg.ERC1155GatewayAddr), + common.HexToAddress(cfg.MessengerAddr), + common.HexToAddress(cfg.ETHGatewayAddr), + common.HexToAddress(cfg.StandardERC20Gateway), + common.HexToAddress(cfg.WETHGatewayAddr), + } + + if cfg.USDCGatewayAddr != "" { + addressList = append(addressList, common.HexToAddress(cfg.USDCGatewayAddr)) + } + + if cfg.LIDOGatewayAddr != "" { + addressList = append(addressList, common.HexToAddress(cfg.LIDOGatewayAddr)) + } + + if cfg.DAIGatewayAddr != "" { + addressList = append(addressList, common.HexToAddress(cfg.DAIGatewayAddr)) + } + + return &L2MessageFetcher{ + ctx: ctx, + cfg: cfg, + db: db, + crossMessageOrm: orm.NewCrossMessage(db), + client: client, + addressList: addressList, + }, nil +} + +// Start starts the l2 message fetching process. +func (c *L2MessageFetcher) Start() { + tick := time.NewTicker(time.Duration(c.cfg.BlockTime) * time.Second) + go func() { + for { + select { + case <-c.ctx.Done(): + tick.Stop() + return + case <-tick.C: + c.fetchAndSaveEvents(c.cfg.Confirmation) + } + } + }() +} + +func (c *L2MessageFetcher) fetchAndSaveEvents(confirmation uint64) { + endHeight, err := utils.GetBlockNumber(c.ctx, c.client, confirmation) + if err != nil { + log.Error("failed to get L1 safe block number", "err", err) + return + } + + message, err := c.crossMessageOrm.GetLatestMessage(c.ctx, orm.MessageTypeL2) + if err != nil { + log.Error("failed to get L2 cross message processed height", "err", err) + return + } + startHeight := c.cfg.StartHeight + if message != nil && message.L2BlockNumber+1 > startHeight { + startHeight = message.L2BlockNumber + 1 + } + log.Info("fetch and save missing L2 events", "start height", startHeight) + + for from := startHeight; from <= endHeight; from += c.cfg.FetchLimit { + to := from + c.cfg.FetchLimit - 1 + if to > endHeight { + to = endHeight + } + err = c.doFetchAndSaveEvents(c.ctx, from, to, c.addressList) + if err != nil { + log.Error("failed to fetch and save L1 events", "err", err) + return + } + } +} + +func (c *L2MessageFetcher) doFetchAndSaveEvents(ctx context.Context, from uint64, to uint64, addrList []common.Address) error { + var l2FailedGatewayRouterTxs []*orm.CrossMessage + blockTimestampsMap := make(map[uint64]uint64) + for number := from; number <= to; number++ { + blockNumber := new(big.Int).SetUint64(number) + block, err := c.client.BlockByNumber(context.Background(), blockNumber) + if err != nil { + log.Error("failed to get block by number", "number", blockNumber.String(), "err", err) + return err + } + blockTimestampsMap[block.NumberU64()] = block.Time() + + for _, tx := range block.Transactions() { + to := tx.To() + if to == nil { + continue + } + toAddress := to.String() + if toAddress == c.cfg.GatewayRouterAddr { + receipt, err := c.client.TransactionReceipt(ctx, tx.Hash()) + if err != nil { + log.Error("Failed to get transaction receipt", "txHash", tx.Hash(), "err", err) + return err + } + + signer := types.NewLondonSigner(new(big.Int).SetUint64(c.cfg.ChainID)) + sender, err := signer.Sender(tx) + if err != nil { + log.Error("get sender failed", "chain id", c.cfg.ChainID, "tx hash", tx.Hash().String(), "err", err) + return err + } + + // Check if the transaction failed + if receipt.Status == types.ReceiptStatusFailed { + l2FailedGatewayRouterTxs = append(l2FailedGatewayRouterTxs, &orm.CrossMessage{ + MessageHash: tx.Hash().String(), + MessageType: int(orm.MessageTypeL2), + Sender: sender.String(), + Receiver: (*tx.To()).String(), + BlockTimestamp: block.Time(), + TxStatus: int(orm.TxStatusTypeSentFailed), + }) + } + } + } + } + + query := geth.FilterQuery{ + FromBlock: new(big.Int).SetUint64(from), // inclusive + ToBlock: new(big.Int).SetUint64(to), // inclusive + Addresses: addrList, + Topics: make([][]common.Hash, 1), + } + query.Topics[0] = make([]common.Hash, 7) + query.Topics[0][0] = backendabi.L2WithdrawETHSig + query.Topics[0][1] = backendabi.L2WithdrawERC20Sig + query.Topics[0][2] = backendabi.L2WithdrawERC721Sig + query.Topics[0][3] = backendabi.L2WithdrawERC1155Sig + query.Topics[0][4] = backendabi.L2SentMessageEventSig + query.Topics[0][5] = backendabi.L2RelayedMessageEventSig + query.Topics[0][6] = backendabi.L2FailedRelayedMessageEventSig + + logs, err := c.client.FilterLogs(ctx, query) + if err != nil { + log.Error("Failed to filter l2 event logs", "from", from, "to", to, "err", err) + return err + } + l2WithdrawMessages, l2RelayedMessages, err := logic.ParseL2EventLogs(logs, blockTimestampsMap) + if err != nil { + log.Error("failed to parse l2 event logs", "from", from, "to", to, "err", err) + return err + } + + if err = c.updateL2WithdrawMessageProofs(ctx, l2WithdrawMessages); err != nil { + log.Error("failed to update withdraw message proofs", "err", err) + } + + err = c.db.Transaction(func(tx *gorm.DB) error { + if txErr := c.crossMessageOrm.InsertMessages(ctx, l2WithdrawMessages, tx); txErr != nil { + log.Error("failed to insert l2 withdraw messages", "from", from, "to", to, "err", txErr) + return txErr + } + if txErr := c.crossMessageOrm.UpdateL2RelayedMessagesOfL1Deposits(ctx, l2RelayedMessages, tx); txErr != nil { + log.Error("failed to update l2 relayed messages of l1 deposits", "from", from, "to", to, "err", txErr) + return txErr + } + if txErr := c.crossMessageOrm.InsertMessages(ctx, l2FailedGatewayRouterTxs, tx); txErr != nil { + log.Error("failed to insert l2 failed gateway router transactions", "from", from, "to", to, "err", txErr) + return txErr + } + return nil + }) + if err != nil { + log.Error("failed to update db of l2 events", "from", from, "to", to, "err", err) + return err + } + return nil +} + +func (c *L2MessageFetcher) updateL2WithdrawMessageProofs(ctx context.Context, l2WithdrawMessages []*orm.CrossMessage) error { + withdrawTrie := messageproof.NewWithdrawTrie() + message, err := c.crossMessageOrm.GetLatestMessage(ctx, orm.MessageTypeL2) + if err != nil { + log.Error("failed to get latest l2 message", "err", err) + return err + } + if message != nil { + withdrawTrie.Initialize(message.MessageNonce, common.HexToHash(message.MessageHash), message.MerkleProof) + } + messageHashes := make([]common.Hash, len(l2WithdrawMessages)) + for i, message := range l2WithdrawMessages { + messageHashes[i] = common.HexToHash(message.MessageHash) + } + proofs := withdrawTrie.AppendMessages(messageHashes) + if len(l2WithdrawMessages) != len(proofs) { + log.Error("invalid proof array length", "l2 withdraw messages length", len(l2WithdrawMessages), "proofs length", len(proofs)) + return fmt.Errorf("invalid proof array length: got %d proofs for %d l2WithdrawMessages", len(proofs), len(l2WithdrawMessages)) + } + for i, proof := range proofs { + l2WithdrawMessages[i].MerkleProof = proof + } + return nil +} diff --git a/bridge-history-api/crossmsg/messageproof/withdraw_trie.go b/bridge-history-api/crossmessage/controller/messageproof/withdraw_trie.go similarity index 100% rename from bridge-history-api/crossmsg/messageproof/withdraw_trie.go rename to bridge-history-api/crossmessage/controller/messageproof/withdraw_trie.go diff --git a/bridge-history-api/crossmsg/messageproof/withdraw_trie_test.go b/bridge-history-api/crossmessage/controller/messageproof/withdraw_trie_test.go similarity index 100% rename from bridge-history-api/crossmsg/messageproof/withdraw_trie_test.go rename to bridge-history-api/crossmessage/controller/messageproof/withdraw_trie_test.go diff --git a/bridge-history-api/crossmessage/logic/event_parser.go b/bridge-history-api/crossmessage/logic/event_parser.go new file mode 100644 index 0000000000..cc3a530ffa --- /dev/null +++ b/bridge-history-api/crossmessage/logic/event_parser.go @@ -0,0 +1,464 @@ +package logic + +import ( + "context" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + + backendabi "bridge-history-api/abi" + "bridge-history-api/orm" + "bridge-history-api/utils" +) + +// ParseL1CrossChainEventLogs parses L1 watched cross chain events. +func ParseL1CrossChainEventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64, client *ethclient.Client) ([]*orm.CrossMessage, []*orm.CrossMessage, error) { + var l1DepositMessages []*orm.CrossMessage + var l1RelayedMessages []*orm.CrossMessage + for _, vlog := range logs { + switch vlog.Topics[0] { + case backendabi.L1DepositETHSig: + event := backendabi.DepositETH{} + if err := utils.UnpackLog(backendabi.IL1ETHGatewayABI, &event, "DepositETH", vlog); err != nil { + log.Warn("Failed to unpack DepositETH event", "err", err) + return nil, nil, err + } + lastMessage := l1DepositMessages[len(l1DepositMessages)-1] + lastMessage.L1BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeETH) + lastMessage.L1TxHash = vlog.TxHash.String() + lastMessage.TokenAmounts = event.Amount.String() + lastMessage.MessageType = int(orm.MessageTypeL1) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L1DepositERC20Sig: + event := backendabi.ERC20MessageEvent{} + err := utils.UnpackLog(backendabi.IL1ERC20GatewayABI, &event, "DepositERC20", vlog) + if err != nil { + log.Warn("Failed to unpack DepositERC20 event", "err", err) + return nil, nil, err + } + lastMessage := l1DepositMessages[len(l1DepositMessages)-1] + lastMessage.L1BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC20) + lastMessage.L1TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenAmounts = event.Amount.String() + lastMessage.MessageType = int(orm.MessageTypeL1) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L1DepositERC721Sig: + event := backendabi.ERC721MessageEvent{} + if err := utils.UnpackLog(backendabi.IL1ERC721GatewayABI, &event, "DepositERC721", vlog); err != nil { + log.Warn("Failed to unpack DepositERC721 event", "err", err) + return nil, nil, err + } + lastMessage := l1DepositMessages[len(l1DepositMessages)-1] + lastMessage.L1BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC721) + lastMessage.L1TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = event.TokenID.String() + lastMessage.MessageType = int(orm.MessageTypeL1) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L1BatchDepositERC721Sig: + event := backendabi.BatchERC721MessageEvent{} + if err := utils.UnpackLog(backendabi.IL1ERC721GatewayABI, &event, "BatchDepositERC721", vlog); err != nil { + log.Warn("Failed to unpack BatchDepositERC721 event", "err", err) + return nil, nil, err + } + lastMessage := l1DepositMessages[len(l1DepositMessages)-1] + lastMessage.L1BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC721) + lastMessage.L1TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs) + lastMessage.MessageType = int(orm.MessageTypeL1) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L1DepositERC1155Sig: + event := backendabi.ERC1155MessageEvent{} + if err := utils.UnpackLog(backendabi.IL1ERC1155GatewayABI, &event, "DepositERC1155", vlog); err != nil { + log.Warn("Failed to unpack DepositERC1155 event", "err", err) + return nil, nil, err + } + lastMessage := l1DepositMessages[len(l1DepositMessages)-1] + lastMessage.L1BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC1155) + lastMessage.L1TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = event.TokenID.String() + lastMessage.TokenAmounts = event.Amount.String() + lastMessage.MessageType = int(orm.MessageTypeL1) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L1BatchDepositERC1155Sig: + event := backendabi.BatchERC1155MessageEvent{} + if err := utils.UnpackLog(backendabi.IL1ERC1155GatewayABI, &event, "BatchDepositERC1155", vlog); err != nil { + log.Warn("Failed to unpack BatchDepositERC1155 event", "err", err) + return nil, nil, err + } + lastMessage := l1DepositMessages[len(l1DepositMessages)-1] + lastMessage.L1BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC1155) + lastMessage.L1TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs) + lastMessage.TokenAmounts = convertBigIntArrayToString(event.TokenAmounts) + lastMessage.MessageType = int(orm.MessageTypeL1) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L1SentMessageEventSig: + event := backendabi.L1SentMessageEvent{} + if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "SentMessage", vlog); err != nil { + log.Warn("Failed to unpack SentMessage event", "err", err) + return nil, nil, err + } + // Use this messageHash as next deposit event's messageHash + messageHash := utils.ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message).String() + l1DepositMessages = append(l1DepositMessages, &orm.CrossMessage{ + L1BlockNumber: vlog.BlockNumber, + Sender: event.Sender.String(), + Receiver: event.Target.String(), + TokenType: int(orm.TokenTypeETH), + L1TxHash: vlog.TxHash.String(), + TokenAmounts: event.Value.String(), + MessageType: int(orm.MessageTypeL1), + MessageHash: messageHash, + }) + case backendabi.L1RelayedMessageEventSig: + event := backendabi.L1RelayedMessageEvent{} + if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "RelayedMessage", vlog); err != nil { + log.Warn("Failed to unpack RelayedMessage event", "err", err) + return nil, nil, err + } + l1RelayedMessages = append(l1RelayedMessages, &orm.CrossMessage{ + MessageHash: event.MessageHash.String(), + L1BlockNumber: vlog.BlockNumber, + L1TxHash: vlog.TxHash.String(), + TxStatus: int(orm.TxStatusTypeRelayed), + }) + case backendabi.L1FailedRelayedMessageEventSig: + event := backendabi.L1FailedRelayedMessageEvent{} + if err := utils.UnpackLog(backendabi.IL1ScrollMessengerABI, &event, "FailedRelayedMessage", vlog); err != nil { + log.Warn("Failed to unpack FailedRelayedMessage event", "err", err) + return nil, nil, err + } + l1RelayedMessages = append(l1RelayedMessages, &orm.CrossMessage{ + MessageHash: event.MessageHash.String(), + L1BlockNumber: vlog.BlockNumber, + L1TxHash: vlog.TxHash.String(), + TxStatus: int(orm.TxStatusTypeRelayedFailed), + }) + } + } + return l1DepositMessages, l1RelayedMessages, nil +} + +// ParseL1BatchEventLogs parses L1 watched batch events. +func ParseL1BatchEventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64, client *ethclient.Client) ([]*orm.BatchEvent, error) { + var l1BatchEvents []*orm.BatchEvent + for _, vlog := range logs { + switch vlog.Topics[0] { + case backendabi.L1CommitBatchEventSig: + event := backendabi.L1CommitBatchEvent{} + if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "CommitBatch", vlog); err != nil { + log.Warn("Failed to unpack CommitBatch event", "err", err) + return nil, err + } + commitTx, isPending, err := client.TransactionByHash(ctx, vlog.TxHash) + if err != nil || isPending { + log.Warn("Failed to get commit Batch tx receipt or the tx is still pending", "err", err) + return nil, err + } + index, startBlock, endBlock, err := utils.GetBatchRangeFromCalldata(commitTx.Data()) + if err != nil { + log.Warn("Failed to get batch range from calldata", "hash", commitTx.Hash().String(), "height", vlog.BlockNumber) + return nil, err + } + l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{ + Type: orm.BatchEventTypeCommitBatch, + BatchIndex: index, + StartBlockNumber: startBlock, + EndBlockNumber: endBlock, + }) + case backendabi.L1RevertBatchEventSig: + event := backendabi.L1RevertBatchEvent{} + if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "RevertBatch", vlog); err != nil { + log.Warn("Failed to unpack RevertBatch event", "err", err) + return nil, err + } + l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{ + Type: orm.BatchEventTypeRevertBatch, + BatchIndex: event.BatchIndex.Uint64(), + }) + case backendabi.L1FinalizeBatchEventSig: + event := backendabi.L1FinalizeBatchEvent{} + if err := utils.UnpackLog(backendabi.IScrollChainABI, &event, "FinalizeBatch", vlog); err != nil { + log.Warn("Failed to unpack FinalizeBatch event", "err", err) + return nil, err + } + l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{ + Type: orm.BatchEventTypeFinalizeBatch, + BatchIndex: event.BatchIndex.Uint64(), + }) + } + } + return l1BatchEvents, nil +} + +// ParseL1MessageQueueEventLogs parses L1 watched message queue events. +func ParseL1MessageQueueEventLogs(ctx context.Context, logs []types.Log, blockTimestampsMap map[uint64]uint64, client *ethclient.Client) ([]*orm.MessageQueueEvent, error) { + var l1MessageQueueEvents []*orm.MessageQueueEvent + for _, vlog := range logs { + switch vlog.Topics[0] { + case backendabi.L1QueueTransactionEventSig: + event := backendabi.L1QueueTransactionEvent{} + if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "QueueTransaction", vlog); err != nil { + log.Warn("Failed to unpack QueueTransaction event", "err", err) + return nil, err + } + // 1. Update queue index of both sent message and replay message. + // 2. Update tx hash of replay message. + // The MessageHash is computed by hashing the Data field from the event, which is _xDomainCalldata. + l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{ + Type: orm.MessageQueueEventTypeQueueTransaction, + MessageHash: common.BytesToHash(crypto.Keccak256(event.Data)), + QueueIndex: event.QueueIndex, + TxHash: vlog.TxHash, + }) + case backendabi.L1DequeueTransactionEventSig: + event := backendabi.L1DequeueTransactionEvent{} + if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "DequeueTransaction", vlog); err != nil { + log.Warn("Failed to unpack DequeueTransaction event", "err", err) + return nil, err + } + skippedIndices := getSkippedQueueIndices(event.StartIndex.Uint64(), event.SkippedBitmap) + for _, index := range skippedIndices { + l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{ + Type: orm.MessageQueueEventTypeDequeueTransaction, + QueueIndex: index, + }) + } + case backendabi.L1QueueTransactionEventSig: + event := backendabi.L1DropTransactionEvent{} + if err := utils.UnpackLog(backendabi.IL1MessageQueueABI, &event, "DropTransaction", vlog); err != nil { + log.Warn("Failed to unpack DropTransaction event", "err", err) + return nil, err + } + l1MessageQueueEvents = append(l1MessageQueueEvents, &orm.MessageQueueEvent{ + Type: orm.MessageQueueEventTypeDropTransaction, + QueueIndex: event.Index.Uint64(), + }) + } + } + return l1MessageQueueEvents, nil +} + +// ParseL2EventLogs parses L2 watched events +func ParseL2EventLogs(logs []types.Log, blockTimestampsMap map[uint64]uint64) ([]*orm.CrossMessage, []*orm.CrossMessage, error) { + var l2WithdrawMessages []*orm.CrossMessage + var l2RelayedMessages []*orm.CrossMessage + for _, vlog := range logs { + switch vlog.Topics[0] { + case backendabi.L2WithdrawETHSig: + event := backendabi.DepositETH{} + err := utils.UnpackLog(backendabi.IL2ETHGatewayABI, &event, "WithdrawETH", vlog) + if err != nil { + log.Warn("Failed to unpack WithdrawETH event", "err", err) + return nil, nil, err + } + lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1] + lastMessage.L2BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeETH) + lastMessage.L2TxHash = vlog.TxHash.String() + lastMessage.TokenAmounts = event.Amount.String() + lastMessage.MessageType = int(orm.MessageTypeL2) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L2WithdrawERC20Sig: + event := backendabi.ERC20MessageEvent{} + err := utils.UnpackLog(backendabi.IL2ERC20GatewayABI, &event, "WithdrawERC20", vlog) + if err != nil { + log.Warn("Failed to unpack WithdrawERC20 event", "err", err) + return nil, nil, err + } + lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1] + lastMessage.L2BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC20) + lastMessage.L2TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenAmounts = event.Amount.String() + lastMessage.MessageType = int(orm.MessageTypeL2) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L2WithdrawERC721Sig: + event := backendabi.ERC721MessageEvent{} + err := utils.UnpackLog(backendabi.IL2ERC721GatewayABI, &event, "WithdrawERC721", vlog) + if err != nil { + log.Warn("Failed to unpack WithdrawERC721 event", "err", err) + return nil, nil, err + } + lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1] + lastMessage.L2BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC721) + lastMessage.L2TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = event.TokenID.String() + lastMessage.MessageType = int(orm.MessageTypeL2) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L2BatchWithdrawERC721Sig: + event := backendabi.BatchERC721MessageEvent{} + err := utils.UnpackLog(backendabi.IL2ERC721GatewayABI, &event, "BatchWithdrawERC721", vlog) + if err != nil { + log.Warn("Failed to unpack BatchWithdrawERC721 event", "err", err) + return nil, nil, err + } + lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1] + lastMessage.L2BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC721) + lastMessage.L2TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs) + lastMessage.MessageType = int(orm.MessageTypeL2) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L2WithdrawERC1155Sig: + event := backendabi.ERC1155MessageEvent{} + err := utils.UnpackLog(backendabi.IL2ERC1155GatewayABI, &event, "WithdrawERC1155", vlog) + if err != nil { + log.Warn("Failed to unpack WithdrawERC1155 event", "err", err) + return nil, nil, err + } + lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1] + lastMessage.L2BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC1155) + lastMessage.L2TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = event.TokenID.String() + lastMessage.TokenAmounts = event.Amount.String() + lastMessage.MessageType = int(orm.MessageTypeL2) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L2BatchWithdrawERC1155Sig: + event := backendabi.BatchERC1155MessageEvent{} + err := utils.UnpackLog(backendabi.IL2ERC1155GatewayABI, &event, "BatchWithdrawERC1155", vlog) + if err != nil { + log.Warn("Failed to unpack BatchWithdrawERC1155 event", "err", err) + return nil, nil, err + } + lastMessage := l2WithdrawMessages[len(l2WithdrawMessages)-1] + lastMessage.L2BlockNumber = vlog.BlockNumber + lastMessage.Sender = event.From.String() + lastMessage.Receiver = event.To.String() + lastMessage.TokenType = int(orm.TokenTypeERC1155) + lastMessage.L2TxHash = vlog.TxHash.String() + lastMessage.L1TokenAddress = event.L1Token.String() + lastMessage.L2TokenAddress = event.L2Token.String() + lastMessage.TokenIDs = convertBigIntArrayToString(event.TokenIDs) + lastMessage.TokenAmounts = convertBigIntArrayToString(event.TokenAmounts) + lastMessage.MessageType = int(orm.MessageTypeL2) + lastMessage.BlockTimestamp = blockTimestampsMap[vlog.BlockNumber] + case backendabi.L2SentMessageEventSig: + event := backendabi.L2SentMessageEvent{} + err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "SentMessage", vlog) + if err != nil { + log.Warn("Failed to unpack SentMessage event", "err", err) + return nil, nil, err + } + // Use this messageHash as next deposit event's messageHash + messageHash := utils.ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message) + l2WithdrawMessages = append(l2WithdrawMessages, &orm.CrossMessage{ + MessageHash: messageHash.String(), + Sender: event.Sender.String(), + Receiver: event.Target.String(), + TokenType: int(orm.TokenTypeETH), + L2TxHash: vlog.TxHash.String(), + TokenAmounts: event.Value.String(), + MessageFrom: event.Sender.String(), + MessageTo: event.Target.String(), + MessageValue: event.Value.String(), + MessageNonce: event.MessageNonce.Uint64(), + MessageData: hexutil.Encode(event.Message), + }) + case backendabi.L2RelayedMessageEventSig: + event := backendabi.L2RelayedMessageEvent{} + err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "RelayedMessage", vlog) + if err != nil { + log.Warn("Failed to unpack RelayedMessage event", "err", err) + return nil, nil, err + } + l2RelayedMessages = append(l2RelayedMessages, &orm.CrossMessage{ + MessageHash: event.MessageHash.String(), + L2BlockNumber: vlog.BlockNumber, + L2TxHash: vlog.TxHash.String(), + TxStatus: int(orm.TxStatusTypeRelayed), + }) + case backendabi.L2FailedRelayedMessageEventSig: + event := backendabi.L2RelayedMessageEvent{} + err := utils.UnpackLog(backendabi.IL2ScrollMessengerABI, &event, "FailedRelayedMessage", vlog) + if err != nil { + log.Warn("Failed to unpack FailedRelayedMessage event", "err", err) + return nil, nil, err + } + l2RelayedMessages = append(l2RelayedMessages, &orm.CrossMessage{ + MessageHash: event.MessageHash.String(), + L2BlockNumber: vlog.BlockNumber, + L2TxHash: vlog.TxHash.String(), + TxStatus: int(orm.TxStatusTypeRelayedFailed), + }) + } + } + return l2WithdrawMessages, l2RelayedMessages, nil +} + +func convertBigIntArrayToString(array []*big.Int) string { + stringArray := make([]string, len(array)) + for i, num := range array { + stringArray[i] = num.String() + } + + result := strings.Join(stringArray, ", ") + return result +} + +func getSkippedQueueIndices(startIndex uint64, skippedBitmap *big.Int) []uint64 { + var indices []uint64 + for i := 0; i < 256; i++ { + index := startIndex + uint64(i) + bit := new(big.Int).Rsh(skippedBitmap, uint(i)) + if bit.Bit(0) == 0 { + continue + } + indices = append(indices, index) + } + return indices +} diff --git a/bridge-history-api/crossmsg/batch_info_fetcher.go b/bridge-history-api/crossmsg/batch_info_fetcher.go deleted file mode 100644 index 83a9472536..0000000000 --- a/bridge-history-api/crossmsg/batch_info_fetcher.go +++ /dev/null @@ -1,116 +0,0 @@ -package crossmsg - -import ( - "context" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" - - "bridge-history-api/crossmsg/messageproof" - "bridge-history-api/orm" - "bridge-history-api/utils" -) - -// BatchInfoFetcher fetches batch info from l1 chain and update db -type BatchInfoFetcher struct { - ctx context.Context - scrollChainAddr common.Address - batchInfoStartNumber uint64 - confirmation uint64 - blockTimeInSec int - client *ethclient.Client - db *gorm.DB - rollupOrm *orm.RollupBatch - msgProofUpdater *messageproof.MsgProofUpdater -} - -// NewBatchInfoFetcher creates a new BatchInfoFetcher instance -func NewBatchInfoFetcher(ctx context.Context, scrollChainAddr common.Address, batchInfoStartNumber uint64, confirmation uint64, blockTimeInSec int, client *ethclient.Client, db *gorm.DB, msgProofUpdater *messageproof.MsgProofUpdater) *BatchInfoFetcher { - return &BatchInfoFetcher{ - ctx: ctx, - scrollChainAddr: scrollChainAddr, - batchInfoStartNumber: batchInfoStartNumber, - confirmation: confirmation, - blockTimeInSec: blockTimeInSec, - client: client, - db: db, - rollupOrm: orm.NewRollupBatch(db), - msgProofUpdater: msgProofUpdater, - } -} - -// Start the BatchInfoFetcher -func (b *BatchInfoFetcher) Start() { - log.Info("BatchInfoFetcher Start") - // Fetch batch info at beginning - // Then start msg proof updater after db have some bridge batch - err := b.fetchBatchInfo() - if err != nil { - log.Error("fetch batch info at beginning failed: ", "err", err) - } - - go b.msgProofUpdater.Start() - - go func() { - tick := time.NewTicker(time.Duration(b.blockTimeInSec) * time.Second) - for { - select { - case <-b.ctx.Done(): - tick.Stop() - return - case <-tick.C: - err := b.fetchBatchInfo() - if err != nil { - log.Error("fetch batch info failed: ", "err", err) - } - } - } - }() -} - -// Stop the BatchInfoFetcher and call msg proof updater to stop -func (b *BatchInfoFetcher) Stop() { - log.Info("BatchInfoFetcher Stop") - b.msgProofUpdater.Stop() -} - -func (b *BatchInfoFetcher) fetchBatchInfo() error { - number, err := utils.GetSafeBlockNumber(b.ctx, b.client, b.confirmation) - if err != nil { - log.Error("Can not get latest block number: ", "err", err) - return err - } - latestBatchHeight, err := b.rollupOrm.GetLatestRollupBatchProcessedHeight(b.ctx) - if err != nil { - log.Error("Can not get latest BatchInfo: ", "err", err) - return err - } - var startHeight uint64 - if latestBatchHeight == 0 { - log.Info("no batch record in database, start from batchInfoStartNumber", "batchInfoStartNumber", b.batchInfoStartNumber) - startHeight = b.batchInfoStartNumber - } else { - startHeight = latestBatchHeight + 1 - } - if startHeight < b.batchInfoStartNumber { - startHeight = b.batchInfoStartNumber - } - for from := startHeight; number >= from; from += fetchLimit { - to := from + fetchLimit - 1 - // number - confirmation can never less than 0 since the for loop condition - // but watch out the overflow - if to > number { - to = number - } - // filter logs to fetch batches - err = FetchAndSaveBatchIndex(b.ctx, b.client, b.db, int64(from), int64(to), b.scrollChainAddr) - if err != nil { - log.Error("Can not fetch and save from chain: ", "err", err) - return err - } - } - return nil -} diff --git a/bridge-history-api/crossmsg/block_timestamp_fetcher.go b/bridge-history-api/crossmsg/block_timestamp_fetcher.go deleted file mode 100644 index 42c8c417f3..0000000000 --- a/bridge-history-api/crossmsg/block_timestamp_fetcher.go +++ /dev/null @@ -1,85 +0,0 @@ -package crossmsg - -import ( - "context" - "math/big" - "time" - - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" -) - -// GetEarliestNoBlockTimestampHeightFunc is a function type that gets the earliest record without block timestamp from database -type GetEarliestNoBlockTimestampHeightFunc func(ctx context.Context) (uint64, error) - -// UpdateBlockTimestampFunc is a function type that updates block timestamp into database -type UpdateBlockTimestampFunc func(ctx context.Context, height uint64, timestamp time.Time) error - -// BlockTimestampFetcher fetches block timestamp from blockchain and saves them to database -type BlockTimestampFetcher struct { - ctx context.Context - confirmation uint64 - blockTimeInSec int - client *ethclient.Client - updateBlockTimestampFunc UpdateBlockTimestampFunc - getEarliestNoBlockTimestampHeightFunc GetEarliestNoBlockTimestampHeightFunc -} - -// NewBlockTimestampFetcher creates a new BlockTimestampFetcher instance -func NewBlockTimestampFetcher(ctx context.Context, confirmation uint64, blockTimeInSec int, client *ethclient.Client, updateBlockTimestampFunc UpdateBlockTimestampFunc, getEarliestNoBlockTimestampHeightFunc GetEarliestNoBlockTimestampHeightFunc) *BlockTimestampFetcher { - return &BlockTimestampFetcher{ - ctx: ctx, - confirmation: confirmation, - blockTimeInSec: blockTimeInSec, - client: client, - getEarliestNoBlockTimestampHeightFunc: getEarliestNoBlockTimestampHeightFunc, - updateBlockTimestampFunc: updateBlockTimestampFunc, - } -} - -// Start the BlockTimestampFetcher -func (b *BlockTimestampFetcher) Start() { - go func() { - tick := time.NewTicker(time.Duration(b.blockTimeInSec) * time.Second) - for { - select { - case <-b.ctx.Done(): - tick.Stop() - return - case <-tick.C: - number, err := b.client.BlockNumber(b.ctx) - if err != nil { - log.Error("Can not get latest block number", "err", err) - continue - } - startHeight, err := b.getEarliestNoBlockTimestampHeightFunc(b.ctx) - if err != nil { - log.Error("Can not get latest record without block timestamp", "err", err) - continue - } - for height := startHeight; number >= height+b.confirmation && height > 0; { - block, err := b.client.HeaderByNumber(b.ctx, new(big.Int).SetUint64(height)) - if err != nil { - log.Error("Can not get block by number", "err", err) - break - } - err = b.updateBlockTimestampFunc(b.ctx, height, time.Unix(int64(block.Time), 0)) - if err != nil { - log.Error("Can not update blockTimestamp into DB ", "err", err) - break - } - height, err = b.getEarliestNoBlockTimestampHeightFunc(b.ctx) - if err != nil { - log.Error("Can not get latest record without block timestamp", "err", err) - break - } - } - } - } - }() -} - -// Stop the BlockTimestampFetcher and log the info -func (b *BlockTimestampFetcher) Stop() { - log.Info("BlockTimestampFetcher Stop") -} diff --git a/bridge-history-api/crossmsg/cross_msg_fetcher.go b/bridge-history-api/crossmsg/cross_msg_fetcher.go deleted file mode 100644 index 7c57516732..0000000000 --- a/bridge-history-api/crossmsg/cross_msg_fetcher.go +++ /dev/null @@ -1,215 +0,0 @@ -package crossmsg - -import ( - "context" - "fmt" - "math/big" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - "github.com/modern-go/reflect2" - "gorm.io/gorm" - - "bridge-history-api/config" - "bridge-history-api/utils" -) - -// MsgFetcher fetches cross message events from blockchain and saves them to database -type MsgFetcher struct { - ctx context.Context - config *config.LayerConfig - db *gorm.DB - client *ethclient.Client - worker *FetchEventWorker - reorgHandling ReorgHandling - addressList []common.Address - cachedHeaders []*types.Header - mu sync.Mutex - reorgStartCh chan struct{} - reorgEndCh chan struct{} -} - -// NewMsgFetcher creates a new MsgFetcher instance -func NewMsgFetcher(ctx context.Context, config *config.LayerConfig, db *gorm.DB, client *ethclient.Client, worker *FetchEventWorker, addressList []common.Address, reorg ReorgHandling) (*MsgFetcher, error) { - msgFetcher := &MsgFetcher{ - ctx: ctx, - config: config, - db: db, - client: client, - worker: worker, - reorgHandling: reorg, - addressList: addressList, - cachedHeaders: make([]*types.Header, 0), - reorgStartCh: make(chan struct{}), - reorgEndCh: make(chan struct{}), - } - return msgFetcher, nil -} - -// Start the MsgFetcher -func (c *MsgFetcher) Start() { - log.Info("MsgFetcher Start") - // fetch missing events from finalized blocks, we don't handle reorgs here - c.forwardFetchAndSaveMissingEvents(c.config.Confirmation) - - tick := time.NewTicker(time.Duration(c.config.BlockTime) * time.Second) - headerTick := time.NewTicker(time.Duration(c.config.BlockTime/2) * time.Second) - go func() { - for { - select { - case <-c.reorgStartCh: - // create timeout here - timeout := time.NewTicker(300 * time.Second) - select { - case <-c.reorgEndCh: - log.Info("Reorg finished") - timeout.Stop() - case <-timeout.C: - // TODO: need to notify the on-call members to handle reorg manually - timeout.Stop() - log.Crit("Reorg timeout") - } - case <-c.ctx.Done(): - tick.Stop() - return - case <-tick.C: - c.mu.Lock() - c.forwardFetchAndSaveMissingEvents(1) - c.mu.Unlock() - } - } - }() - - go func() { - for { - select { - case <-c.ctx.Done(): - headerTick.Stop() - return - case <-headerTick.C: - c.fetchMissingLatestHeaders() - } - } - }() -} - -// Stop the MsgFetcher and log the info -func (c *MsgFetcher) Stop() { - log.Info("MsgFetcher Stop") -} - -// forwardFetchAndSaveMissingEvents will fetch all events from the latest processed height to the latest block number. -func (c *MsgFetcher) forwardFetchAndSaveMissingEvents(confirmation uint64) { - // if we fetch to the latest block, shall not exceed cachedHeaders - var number uint64 - var err error - if len(c.cachedHeaders) != 0 && confirmation == 0 { - number = c.cachedHeaders[len(c.cachedHeaders)-1].Number.Uint64() - 1 - } else { - number, err = utils.GetSafeBlockNumber(c.ctx, c.client, confirmation) - if err != nil { - log.Error(fmt.Sprintf("%s: can not get the safe block number", c.worker.Name), "err", err) - return - } - } - if reflect2.IsNil(c.worker.G) || reflect2.IsNil(c.worker.F) { - log.Error(fmt.Sprintf("%s: invalid get/fetch function", c.worker.Name)) - return - } - processedHeight, err := c.worker.G(c.ctx, c.db) - if err != nil { - log.Error(fmt.Sprintf("%s: can not get latest processed block height", c.worker.Name)) - } - log.Info(fmt.Sprintf("%s: ", c.worker.Name), "height", processedHeight) - if processedHeight <= 0 || processedHeight < c.config.StartHeight { - processedHeight = c.config.StartHeight - } else { - processedHeight++ - } - for from := processedHeight; from <= number; from += fetchLimit { - to := from + fetchLimit - 1 - if to > number { - to = number - } - // watch for overflow here, tho its unlikely to happen - err := c.worker.F(c.ctx, c.client, c.db, int64(from), int64(to), c.addressList) - if err != nil { - log.Error(fmt.Sprintf("%s: failed!", c.worker.Name), "err", err) - break - } - } -} - -func (c *MsgFetcher) fetchMissingLatestHeaders() { - var start int64 - number, err := c.client.BlockNumber(c.ctx) - if err != nil { - log.Error("fetchMissingLatestHeaders(): can not get the latest block number", "err", err) - return - } - - if len(c.cachedHeaders) > 0 { - start = c.cachedHeaders[len(c.cachedHeaders)-1].Number.Int64() + 1 - } else { - start = int64(number - c.config.Confirmation) - } - for i := start; i <= int64(number); i++ { - select { - case <-c.ctx.Done(): - close(c.reorgStartCh) - close(c.reorgEndCh) - return - default: - header, err := c.client.HeaderByNumber(c.ctx, big.NewInt(i)) - if err != nil { - log.Error("failed to get latest header", "err", err) - return - } - if len(c.cachedHeaders) == 0 { - c.cachedHeaders = MergeAddIntoHeaderList(c.cachedHeaders, []*types.Header{header}, int(c.config.Confirmation)) - return - } - //check if the fetched header is child from the last cached header - if IsParentAndChild(c.cachedHeaders[len(c.cachedHeaders)-1], header) { - c.cachedHeaders = MergeAddIntoHeaderList(c.cachedHeaders, []*types.Header{header}, int(c.config.Confirmation)) - log.Debug("fetched block into cache", "height", header.Number, "parent hash", header.ParentHash.Hex(), "block hash", c.cachedHeaders[len(c.cachedHeaders)-1].Hash().Hex(), "len", len(c.cachedHeaders)) - continue - } - // reorg happened - log.Warn("Reorg happened", "height", header.Number, "parent hash", header.ParentHash.Hex(), "last cached hash", c.cachedHeaders[len(c.cachedHeaders)-1].Hash().Hex(), "last cached height", c.cachedHeaders[len(c.cachedHeaders)-1].Number) - c.reorgStartCh <- struct{}{} - // waiting here if there is fetcher running - c.mu.Lock() - index, ok, validHeaders := BackwardFindReorgBlock(c.ctx, c.cachedHeaders, c.client, header) - if !ok { - log.Error("Reorg happened too earlier than cached headers", "reorg height", header.Number) - num, getSafeErr := utils.GetSafeBlockNumber(c.ctx, c.client, c.config.Confirmation) - if getSafeErr != nil { - log.Crit("Can not get safe number during reorg, quit the process", "err", err) - } - // clear all our saved data, because no data is safe now - err = c.reorgHandling(c.ctx, num, c.db) - // if handling success then we can update the cachedHeaders - if err == nil { - c.cachedHeaders = c.cachedHeaders[:0] - } - c.mu.Unlock() - c.reorgEndCh <- struct{}{} - return - } - err = c.reorgHandling(c.ctx, c.cachedHeaders[index].Number.Uint64(), c.db) - // if handling success then we can update the cachedHeaders - if err == nil { - c.cachedHeaders = c.cachedHeaders[:index+1] - c.cachedHeaders = MergeAddIntoHeaderList(c.cachedHeaders, validHeaders, int(c.config.Confirmation)) - } - c.mu.Unlock() - c.reorgEndCh <- struct{}{} - } - } - -} diff --git a/bridge-history-api/crossmsg/fetch_missing_event.go b/bridge-history-api/crossmsg/fetch_missing_event.go deleted file mode 100644 index 95a1b68cb4..0000000000 --- a/bridge-history-api/crossmsg/fetch_missing_event.go +++ /dev/null @@ -1,213 +0,0 @@ -package crossmsg - -import ( - "context" - "math/big" - - geth "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" - - backendabi "bridge-history-api/abi" - "bridge-history-api/orm" - "bridge-history-api/utils" -) - -// Todo : read from config -var ( - // the number of blocks fetch per round - fetchLimit = uint64(3000) -) - -// FetchAndSave is a function type that fetches events from blockchain and saves them to database -type FetchAndSave func(ctx context.Context, client *ethclient.Client, database *gorm.DB, from int64, to int64, addressList []common.Address) error - -// GetLatestProcessed is a function type that gets the latest processed block height from database -type GetLatestProcessed func(ctx context.Context, db *gorm.DB) (uint64, error) - -// FetchEventWorker defines worker with fetch and save function, processed number getter, and name -type FetchEventWorker struct { - F FetchAndSave - G GetLatestProcessed - Name string -} - -// GetLatestL1ProcessedHeight get L1 the latest processed height -func GetLatestL1ProcessedHeight(ctx context.Context, db *gorm.DB) (uint64, error) { - l1CrossMsgOrm := orm.NewCrossMsg(db) - relayedOrm := orm.NewRelayedMsg(db) - crossHeight, err := l1CrossMsgOrm.GetLatestL1ProcessedHeight(ctx) - if err != nil { - log.Error("failed to get L1 cross message processed height: ", "err", err) - return 0, err - } - relayedHeight, err := relayedOrm.GetLatestRelayedHeightOnL1(ctx) - if err != nil { - log.Error("failed to get L1 relayed message processed height: ", "err", err) - return 0, err - } - if crossHeight > relayedHeight { - return crossHeight, nil - } - return relayedHeight, nil -} - -// GetLatestL2ProcessedHeight get L2 latest processed height -func GetLatestL2ProcessedHeight(ctx context.Context, db *gorm.DB) (uint64, error) { - l2CrossMsgOrm := orm.NewCrossMsg(db) - relayedOrm := orm.NewRelayedMsg(db) - l2SentMsgOrm := orm.NewL2SentMsg(db) - crossHeight, err := l2CrossMsgOrm.GetLatestL2ProcessedHeight(ctx) - if err != nil { - log.Error("failed to get L2 cross message processed height", "err", err) - return 0, err - } - relayedHeight, err := relayedOrm.GetLatestRelayedHeightOnL2(ctx) - if err != nil { - log.Error("failed to get L2 relayed message processed height", "err", err) - return 0, err - } - l2SentHeight, err := l2SentMsgOrm.GetLatestSentMsgHeightOnL2(ctx) - if err != nil { - log.Error("failed to get L2 sent message processed height", "err", err) - return 0, err - } - maxHeight := crossHeight - if maxHeight < relayedHeight { - maxHeight = relayedHeight - } - if maxHeight < l2SentHeight { - maxHeight = l2SentHeight - } - return maxHeight, nil -} - -// L1FetchAndSaveEvents fetch and save events on L1 -func L1FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, db *gorm.DB, from int64, to int64, addrList []common.Address) error { - l1CrossMsgOrm := orm.NewCrossMsg(db) - relayedOrm := orm.NewRelayedMsg(db) - query := geth.FilterQuery{ - FromBlock: big.NewInt(from), // inclusive - ToBlock: big.NewInt(to), // inclusive - Addresses: addrList, - Topics: make([][]common.Hash, 1), - } - query.Topics[0] = make([]common.Hash, 7) - query.Topics[0][0] = backendabi.L1DepositETHSig - query.Topics[0][1] = backendabi.L1DepositERC20Sig - query.Topics[0][2] = backendabi.L1RelayedMessageEventSignature - query.Topics[0][3] = backendabi.L1SentMessageEventSignature - query.Topics[0][4] = backendabi.L1DepositERC721Sig - query.Topics[0][5] = backendabi.L1DepositERC1155Sig - query.Topics[0][6] = backendabi.L1DepositWETHSig - - logs, err := client.FilterLogs(ctx, query) - if err != nil { - log.Warn("Failed to get l1 event logs", "err", err) - return err - } - depositL1CrossMsgs, relayedMsg, err := utils.ParseBackendL1EventLogs(logs) - if err != nil { - log.Error("l1FetchAndSaveEvents: Failed to parse cross msg event logs", "err", err) - return err - } - err = db.Transaction(func(tx *gorm.DB) error { - if txErr := l1CrossMsgOrm.InsertL1CrossMsg(ctx, depositL1CrossMsgs, tx); txErr != nil { - log.Error("l1FetchAndSaveEvents: Failed to insert cross msg event logs", "err", txErr) - return txErr - } - if txErr := relayedOrm.InsertRelayedMsg(ctx, relayedMsg, tx); txErr != nil { - log.Error("l1FetchAndSaveEvents: Failed to insert relayed msg event logs", "err", txErr) - return txErr - } - return nil - }) - if err != nil { - log.Crit("l2FetchAndSaveEvents: Failed to finish transaction", "err", err) - } - return err -} - -// L2FetchAndSaveEvents fetche and save events on L2 -func L2FetchAndSaveEvents(ctx context.Context, client *ethclient.Client, db *gorm.DB, from int64, to int64, addrList []common.Address) error { - l2CrossMsgOrm := orm.NewCrossMsg(db) - relayedOrm := orm.NewRelayedMsg(db) - l2SentMsgOrm := orm.NewL2SentMsg(db) - query := geth.FilterQuery{ - FromBlock: big.NewInt(from), // inclusive - ToBlock: big.NewInt(to), // inclusive - Addresses: addrList, - Topics: make([][]common.Hash, 1), - } - query.Topics[0] = make([]common.Hash, 7) - query.Topics[0][0] = backendabi.L2WithdrawETHSig - query.Topics[0][1] = backendabi.L2WithdrawERC20Sig - query.Topics[0][2] = backendabi.L2RelayedMessageEventSignature - query.Topics[0][3] = backendabi.L2SentMessageEventSignature - query.Topics[0][4] = backendabi.L2WithdrawERC721Sig - query.Topics[0][5] = backendabi.L2WithdrawERC1155Sig - query.Topics[0][6] = backendabi.L2WithdrawWETHSig - - logs, err := client.FilterLogs(ctx, query) - if err != nil { - log.Warn("Failed to get l2 event logs", "err", err) - return err - } - depositL2CrossMsgs, relayedMsg, l2SentMsgs, err := utils.ParseBackendL2EventLogs(logs) - if err != nil { - log.Error("l2FetchAndSaveEvents: Failed to parse cross msg event logs", "err", err) - return err - } - - err = db.Transaction(func(tx *gorm.DB) error { - if txErr := l2CrossMsgOrm.InsertL2CrossMsg(ctx, depositL2CrossMsgs, tx); txErr != nil { - log.Error("l2FetchAndSaveEvents: Failed to insert cross msg event logs", "err", txErr) - return txErr - } - - if txErr := relayedOrm.InsertRelayedMsg(ctx, relayedMsg, tx); txErr != nil { - log.Error("l2FetchAndSaveEvents: Failed to insert relayed message event logs", "err", txErr) - return txErr - } - - if txErr := l2SentMsgOrm.InsertL2SentMsg(ctx, l2SentMsgs, tx); txErr != nil { - log.Error("l2FetchAndSaveEvents: Failed to insert l2 sent message", "err", txErr) - return txErr - } - return nil - }) - if err != nil { - log.Crit("l2FetchAndSaveEvents: Failed to begin db transaction", "err", err) - } - return err -} - -// FetchAndSaveBatchIndex fetche and save batch index -func FetchAndSaveBatchIndex(ctx context.Context, client *ethclient.Client, db *gorm.DB, from int64, to int64, scrollChainAddr common.Address) error { - rollupBatchOrm := orm.NewRollupBatch(db) - query := geth.FilterQuery{ - FromBlock: big.NewInt(from), // inclusive - ToBlock: big.NewInt(to), // inclusive - Addresses: []common.Address{scrollChainAddr}, - Topics: make([][]common.Hash, 1), - } - query.Topics[0] = make([]common.Hash, 1) - query.Topics[0][0] = backendabi.L1CommitBatchEventSignature - logs, err := client.FilterLogs(ctx, query) - if err != nil { - log.Warn("Failed to get batch commit event logs", "err", err) - return err - } - rollupBatches, err := utils.ParseBatchInfoFromScrollChain(ctx, client, logs) - if err != nil { - log.Error("FetchAndSaveBatchIndex: Failed to parse batch commit msg event logs", "err", err) - return err - } - if txErr := rollupBatchOrm.InsertRollupBatch(ctx, rollupBatches); txErr != nil { - log.Crit("FetchAndSaveBatchIndex: Failed to insert batch commit msg event logs", "err", txErr) - return txErr - } - return nil -} diff --git a/bridge-history-api/crossmsg/messageproof/msg_proof_updater.go b/bridge-history-api/crossmsg/messageproof/msg_proof_updater.go deleted file mode 100644 index 2ccaf8828b..0000000000 --- a/bridge-history-api/crossmsg/messageproof/msg_proof_updater.go +++ /dev/null @@ -1,249 +0,0 @@ -package messageproof - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" - - "bridge-history-api/orm" -) - -// MsgProofUpdater is used to update message proof in db -type MsgProofUpdater struct { - ctx context.Context - db *gorm.DB - l2SentMsgOrm *orm.L2SentMsg - rollupOrm *orm.RollupBatch - withdrawTrie *WithdrawTrie -} - -// NewMsgProofUpdater new MsgProofUpdater instance -func NewMsgProofUpdater(ctx context.Context, confirmations uint64, startBlock uint64, db *gorm.DB) *MsgProofUpdater { - return &MsgProofUpdater{ - ctx: ctx, - db: db, - l2SentMsgOrm: orm.NewL2SentMsg(db), - rollupOrm: orm.NewRollupBatch(db), - withdrawTrie: NewWithdrawTrie(), - } -} - -// Start the MsgProofUpdater -func (m *MsgProofUpdater) Start() { - log.Info("MsgProofUpdater Start") - m.initialize(m.ctx) - go func() { - tick := time.NewTicker(10 * time.Second) - for { - select { - case <-m.ctx.Done(): - tick.Stop() - return - case <-tick.C: - latestBatch, err := m.rollupOrm.GetLatestRollupBatch(m.ctx) - if err != nil { - log.Warn("MsgProofUpdater: Can not get latest RollupBatch: ", "err", err) - continue - } - if latestBatch == nil { - continue - } - latestBatchIndexWithProof, err := m.l2SentMsgOrm.GetLatestL2SentMsgBatchIndex(m.ctx) - if err != nil { - log.Error("MsgProofUpdater: Can not get latest L2SentMsgBatchIndex: ", "err", err) - continue - } - log.Info("latest batch with proof", "batch_index", latestBatchIndexWithProof) - var start uint64 - if latestBatchIndexWithProof < 0 { - start = 1 - } else { - start = uint64(latestBatchIndexWithProof) + 1 - } - for i := start; i <= latestBatch.BatchIndex; i++ { - batch, err := m.rollupOrm.GetRollupBatchByIndex(m.ctx, i) - if err != nil { - log.Error("MsgProofUpdater: Can not get RollupBatch: ", "err", err, "index", i) - break - } - // get all l2 messages in this batch - msgs, proofs, err := m.appendL2Messages(batch.StartBlockNumber, batch.EndBlockNumber) - if err != nil { - log.Error("MsgProofUpdater: can not append l2messages", "startBlockNumber", batch.StartBlockNumber, "endBlockNumber", batch.EndBlockNumber, "err", err) - break - } - // here we update batch withdraw root - err = m.rollupOrm.UpdateRollupBatchWithdrawRoot(m.ctx, batch.BatchIndex, m.withdrawTrie.MessageRoot().Hex()) - if err != nil { - // if failed better restart the binary - log.Error("MsgProofUpdater: can not update batch withdraw root", "err", err) - break - } - err = m.updateMsgProof(msgs, proofs, batch.BatchIndex) - if err != nil { - // if failed better restart the binary - log.Error("MsgProofUpdater: can not update msg proof", "err", err) - break - } - } - - } - } - }() - -} - -// Stop the MsgProofUpdater -func (m *MsgProofUpdater) Stop() { - log.Info("MsgProofUpdater Stop") -} - -func (m *MsgProofUpdater) initialize(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - default: - err := m.initializeWithdrawTrie() - if err != nil { - log.Error("can not initialize withdraw trie", "err", err) - // give it some time to retry - time.Sleep(10 * time.Second) - continue - } - return - } - } -} - -func (m *MsgProofUpdater) initializeWithdrawTrie() error { - var batch *orm.RollupBatch - firstMsg, err := m.l2SentMsgOrm.GetL2SentMessageByNonce(m.ctx, 0) - if err != nil { - return fmt.Errorf("failed to get first l2 message: %v", err) - } - // no l2 message - // TO DO: check if we really dont have l2 sent message with nonce 0 - if firstMsg == nil { - log.Info("No first l2sentmsg in db") - return nil - } - - // if no batch, return and wait for next try round - batch, err = m.rollupOrm.GetLatestRollupBatch(m.ctx) - if err != nil { - return fmt.Errorf("failed to get latest batch: %v", err) - } - if batch == nil { - return fmt.Errorf("no batch found") - } - - var batches []*orm.RollupBatch - batchIndex := batch.BatchIndex - for { - var msg *orm.L2SentMsg - msg, err = m.l2SentMsgOrm.GetLatestL2SentMsgLEHeight(m.ctx, batch.EndBlockNumber) - if err != nil { - log.Warn("failed to get l2 sent message less than height", "endBlocknum", batch.EndBlockNumber, "err", err) - } - if msg != nil && msg.MsgProof != "" { - log.Info("Found latest l2 sent msg with proof: ", "msg_proof", msg.MsgProof, "height", msg.Height, "msg_hash", msg.MsgHash) - // initialize withdrawTrie - proofBytes := common.Hex2Bytes(msg.MsgProof) - m.withdrawTrie.Initialize(msg.Nonce, common.HexToHash(msg.MsgHash), proofBytes) - break - } - - // append unprocessed batch - batches = append(batches, batch) - - if batchIndex == 1 { - // otherwise overflow - // and batchIndex 0 is not in DB - // To Do: check if we dont have batch with index 0 in future - break - } - // iterate for next batch - batchIndex-- - - batch, err = m.rollupOrm.GetRollupBatchByIndex(m.ctx, batchIndex) - if err != nil || batch == nil { - return fmt.Errorf("failed to get block batch %v: %v", batchIndex, err) - } - } - - log.Info("Build withdraw trie with pending messages") - for i := len(batches) - 1; i >= 0; i-- { - b := batches[i] - msgs, proofs, err := m.appendL2Messages(b.StartBlockNumber, b.EndBlockNumber) - if err != nil { - return err - } - err = m.rollupOrm.UpdateRollupBatchWithdrawRoot(m.ctx, b.BatchIndex, m.withdrawTrie.MessageRoot().Hex()) - if err != nil { - return err - } - err = m.updateMsgProof(msgs, proofs, b.BatchIndex) - if err != nil { - return err - } - } - log.Info("Build withdraw trie finished") - - return nil -} - -func (m *MsgProofUpdater) updateMsgProof(msgs []*orm.L2SentMsg, proofs [][]byte, batchIndex uint64) error { - if len(msgs) == 0 { - return nil - } - // this should not happen, but double check - if len(msgs) != len(proofs) { - return fmt.Errorf("illegal state: len(msgs) != len(proofs)") - } - err := m.db.Transaction(func(tx *gorm.DB) error { - for i, msg := range msgs { - proofHex := common.Bytes2Hex(proofs[i]) - log.Debug("updateMsgProof", "msgHash", msg.MsgHash, "batchIndex", batchIndex, "proof", proofHex) - if err := m.l2SentMsgOrm.UpdateL2MessageProof(m.ctx, msg.MsgHash, proofHex, batchIndex, tx); err != nil { - return err - } - } - return nil - }) - if err != nil { - return err - } - return nil -} - -// appendL2Messages will append all messages between firstBlock and lastBlock (both inclusive) to withdrawTrie and compute corresponding merkle proof of each message. -func (m *MsgProofUpdater) appendL2Messages(firstBlock, lastBlock uint64) ([]*orm.L2SentMsg, [][]byte, error) { - var msgProofs [][]byte - messages, err := m.l2SentMsgOrm.GetL2SentMsgMsgHashByHeightRange(m.ctx, firstBlock, lastBlock) - if err != nil { - log.Error("GetL2SentMsgMsgHashByHeightRange failed", "error", err, "firstBlock", firstBlock, "lastBlock", lastBlock) - return messages, msgProofs, err - } - if len(messages) == 0 { - return messages, msgProofs, nil - } - - // double check whether nonce is matched - if messages[0].Nonce != m.withdrawTrie.NextMessageNonce { - log.Error("L2 message nonce mismatch", "expected", m.withdrawTrie.NextMessageNonce, "found", messages[0].Nonce) - return messages, msgProofs, fmt.Errorf("l2 message nonce mismatch, expected: %v, found: %v", m.withdrawTrie.NextMessageNonce, messages[0].Nonce) - } - - var hashes []common.Hash - for _, msg := range messages { - hashes = append(hashes, common.HexToHash(msg.MsgHash)) - } - msgProofs = m.withdrawTrie.AppendMessages(hashes) - - return messages, msgProofs, nil -} diff --git a/bridge-history-api/crossmsg/msg_fetcher_test.go b/bridge-history-api/crossmsg/msg_fetcher_test.go deleted file mode 100644 index 3a20bca7c9..0000000000 --- a/bridge-history-api/crossmsg/msg_fetcher_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package crossmsg_test - -import ( - "crypto/rand" - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/assert" - - "bridge-history-api/crossmsg" -) - -func TestMergeIntoList(t *testing.T) { - headers, err := generateHeaders(64) - assert.NoError(t, err) - assert.Equal(t, headers[0].Hash(), headers[1].ParentHash) - headers2, err := generateHeaders(18) - assert.NoError(t, err) - result := crossmsg.MergeAddIntoHeaderList(headers, headers2, 64) - assert.Equal(t, 64, len(result)) - assert.Equal(t, headers2[len(headers2)-1], result[len(result)-1]) - assert.NotEqual(t, headers[0], result[0]) -} - -func generateHeaders(amount int) ([]*types.Header, error) { - headers := make([]*types.Header, amount) - - for i := 0; i < amount; i++ { - var parentHash common.Hash - if i > 0 { - parentHash = headers[i-1].Hash() - } - nonce, err := rand.Int(rand.Reader, big.NewInt(1<<63-1)) - if err != nil { - return nil, err - } - difficulty := big.NewInt(131072) - - header := &types.Header{ - ParentHash: parentHash, - UncleHash: types.EmptyUncleHash, - Coinbase: common.Address{}, - Root: common.Hash{}, - TxHash: types.EmptyRootHash, - ReceiptHash: types.EmptyRootHash, - Bloom: types.Bloom{}, - Difficulty: difficulty, - Number: big.NewInt(int64(i)), - GasLimit: 5000000, - GasUsed: 0, - Time: uint64(i * 15), - Extra: []byte{}, - MixDigest: common.Hash{}, - Nonce: types.EncodeNonce(nonce.Uint64()), - } - headers[i] = header - } - - return headers, nil -} - -// TODO: add more test cases -// func TestReorg(t *testing.T) diff --git a/bridge-history-api/crossmsg/reorg_handle.go b/bridge-history-api/crossmsg/reorg_handle.go deleted file mode 100644 index 5bcc22c02c..0000000000 --- a/bridge-history-api/crossmsg/reorg_handle.go +++ /dev/null @@ -1,108 +0,0 @@ -package crossmsg - -import ( - "context" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" - - "bridge-history-api/orm" -) - -// ReorgHandling handles reorg function type -type ReorgHandling func(ctx context.Context, reorgHeight uint64, db *gorm.DB) error - -func reverseArray(arr []*types.Header) []*types.Header { - for i := 0; i < len(arr)/2; i++ { - j := len(arr) - i - 1 - arr[i], arr[j] = arr[j], arr[i] - } - return arr -} - -// IsParentAndChild match the child header ParentHash with parent header Hash -func IsParentAndChild(parentHeader *types.Header, header *types.Header) bool { - return header.ParentHash == parentHeader.Hash() -} - -// MergeAddIntoHeaderList merges two header lists, if exceed the max length then drop the oldest entries -func MergeAddIntoHeaderList(baseArr, extraArr []*types.Header, maxLength int) []*types.Header { - mergedArr := append(baseArr, extraArr...) - if len(mergedArr) <= maxLength { - return mergedArr - } - - startIndex := len(mergedArr) - maxLength - return mergedArr[startIndex:] -} - -// BackwardFindReorgBlock finds the reorg block by backward search -func BackwardFindReorgBlock(ctx context.Context, headers []*types.Header, client *ethclient.Client, lastHeader *types.Header) (int, bool, []*types.Header) { - maxStep := len(headers) - backwardHeaderList := []*types.Header{lastHeader} - for iterRound := 0; iterRound < maxStep; iterRound++ { - header, err := client.HeaderByHash(ctx, lastHeader.ParentHash) - if err != nil { - log.Error("BackwardFindReorgBlock failed", "error", err) - return -1, false, nil - } - backwardHeaderList = append(backwardHeaderList, header) - for j := len(headers) - 1; j >= 0; j-- { - if IsParentAndChild(headers[j], header) { - backwardHeaderList = reverseArray(backwardHeaderList) - return j, true, backwardHeaderList - } - } - lastHeader = header - } - return -1, false, nil -} - -// L1ReorgHandling handles l1 reorg -func L1ReorgHandling(ctx context.Context, reorgHeight uint64, db *gorm.DB) error { - l1CrossMsgOrm := orm.NewCrossMsg(db) - relayedOrm := orm.NewRelayedMsg(db) - err := db.Transaction(func(tx *gorm.DB) error { - if err := l1CrossMsgOrm.DeleteL1CrossMsgAfterHeight(ctx, reorgHeight, tx); err != nil { - log.Error("delete l1 cross msg from height", "height", reorgHeight, "err", err) - return err - } - if err := relayedOrm.DeleteL1RelayedHashAfterHeight(ctx, reorgHeight, tx); err != nil { - log.Error("delete l1 relayed msg from height", "height", reorgHeight, "err", err) - return err - } - return nil - }) - if err != nil { - log.Crit("l1 reorg handling failed", "err", err) - } - return err -} - -// L2ReorgHandling handles l2 reorg -func L2ReorgHandling(ctx context.Context, reorgHeight uint64, db *gorm.DB) error { - l2CrossMsgOrm := orm.NewCrossMsg(db) - relayedOrm := orm.NewRelayedMsg(db) - l2SentMsgOrm := orm.NewL2SentMsg(db) - err := db.Transaction(func(tx *gorm.DB) error { - if err := l2CrossMsgOrm.DeleteL2CrossMsgFromHeight(ctx, reorgHeight, tx); err != nil { - log.Error("delete l2 cross msg from height", "height", reorgHeight, "err", err) - return err - } - if err := relayedOrm.DeleteL2RelayedHashAfterHeight(ctx, reorgHeight, tx); err != nil { - log.Error("delete l2 relayed msg from height", "height", reorgHeight, "err", err) - return err - } - if err := l2SentMsgOrm.DeleteL2SentMsgAfterHeight(ctx, reorgHeight, tx); err != nil { - log.Error("delete l2 sent msg from height", "height", reorgHeight, "err", err) - return err - } - return nil - }) - if err != nil { - log.Crit("l2 reorg handling failed", "err", err) - } - return err -} diff --git a/bridge-history-api/go.mod b/bridge-history-api/go.mod index 1b96039704..0c30ea2163 100644 --- a/bridge-history-api/go.mod +++ b/bridge-history-api/go.mod @@ -8,9 +8,9 @@ require ( github.com/gin-contrib/cors v1.4.0 github.com/gin-contrib/pprof v1.4.0 github.com/gin-gonic/gin v1.9.1 + github.com/go-redis/redis/v8 v8.11.5 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.19 - github.com/modern-go/reflect2 v1.0.2 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pressly/goose/v3 v3.7.0 github.com/prometheus/client_golang v1.14.0 @@ -42,6 +42,7 @@ require ( github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/docker v23.0.6+incompatible // indirect github.com/ethereum/c-kzg-4844 v0.3.1 // indirect github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect @@ -90,8 +91,8 @@ require ( github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.27.1 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect diff --git a/bridge-history-api/go.sum b/bridge-history-api/go.sum index bc5bbd8704..9b9b66db10 100644 --- a/bridge-history-api/go.sum +++ b/bridge-history-api/go.sum @@ -85,6 +85,8 @@ github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRk github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/docker/docker v23.0.6+incompatible h1:aBD4np894vatVX99UTx/GyOUOK4uEcROwA3+bQhEcoU= github.com/docker/docker v23.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -148,9 +150,10 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k= github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -347,7 +350,6 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -356,7 +358,6 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= @@ -571,7 +572,6 @@ golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -622,7 +622,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/bridge-history-api/internal/controller/batch_controller.go b/bridge-history-api/internal/controller/batch_controller.go deleted file mode 100644 index 03620f13f9..0000000000 --- a/bridge-history-api/internal/controller/batch_controller.go +++ /dev/null @@ -1,37 +0,0 @@ -package controller - -import ( - "github.com/gin-gonic/gin" - "gorm.io/gorm" - - "bridge-history-api/internal/logic" - "bridge-history-api/internal/types" -) - -// BatchController contains the query claimable txs service -type BatchController struct { - batchLogic *logic.BatchLogic -} - -// NewBatchController return NewBatchController instance -func NewBatchController(db *gorm.DB) *BatchController { - return &BatchController{ - batchLogic: logic.NewBatchLogic(db), - } -} - -// GetWithdrawRootByBatchIndex defines the http get method behavior -func (b *BatchController) GetWithdrawRootByBatchIndex(ctx *gin.Context) { - var req types.QueryByBatchIndexRequest - if err := ctx.ShouldBind(&req); err != nil { - types.RenderFailure(ctx, types.ErrParameterInvalidNo, err) - return - } - result, err := b.batchLogic.GetWithdrawRootByBatchIndex(ctx, req.BatchIndex) - if err != nil { - types.RenderFailure(ctx, types.ErrGetWithdrawRootByBatchIndexFailure, err) - return - } - - types.RenderSuccess(ctx, result) -} diff --git a/bridge-history-api/internal/controller/controller.go b/bridge-history-api/internal/controller/controller.go index d63cb35ee5..b71222a93f 100644 --- a/bridge-history-api/internal/controller/controller.go +++ b/bridge-history-api/internal/controller/controller.go @@ -3,22 +3,20 @@ package controller import ( "sync" + "github.com/go-redis/redis/v8" "gorm.io/gorm" ) var ( // HistoryCtrler is controller instance HistoryCtrler *HistoryController - // BatchCtrler is controller instance - BatchCtrler *BatchController initControllerOnce sync.Once ) // InitController inits Controller with database -func InitController(db *gorm.DB) { +func InitController(db *gorm.DB, redis *redis.Client) { initControllerOnce.Do(func() { - HistoryCtrler = NewHistoryController(db) - BatchCtrler = NewBatchController(db) + HistoryCtrler = NewHistoryController(db, redis) }) } diff --git a/bridge-history-api/internal/controller/history_controller.go b/bridge-history-api/internal/controller/history_controller.go index 6e3932e9ae..f5f42d5a74 100644 --- a/bridge-history-api/internal/controller/history_controller.go +++ b/bridge-history-api/internal/controller/history_controller.go @@ -1,13 +1,16 @@ package controller import ( + "context" + "encoding/json" "errors" + "fmt" "reflect" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/gin-gonic/gin" + "github.com/go-redis/redis/v8" "github.com/patrickmn/go-cache" "golang.org/x/sync/singleflight" "gorm.io/gorm" @@ -17,76 +20,242 @@ import ( ) const ( - cacheKeyPrefixClaimableTxsByAddr = "claimableTxsByAddr:" - cacheKeyPrefixQueryTxsByHash = "queryTxsByHash:" + cacheKeyPrefixL2ClaimableWithdrawalsByAddr = "l2ClaimableWithdrawalsByAddr:" + cacheKeyPrefixL2WithdrawalsByAddr = "l2WithdrawalsByAddr:" + cacheKeyPrefixTxsByAddr = "txsByAddr:" + cacheKeyPrefixQueryTxsByHash = "queryTxsByHash:" ) // HistoryController contains the query claimable txs service type HistoryController struct { historyLogic *logic.HistoryLogic + redis *redis.Client cache *cache.Cache singleFlight singleflight.Group cacheMetrics *cacheMetrics } // NewHistoryController return HistoryController instance -func NewHistoryController(db *gorm.DB) *HistoryController { +func NewHistoryController(db *gorm.DB, redis *redis.Client) *HistoryController { return &HistoryController{ historyLogic: logic.NewHistoryLogic(db), + redis: redis, cache: cache.New(30*time.Second, 10*time.Minute), cacheMetrics: initCacheMetrics(), } } -// GetAllClaimableTxsByAddr defines the http get method behavior -func (c *HistoryController) GetAllClaimableTxsByAddr(ctx *gin.Context) { +// GetL2ClaimableWithdrawalsByAddress defines the http get method behavior +func (c *HistoryController) GetL2ClaimableWithdrawalsByAddress(ctx *gin.Context) { var req types.QueryByAddressRequest if err := ctx.ShouldBind(&req); err != nil { types.RenderFailure(ctx, types.ErrParameterInvalidNo, err) return } - cacheKey := cacheKeyPrefixClaimableTxsByAddr + req.Address - if cachedData, found := c.cache.Get(cacheKey); found { - c.cacheMetrics.cacheHits.WithLabelValues("GetAllClaimableTxsByAddr").Inc() - // Log cache hit along with request param. + cacheKey := fmt.Sprintf("%s%s", cacheKeyPrefixL2ClaimableWithdrawalsByAddr, req.Address) + pagedTxs, total, isHit, err := c.getCachedTxsInfo(ctx, cacheKey, uint64(req.Page), uint64(req.PageSize)) + if err != nil { + log.Error("failed to get cached tx info", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + if isHit { + c.cacheMetrics.cacheHits.WithLabelValues("GetL2ClaimableWithdrawalsByAddress").Inc() log.Info("cache hit", "request", req) - if cachedData == nil { - types.RenderSuccess(ctx, &types.ResultData{}) - return - } else if resultData, ok := cachedData.(*types.ResultData); ok { - types.RenderSuccess(ctx, resultData) - return + resultData := &types.ResultData{Result: pagedTxs, Total: total} + types.RenderSuccess(ctx, resultData) + return + } + + c.cacheMetrics.cacheMisses.WithLabelValues("GetL2ClaimableWithdrawalsByAddress").Inc() + log.Info("cache miss", "request", req) + + result, err, _ := c.singleFlight.Do(cacheKey, func() (interface{}, error) { + var txs []*types.TxHistoryInfo + txs, err = c.historyLogic.GetL2ClaimableWithdrawalsByAddress(ctx, req.Address) + if err != nil { + return nil, err } - // Log error for unexpected type, then fetch data from the database. - log.Error("unexpected type in cache", "expected", "*types.ResultData", "got", reflect.TypeOf(cachedData)) - } else { - c.cacheMetrics.cacheMisses.WithLabelValues("GetAllClaimableTxsByAddr").Inc() - // Log cache miss along with request param. - log.Info("cache miss", "request", req) + return txs, nil + }) + if err != nil { + types.RenderFailure(ctx, types.ErrGetL2WithdrawalsError, err) + return } + txs, ok := result.([]*types.TxHistoryInfo) + if !ok { + log.Error("unexpected type from singleflight", "expected", "[]*types.TxHistoryInfo", "got", reflect.TypeOf(result)) + types.RenderFailure(ctx, types.ErrGetL2WithdrawalsError, errors.New("unexpected error")) + return + } + + err = c.cacheTxsInfo(ctx, cacheKey, txs) + if err != nil { + log.Error("failed to cache txs info", "key", cacheKey, "err", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + pagedTxs, total, isHit, err = c.getCachedTxsInfo(ctx, cacheKey, uint64(req.Page), uint64(req.PageSize)) + if err != nil { + log.Error("failed to get cached tx info", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + if !isHit { + log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + resultData := &types.ResultData{Result: pagedTxs, Total: total} + types.RenderSuccess(ctx, resultData) +} + +// GetL2WithdrawalsByAddress defines the http get method behavior +func (c *HistoryController) GetL2WithdrawalsByAddress(ctx *gin.Context) { + var req types.QueryByAddressRequest + if err := ctx.ShouldBind(&req); err != nil { + types.RenderFailure(ctx, types.ErrParameterInvalidNo, err) + return + } + + cacheKey := fmt.Sprintf("%s%s", cacheKeyPrefixL2WithdrawalsByAddr, req.Address) + pagedTxs, total, isHit, err := c.getCachedTxsInfo(ctx, cacheKey, uint64(req.Page), uint64(req.PageSize)) + if err != nil { + log.Error("failed to get cached tx info", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + if isHit { + c.cacheMetrics.cacheHits.WithLabelValues("GetL2WithdrawalsByAddress").Inc() + log.Info("cache hit", "request", req) + resultData := &types.ResultData{Result: pagedTxs, Total: total} + types.RenderSuccess(ctx, resultData) + return + } + + c.cacheMetrics.cacheMisses.WithLabelValues("GetL2WithdrawalsByAddress").Inc() + log.Info("cache miss", "request", req) + result, err, _ := c.singleFlight.Do(cacheKey, func() (interface{}, error) { - txs, total, err := c.historyLogic.GetClaimableTxsByAddress(ctx, common.HexToAddress(req.Address)) + var txs []*types.TxHistoryInfo + txs, err = c.historyLogic.GetL2WithdrawalsByAddress(ctx, req.Address) if err != nil { return nil, err } - resultData := &types.ResultData{Result: txs, Total: total} - c.cache.Set(cacheKey, resultData, cache.DefaultExpiration) - return resultData, nil + return txs, nil }) + if err != nil { + types.RenderFailure(ctx, types.ErrGetL2WithdrawalsError, err) + return + } + txs, ok := result.([]*types.TxHistoryInfo) + if !ok { + log.Error("unexpected type from singleflight", "expected", "[]*types.TxHistoryInfo", "got", reflect.TypeOf(result)) + types.RenderFailure(ctx, types.ErrGetL2WithdrawalsError, errors.New("unexpected error")) + return + } + + err = c.cacheTxsInfo(ctx, cacheKey, txs) if err != nil { - types.RenderFailure(ctx, types.ErrGetClaimablesFailure, err) + log.Error("failed to cache txs info", "key", cacheKey, "err", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) return } - if resultData, ok := result.(*types.ResultData); ok { + pagedTxs, total, isHit, err = c.getCachedTxsInfo(ctx, cacheKey, uint64(req.Page), uint64(req.PageSize)) + if err != nil { + log.Error("failed to get cached tx info", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + if !isHit { + log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + resultData := &types.ResultData{Result: pagedTxs, Total: total} + types.RenderSuccess(ctx, resultData) +} + +// GetTxsByAddress defines the http get method behavior +func (c *HistoryController) GetTxsByAddress(ctx *gin.Context) { + var req types.QueryByAddressRequest + if err := ctx.ShouldBind(&req); err != nil { + types.RenderFailure(ctx, types.ErrParameterInvalidNo, err) + return + } + + cacheKey := fmt.Sprintf("%s%s", cacheKeyPrefixTxsByAddr, req.Address) + pagedTxs, total, isHit, err := c.getCachedTxsInfo(ctx, cacheKey, uint64(req.Page), uint64(req.PageSize)) + if err != nil { + log.Error("failed to get cached tx info", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + if isHit { + c.cacheMetrics.cacheHits.WithLabelValues("GetTxsByAddress").Inc() + log.Info("cache hit", "request", req) + resultData := &types.ResultData{Result: pagedTxs, Total: total} types.RenderSuccess(ctx, resultData) - } else { - log.Error("unexpected type from singleflight", "expected", "*types.ResultData", "got", reflect.TypeOf(result)) - types.RenderFailure(ctx, types.ErrGetClaimablesFailure, errors.New("unexpected error")) + return + } + + c.cacheMetrics.cacheMisses.WithLabelValues("GetTxsByAddress").Inc() + log.Info("cache miss", "request", req) + + result, err, _ := c.singleFlight.Do(cacheKey, func() (interface{}, error) { + var txs []*types.TxHistoryInfo + txs, err = c.historyLogic.GetTxsByAddress(ctx, req.Address) + if err != nil { + return nil, err + } + return txs, nil + }) + if err != nil { + types.RenderFailure(ctx, types.ErrGetL2WithdrawalsError, err) + return + } + + txs, ok := result.([]*types.TxHistoryInfo) + if !ok { + log.Error("unexpected type from singleflight", "expected", "[]*types.TxHistoryInfo", "got", reflect.TypeOf(result)) + types.RenderFailure(ctx, types.ErrGetL2WithdrawalsError, errors.New("unexpected error")) + return + } + + err = c.cacheTxsInfo(ctx, cacheKey, txs) + if err != nil { + log.Error("failed to cache txs info", "key", cacheKey, "err", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return } + + pagedTxs, total, isHit, err = c.getCachedTxsInfo(ctx, cacheKey, uint64(req.Page), uint64(req.PageSize)) + if err != nil { + log.Error("failed to get cached tx info", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + if !isHit { + log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", req.Page, "page size", req.PageSize, "error", err) + types.RenderFailure(ctx, types.ErrGetTxsError, err) + return + } + + resultData := &types.ResultData{Result: pagedTxs, Total: total} + types.RenderSuccess(ctx, resultData) } // PostQueryTxsByHash defines the http post method behavior @@ -97,8 +266,8 @@ func (c *HistoryController) PostQueryTxsByHash(ctx *gin.Context) { return } - if len(req.Txs) > 10 { - types.RenderFailure(ctx, types.ErrParameterInvalidNo, errors.New("the number of hashes in the request exceeds the allowed maximum of 10")) + if len(req.Txs) > 100 { + types.RenderFailure(ctx, types.ErrParameterInvalidNo, errors.New("the number of hashes in the request exceeds the allowed maximum of 100")) return } hashesMap := make(map[string]struct{}, len(req.Txs)) @@ -112,30 +281,37 @@ func (c *HistoryController) PostQueryTxsByHash(ctx *gin.Context) { hashesMap[hash] = struct{}{} cacheKey := cacheKeyPrefixQueryTxsByHash + hash - if cachedData, found := c.cache.Get(cacheKey); found { + cachedData, err := c.redis.Get(ctx, cacheKey).Bytes() + if err == nil { c.cacheMetrics.cacheHits.WithLabelValues("PostQueryTxsByHash").Inc() // Log cache hit along with tx hash. log.Info("cache hit", "tx hash", hash) - if cachedData == nil { + if len(cachedData) == 0 { continue - } else if txInfo, ok := cachedData.(*types.TxHistoryInfo); ok { - results = append(results, txInfo) } else { - log.Error("unexpected type in cache", "expected", "*types.TxHistoryInfo", "got", reflect.TypeOf(cachedData)) - uncachedHashes = append(uncachedHashes, hash) + var txInfo types.TxHistoryInfo + if err = json.Unmarshal(cachedData, &txInfo); err != nil { + log.Error("failed to unmarshal cached data", "error", err) + uncachedHashes = append(uncachedHashes, hash) + } else { + results = append(results, &txInfo) + } } - } else { + } else if err == redis.Nil { c.cacheMetrics.cacheMisses.WithLabelValues("PostQueryTxsByHash").Inc() // Log cache miss along with tx hash. log.Info("cache miss", "tx hash", hash) uncachedHashes = append(uncachedHashes, hash) + } else { + log.Error("failed to get data from Redis", "error", err) + uncachedHashes = append(uncachedHashes, hash) } } if len(uncachedHashes) > 0 { dbResults, err := c.historyLogic.GetTxsByHashes(ctx, uncachedHashes) if err != nil { - types.RenderFailure(ctx, types.ErrGetTxsByHashFailure, err) + types.RenderFailure(ctx, types.ErrGetTxsByHashError, err) return } @@ -149,9 +325,18 @@ func (c *HistoryController) PostQueryTxsByHash(ctx *gin.Context) { cacheKey := cacheKeyPrefixQueryTxsByHash + hash result, found := resultMap[hash] if found { - c.cache.Set(cacheKey, result, cache.DefaultExpiration) + jsonData, err := json.Marshal(result) + if err != nil { + log.Error("failed to marshal data", "error", err) + } else { + if err := c.redis.Set(ctx, cacheKey, jsonData, 30*time.Minute).Err(); err != nil { + log.Error("failed to set data to Redis", "error", err) + } + } } else { - c.cache.Set(cacheKey, nil, cache.DefaultExpiration) + if err := c.redis.Set(ctx, cacheKey, "", 30*time.Minute).Err(); err != nil { + log.Error("failed to set data to Redis", "error", err) + } } } } @@ -159,3 +344,75 @@ func (c *HistoryController) PostQueryTxsByHash(ctx *gin.Context) { resultData := &types.ResultData{Result: results, Total: uint64(len(results))} types.RenderSuccess(ctx, resultData) } + +func (c *HistoryController) getCachedTxsInfo(ctx context.Context, cacheKey string, pageNum, pageSize uint64) ([]*types.TxHistoryInfo, uint64, bool, error) { + start := int64(pageNum * pageSize) + end := int64((pageNum+1)*pageSize - 1) + + total, err := c.redis.ZCard(ctx, cacheKey).Result() + if err != nil { + if err == redis.Nil { + // Key does not exist, cache miss. + return nil, 0, false, nil + } + log.Error("failed to get zcard result", "error", err) + return nil, 0, false, err + } + + values, err := c.redis.ZRange(ctx, cacheKey, start, end).Result() + if err != nil { + if err == redis.Nil { + // Key does not exist, cache miss. + return nil, 0, false, nil + } + log.Error("failed to get zrange result", "error", err) + return nil, 0, false, err + } + + var pagedTxs []*types.TxHistoryInfo + for _, v := range values { + var tx types.TxHistoryInfo + err := json.Unmarshal([]byte(v), &tx) + if err != nil { + log.Error("failed to unmarshal transaction data", "error", err) + return nil, 0, false, err + } + pagedTxs = append(pagedTxs, &tx) + } + + return pagedTxs, uint64(total), true, nil +} + +func (c *HistoryController) cacheTxsInfo(ctx context.Context, cacheKey string, txs []*types.TxHistoryInfo) error { + err := c.redis.Watch(ctx, func(tx *redis.Tx) error { + pipe := tx.Pipeline() + + // The transactions are sorted, thus we set the score as their indices. + for i, tx := range txs { + if err := pipe.ZAdd(ctx, cacheKey, &redis.Z{Score: float64(i), Member: tx}).Err(); err != nil { + log.Error("failed to add transaction to sorted set", "error", err) + return err + } + } + + if err := pipe.Expire(ctx, cacheKey, 30*time.Minute).Err(); err != nil { + log.Error("failed to set expiry time", "error", err) + return err + } + + _, err := pipe.Exec(ctx) + if err != nil { + log.Error("failed to execute transaction", "error", err) + return err + } + + return nil + }, cacheKey) + + if err != nil { + log.Error("failed to execute transaction", "error", err) + return err + } + + return nil +} diff --git a/bridge-history-api/internal/logic/batch_logic.go b/bridge-history-api/internal/logic/batch_logic.go deleted file mode 100644 index c61ba5aa9f..0000000000 --- a/bridge-history-api/internal/logic/batch_logic.go +++ /dev/null @@ -1,35 +0,0 @@ -package logic - -import ( - "context" - - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" - - "bridge-history-api/orm" -) - -// BatchLogic example service. -type BatchLogic struct { - rollupOrm *orm.RollupBatch -} - -// NewBatchLogic returns services backed with a "db" -func NewBatchLogic(db *gorm.DB) *BatchLogic { - logic := &BatchLogic{rollupOrm: orm.NewRollupBatch(db)} - return logic -} - -// GetWithdrawRootByBatchIndex get withdraw root by batch index from db -func (b *BatchLogic) GetWithdrawRootByBatchIndex(ctx context.Context, batchIndex uint64) (string, error) { - batch, err := b.rollupOrm.GetRollupBatchByIndex(ctx, batchIndex) - if err != nil { - log.Debug("getWithdrawRootByBatchIndex failed", "error", err) - return "", err - } - if batch == nil { - log.Debug("getWithdrawRootByBatchIndex failed", "error", "batch not found") - return "", nil - } - return batch.WithdrawRoot, nil -} diff --git a/bridge-history-api/internal/logic/history_logic.go b/bridge-history-api/internal/logic/history_logic.go index 6bbf48ab34..f4a5b7168b 100644 --- a/bridge-history-api/internal/logic/history_logic.go +++ b/bridge-history-api/internal/logic/history_logic.go @@ -5,183 +5,115 @@ import ( "strconv" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" "gorm.io/gorm" "bridge-history-api/internal/types" "bridge-history-api/orm" ) -// HistoryLogic example service. +// HistoryLogic services. type HistoryLogic struct { - db *gorm.DB + crossMessageOrm *orm.CrossMessage } -// NewHistoryLogic returns services backed with a "db" +// NewHistoryLogic returns bridge history services. func NewHistoryLogic(db *gorm.DB) *HistoryLogic { - logic := &HistoryLogic{db: db} + logic := &HistoryLogic{crossMessageOrm: orm.NewCrossMessage(db)} return logic } -// updateL2TxClaimInfo updates UserClaimInfos for each transaction history. -func updateL2TxClaimInfo(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) { - l2SentMsgOrm := orm.NewL2SentMsg(db) - rollupOrm := orm.NewRollupBatch(db) - - var l2MsgHashes []string - for _, txHistory := range txHistories { - if !txHistory.IsL1 { - l2MsgHashes = append(l2MsgHashes, txHistory.MsgHash) - } - } - - l2sentMsgs, err := l2SentMsgOrm.GetL2SentMsgsByHashes(ctx, l2MsgHashes) - if err != nil || len(l2sentMsgs) == 0 { - log.Debug("GetL2SentMsgsByHashes failed", "l2 sent msgs", l2sentMsgs, "error", err) - return - } - - l2MsgMap := make(map[string]*orm.L2SentMsg, len(l2sentMsgs)) - var batchIndexes []uint64 - for _, l2sentMsg := range l2sentMsgs { - l2MsgMap[l2sentMsg.MsgHash] = l2sentMsg - batchIndexes = append(batchIndexes, l2sentMsg.BatchIndex) - } - - batches, err := rollupOrm.GetRollupBatchesByIndexes(ctx, batchIndexes) +// GetL2ClaimableWithdrawalsByAddress gets all claimable withdrawal txs under given address. +func (h *HistoryLogic) GetL2ClaimableWithdrawalsByAddress(ctx context.Context, address string) ([]*types.TxHistoryInfo, error) { + messages, err := h.crossMessageOrm.GetL2ClaimableWithdrawalsByAddress(ctx, address) if err != nil { - log.Debug("GetRollupBatchesByIndexes failed", "error", err) - return - } - - batchMap := make(map[uint64]*orm.RollupBatch, len(batches)) - for _, batch := range batches { - batchMap[batch.BatchIndex] = batch + return nil, err } - - for _, txHistory := range txHistories { - if txHistory.IsL1 { - continue - } - - l2sentMsg, foundL2SentMsg := l2MsgMap[txHistory.MsgHash] - batch, foundBatch := batchMap[l2sentMsg.BatchIndex] - if foundL2SentMsg && foundBatch { - txHistory.ClaimInfo = &types.UserClaimInfo{ - From: l2sentMsg.Sender, - To: l2sentMsg.Target, - Value: l2sentMsg.Value, - Nonce: strconv.FormatUint(l2sentMsg.Nonce, 10), - Message: l2sentMsg.MsgData, - Proof: "0x" + l2sentMsg.MsgProof, - BatchHash: batch.BatchHash, - BatchIndex: strconv.FormatUint(l2sentMsg.BatchIndex, 10), - } - } + var txHistories []*types.TxHistoryInfo + for _, message := range messages { + txHistories = append(txHistories, getTxHistoryInfo(message)) } + return txHistories, err } -func updateCrossTxHashes(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) { - msgHashes := make([]string, len(txHistories)) - for i, txHistory := range txHistories { - msgHashes[i] = txHistory.MsgHash - } - - relayed := orm.NewRelayedMsg(db) - relayedMsgs, err := relayed.GetRelayedMsgsByHashes(ctx, msgHashes) - if err != nil || len(relayedMsgs) == 0 { - log.Debug("GetRelayedMsgsByHashes failed", "msg hashes", msgHashes, "relayed msgs", relayedMsgs, "error", err) - return - } - - relayedMsgMap := make(map[string]*orm.RelayedMsg, len(relayedMsgs)) - for _, relayedMsg := range relayedMsgs { - relayedMsgMap[relayedMsg.MsgHash] = relayedMsg +// GetL2WithdrawalsByAddress gets all withdrawal txs under given address. +func (h *HistoryLogic) GetL2WithdrawalsByAddress(ctx context.Context, address string) ([]*types.TxHistoryInfo, error) { + messages, err := h.crossMessageOrm.GetL2WithdrawalsByAddress(ctx, address) + if err != nil { + return nil, err } - - for _, txHistory := range txHistories { - if relayedMsg, found := relayedMsgMap[txHistory.MsgHash]; found { - txHistory.FinalizeTx.Hash = relayedMsg.Layer1Hash + relayedMsg.Layer2Hash - txHistory.FinalizeTx.BlockNumber = relayedMsg.Height - } + var txHistories []*types.TxHistoryInfo + for _, message := range messages { + txHistories = append(txHistories, getTxHistoryInfo(message)) } + return txHistories, err } -func updateCrossTxHashesAndL2TxClaimInfo(ctx context.Context, txHistories []*types.TxHistoryInfo, db *gorm.DB) { - updateCrossTxHashes(ctx, txHistories, db) - updateL2TxClaimInfo(ctx, txHistories, db) -} - -// GetClaimableTxsByAddress get all claimable txs under given address -func (h *HistoryLogic) GetClaimableTxsByAddress(ctx context.Context, address common.Address) ([]*types.TxHistoryInfo, uint64, error) { - var txHistories []*types.TxHistoryInfo - l2SentMsgOrm := orm.NewL2SentMsg(h.db) - l2CrossMsgOrm := orm.NewCrossMsg(h.db) - results, err := l2SentMsgOrm.GetClaimableL2SentMsgByAddress(ctx, address.Hex()) - if err != nil || len(results) == 0 { - return txHistories, 0, err - } - var msgHashList []string - for _, result := range results { - msgHashList = append(msgHashList, result.MsgHash) - } - crossMsgs, err := l2CrossMsgOrm.GetL2CrossMsgByMsgHashList(ctx, msgHashList) - // crossMsgs can be empty, because they can be emitted by user directly call contract +// GetTxsByAddress gets tx infos under given address. +func (h *HistoryLogic) GetTxsByAddress(ctx context.Context, address string) ([]*types.TxHistoryInfo, error) { + messages, err := h.crossMessageOrm.GetTxsByAddress(ctx, address) if err != nil { - return txHistories, 0, err - } - crossMsgMap := make(map[string]*orm.CrossMsg) - for _, crossMsg := range crossMsgs { - crossMsgMap[crossMsg.MsgHash] = crossMsg + return nil, err } - for _, result := range results { - txInfo := &types.TxHistoryInfo{ - Hash: result.TxHash, - MsgHash: result.MsgHash, - IsL1: false, - BlockNumber: result.Height, - FinalizeTx: &types.Finalized{}, - } - if crossMsg, exist := crossMsgMap[result.MsgHash]; exist { - txInfo.Amount = crossMsg.Amount - txInfo.To = crossMsg.Target - txInfo.BlockTimestamp = crossMsg.Timestamp - txInfo.CreatedAt = crossMsg.CreatedAt - txInfo.L1Token = crossMsg.Layer1Token - txInfo.L2Token = crossMsg.Layer2Token - } - txHistories = append(txHistories, txInfo) + var txHistories []*types.TxHistoryInfo + for _, message := range messages { + txHistories = append(txHistories, getTxHistoryInfo(message)) } - updateL2TxClaimInfo(ctx, txHistories, h.db) - return txHistories, uint64(len(results)), err + return txHistories, err } -// GetTxsByHashes get tx infos under given tx hashes -func (h *HistoryLogic) GetTxsByHashes(ctx context.Context, hashes []string) ([]*types.TxHistoryInfo, error) { - CrossMsgOrm := orm.NewCrossMsg(h.db) - results, err := CrossMsgOrm.GetCrossMsgsByHashes(ctx, hashes) +// GetTxsByHashes gets tx infos under given tx hashes. +func (h *HistoryLogic) GetTxsByHashes(ctx context.Context, txHashes []string) ([]*types.TxHistoryInfo, error) { + messages, err := h.crossMessageOrm.GetMessagesByTxHashes(ctx, txHashes) if err != nil { return nil, err } - var txHistories []*types.TxHistoryInfo - for _, result := range results { - txHistory := &types.TxHistoryInfo{ - Hash: result.Layer1Hash + result.Layer2Hash, - MsgHash: result.MsgHash, - Amount: result.Amount, - To: result.Target, - L1Token: result.Layer1Token, - L2Token: result.Layer2Token, - IsL1: orm.MsgType(result.MsgType) == orm.Layer1Msg, - BlockNumber: result.Height, - BlockTimestamp: result.Timestamp, - CreatedAt: result.CreatedAt, - FinalizeTx: &types.Finalized{Hash: ""}, - } - txHistories = append(txHistories, txHistory) + for _, message := range messages { + txHistories = append(txHistories, getTxHistoryInfo(message)) } - - updateCrossTxHashesAndL2TxClaimInfo(ctx, txHistories, h.db) return txHistories, nil } + +func getTxHistoryInfo(message *orm.CrossMessage) *types.TxHistoryInfo { + txHistory := &types.TxHistoryInfo{ + MsgHash: message.MessageHash, + Amount: message.TokenAmounts, + L1Token: message.L1TokenAddress, + L2Token: message.L2TokenAddress, + IsL1: orm.MessageType(message.MessageType) == orm.MessageTypeL1, + TxStatus: orm.TxStatusType(message.TxStatus), + CreatedAt: &message.CreatedAt, + } + if txHistory.IsL1 { + txHistory.Hash = message.L1TxHash + txHistory.BlockNumber = message.L1BlockNumber + } else { + txHistory.Hash = message.L2TxHash + txHistory.BlockNumber = message.L2BlockNumber + } + if orm.RollupStatusType(message.RollupStatus) == orm.RollupStatusTypeFinalized { + if txHistory.IsL1 { + txHistory.FinalizeTx = &types.Finalized{ + Hash: message.L2TxHash, + BlockNumber: message.L2BlockNumber, + IsFinalized: true, + } + } else { + txHistory.FinalizeTx = &types.Finalized{ + Hash: message.L1TxHash, + BlockNumber: message.L1BlockNumber, + IsFinalized: orm.RollupStatusType(message.RollupStatus) == orm.RollupStatusTypeFinalized, + } + } + txHistory.ClaimInfo = &types.UserClaimInfo{ + From: message.MessageFrom, + To: message.MessageTo, + Value: message.MessageValue, + Nonce: strconv.FormatUint(message.MessageNonce, 10), + Message: message.MessageData, + Proof: common.Bytes2Hex(message.MerkleProof), + BatchIndex: strconv.FormatUint(message.BatchIndex, 10), + } + } + return txHistory +} diff --git a/bridge-history-api/internal/route/route.go b/bridge-history-api/internal/route/route.go index e8dae24175..5ca2d2b2e2 100644 --- a/bridge-history-api/internal/route/route.go +++ b/bridge-history-api/internal/route/route.go @@ -26,5 +26,7 @@ func Route(router *gin.Engine, conf *config.Config, reg prometheus.Registerer) { r := router.Group("api/") r.POST("/txsbyhashes", controller.HistoryCtrler.PostQueryTxsByHash) - r.GET("/claimable", controller.HistoryCtrler.GetAllClaimableTxsByAddr) + r.GET("/claimablewithdrawals", controller.HistoryCtrler.GetL2ClaimableWithdrawalsByAddress) + r.GET("/withdrawals", controller.HistoryCtrler.GetL2WithdrawalsByAddress) + r.GET("/txs", controller.HistoryCtrler.GetTxsByAddress) } diff --git a/bridge-history-api/internal/types/history_types.go b/bridge-history-api/internal/types/types.go similarity index 54% rename from bridge-history-api/internal/types/history_types.go rename to bridge-history-api/internal/types/types.go index f564643858..d4715042b7 100644 --- a/bridge-history-api/internal/types/history_types.go +++ b/bridge-history-api/internal/types/types.go @@ -5,28 +5,32 @@ import ( "time" "github.com/gin-gonic/gin" + + "bridge-history-api/orm" ) const ( - // Success shows OK. + // Success indicates that the operation was successful. Success = 0 - // InternalServerError shows a fatal error in the server + // InternalServerError represents a fatal error occurring on the server. InternalServerError = 500 - // ErrParameterInvalidNo is invalid params + // ErrParameterInvalidNo represents an error when the parameters are invalid. ErrParameterInvalidNo = 40001 - // ErrGetClaimablesFailure is getting all claimables txs error - ErrGetClaimablesFailure = 40002 - // ErrGetTxsByHashFailure is getting txs by hash list error - ErrGetTxsByHashFailure = 40003 - // ErrGetTxsByAddrFailure is getting txs by address error - ErrGetTxsByAddrFailure = 40004 - // ErrGetWithdrawRootByBatchIndexFailure is getting withdraw root by batch index error - ErrGetWithdrawRootByBatchIndexFailure = 40005 + // ErrGetL2ClaimableWithdrawalsError represents an error when trying to get l2 claimable withdrawal transactions. + ErrGetL2ClaimableWithdrawalsError = 40002 + // ErrGetL2WithdrawalsError represents an error when trying to get l2 withdrawal transactions by address. + ErrGetL2WithdrawalsError = 40003 + // ErrGetTxsError represents an error when trying to get transactions by address. + ErrGetTxsError = 40004 + // ErrGetTxsByHashError represents an error when trying to get transactions by hash list. + ErrGetTxsByHashError = 40005 ) // QueryByAddressRequest the request parameter of address api type QueryByAddressRequest struct { - Address string `form:"address" binding:"required"` + Address string `form:"address" binding:"required"` + Page int `form:"page" binding:"required"` + PageSize int `form:"page_size" binding:"required"` } // QueryByHashRequest the request parameter of hash api @@ -34,12 +38,6 @@ type QueryByHashRequest struct { Txs []string `raw:"txs" binding:"required"` } -// QueryByBatchIndexRequest the request parameter of batch index api -type QueryByBatchIndexRequest struct { - // BatchIndex can not be 0, because we dont decode the genesis block - BatchIndex uint64 `form:"batch_index" binding:"required"` -} - // ResultData contains return txs and total type ResultData struct { Result []*TxHistoryInfo `json:"result"` @@ -55,12 +53,9 @@ type Response struct { // Finalized the schema of tx finalized infos type Finalized struct { - Hash string `json:"hash"` - Amount string `json:"amount"` - To string `json:"to"` // useless - IsL1 bool `json:"isL1"` - BlockNumber uint64 `json:"blockNumber"` - BlockTimestamp *time.Time `json:"blockTimestamp"` // uselesss + Hash string `json:"hash"` + BlockNumber uint64 `json:"blockNumber"` + IsFinalized bool `json:"isFinalized"` } // UserClaimInfo the schema of tx claim infos @@ -69,7 +64,6 @@ type UserClaimInfo struct { To string `json:"to"` Value string `json:"value"` Nonce string `json:"nonce"` - BatchHash string `json:"batch_hash"` Message string `json:"message"` Proof string `json:"proof"` BatchIndex string `json:"batch_index"` @@ -77,18 +71,17 @@ type UserClaimInfo struct { // TxHistoryInfo the schema of tx history infos type TxHistoryInfo struct { - Hash string `json:"hash"` - MsgHash string `json:"msgHash"` - Amount string `json:"amount"` - To string `json:"to"` // useless - IsL1 bool `json:"isL1"` - L1Token string `json:"l1Token"` - L2Token string `json:"l2Token"` - BlockNumber uint64 `json:"blockNumber"` - BlockTimestamp *time.Time `json:"blockTimestamp"` // useless - FinalizeTx *Finalized `json:"finalizeTx"` - ClaimInfo *UserClaimInfo `json:"claimInfo"` - CreatedAt *time.Time `json:"createdTime"` + Hash string `json:"hash"` + MsgHash string `json:"msgHash"` + Amount string `json:"amount"` + IsL1 bool `json:"isL1"` + L1Token string `json:"l1Token"` + L2Token string `json:"l2Token"` + BlockNumber uint64 `json:"blockNumber"` + TxStatus orm.TxStatusType `json:"txStatus"` + FinalizeTx *Finalized `json:"finalizeTx"` + ClaimInfo *UserClaimInfo `json:"claimInfo"` + CreatedAt *time.Time `json:"createdTime"` } // RenderJSON renders response with json diff --git a/bridge-history-api/orm/batch.go b/bridge-history-api/orm/batch.go deleted file mode 100644 index 4bee91db96..0000000000 --- a/bridge-history-api/orm/batch.go +++ /dev/null @@ -1,114 +0,0 @@ -package orm - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" -) - -// RollupBatch is the struct for rollup_batch table -type RollupBatch struct { - db *gorm.DB `gorm:"column:-"` - - ID uint64 `json:"id" gorm:"column:id"` - BatchIndex uint64 `json:"batch_index" gorm:"column:batch_index"` - BatchHash string `json:"batch_hash" gorm:"column:batch_hash"` - CommitHeight uint64 `json:"commit_height" gorm:"column:commit_height"` - StartBlockNumber uint64 `json:"start_block_number" gorm:"column:start_block_number"` - EndBlockNumber uint64 `json:"end_block_number" gorm:"column:end_block_number"` - WithdrawRoot string `json:"withdraw_root" gorm:"column:withdraw_root;default:NULL"` - CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"` - UpdatedAt *time.Time `json:"updated_at" gorm:"column:updated_at"` - DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"column:deleted_at;default:NULL"` -} - -// NewRollupBatch create an RollupBatch instance -func NewRollupBatch(db *gorm.DB) *RollupBatch { - return &RollupBatch{db: db} -} - -// TableName returns the table name for the Batch model. -func (*RollupBatch) TableName() string { - return "rollup_batch" -} - -// GetLatestRollupBatchProcessedHeight return latest processed height from rollup_batch table -func (r *RollupBatch) GetLatestRollupBatchProcessedHeight(ctx context.Context) (uint64, error) { - var result RollupBatch - err := r.db.WithContext(ctx).Unscoped().Select("commit_height").Order("id desc").First(&result).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("RollupBatch.GetLatestRollupBatchProcessedHeight error: %w", err) - } - return result.CommitHeight, nil -} - -// GetLatestRollupBatch return the latest rollup batch in db -func (r *RollupBatch) GetLatestRollupBatch(ctx context.Context) (*RollupBatch, error) { - var result RollupBatch - err := r.db.WithContext(ctx).Model(&RollupBatch{}).Where("batch_hash is not NULL").Order("batch_index desc").First(&result).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, fmt.Errorf("RollupBatch.GetLatestRollupBatch error: %w", err) - } - return &result, nil -} - -// GetRollupBatchByIndex return the rollup batch by index -func (r *RollupBatch) GetRollupBatchByIndex(ctx context.Context, index uint64) (*RollupBatch, error) { - var result RollupBatch - err := r.db.WithContext(ctx).Model(&RollupBatch{}).Where("batch_index = ?", index).First(&result).Error - if err != nil { - return nil, fmt.Errorf("RollupBatch.GetRollupBatchByIndex error: %w", err) - } - return &result, nil -} - -// GetRollupBatchesByIndexes return the rollup batches by indexes -func (r *RollupBatch) GetRollupBatchesByIndexes(ctx context.Context, indexes []uint64) ([]*RollupBatch, error) { - var results []*RollupBatch - err := r.db.WithContext(ctx).Model(&RollupBatch{}).Where("batch_index IN (?)", indexes).Find(&results).Error - if err != nil { - return nil, fmt.Errorf("RollupBatch.GetRollupBatchesByIndexes error: %w", err) - } - return results, nil -} - -// InsertRollupBatch batch insert rollup batch into db and return the transaction -func (r *RollupBatch) InsertRollupBatch(ctx context.Context, batches []*RollupBatch, dbTx ...*gorm.DB) error { - if len(batches) == 0 { - return nil - } - db := r.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - err := db.WithContext(ctx).Model(&RollupBatch{}).Create(&batches).Error - if err != nil { - batchIndexes := make([]uint64, 0, len(batches)) - heights := make([]uint64, 0, len(batches)) - for _, batch := range batches { - batchIndexes = append(batchIndexes, batch.BatchIndex) - heights = append(heights, batch.CommitHeight) - } - log.Error("failed to insert rollup batch", "batchIndexes", batchIndexes, "heights", heights) - return fmt.Errorf("RollupBatch.InsertRollupBatch error: %w", err) - } - return nil -} - -// UpdateRollupBatchWithdrawRoot updates the withdraw_root column in rollup_batch table -func (r *RollupBatch) UpdateRollupBatchWithdrawRoot(ctx context.Context, batchIndex uint64, withdrawRoot string) error { - err := r.db.WithContext(ctx).Model(&RollupBatch{}).Where("batch_index = ?", batchIndex).Update("withdraw_root", withdrawRoot).Error - if err != nil { - return fmt.Errorf("RollupBatch.UpdateRuollupBatch error: %w", err) - } - return nil -} diff --git a/bridge-history-api/orm/cross_message.go b/bridge-history-api/orm/cross_message.go new file mode 100644 index 0000000000..3dc7649f13 --- /dev/null +++ b/bridge-history-api/orm/cross_message.go @@ -0,0 +1,340 @@ +package orm + +import ( + "context" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +// TokenType represents the type of token. +type TokenType int + +// Constants for TokenType. +const ( + TokenTypeUnknown TokenType = iota + TokenTypeETH + TokenTypeERC20 + TokenTypeERC721 + TokenTypeERC1155 +) + +// MessageType represents the type of message. +type MessageType int + +// Constants for MessageType. +const ( + MessageTypeUnknown MessageType = iota + MessageTypeL1 + MessageTypeL2 +) + +// TxStatusType represents the status of a transaction. +type TxStatusType int + +// Constants for TxStatusType. +const ( + TxStatusTypeSent TxStatusType = iota + TxStatusTypeSentFailed + TxStatusTypeRelayed + TxStatusTypeRelayedFailed + TxStatusTypeSkipped + TxStatusTypeDropped +) + +// RollupStatusType represents the status of a rollup. +type RollupStatusType int + +// Constants for RollupStatusType. +const ( + RollupStatusTypeUncommitted RollupStatusType = iota + RollupStatusTypeCommitted + RollupStatusTypeFinalized +) + +// BatchEventType represents the type of batch event. +type BatchEventType int + +// Constants for BatchEventType. +const ( + BatchEventTypeUnknown BatchEventType = iota + BatchEventTypeCommitBatch + BatchEventTypeRevertBatch + BatchEventTypeFinalizeBatch +) + +// BatchEvent struct represents the details of a batch event. +type BatchEvent struct { + Type BatchEventType + BatchIndex uint64 + StartBlockNumber uint64 + EndBlockNumber uint64 +} + +// MessageQueueEventType represents the type of message queue event. +type MessageQueueEventType int + +// Constants for MessageQueueEventType. +const ( + MessageQueueEventTypeUnknown MessageQueueEventType = iota + MessageQueueEventTypeQueueTransaction + MessageQueueEventTypeDequeueTransaction + MessageQueueEventTypeDropTransaction +) + +// MessageQueueEvent struct represents the details of a batch event. +type MessageQueueEvent struct { + Type MessageQueueEventType + MessageHash common.Hash + QueueIndex uint64 + TxHash common.Hash +} + +// CrossMessage represents a cross message. +type CrossMessage struct { + db *gorm.DB `gorm:"column:-"` + + ID uint64 `json:"id" gorm:"column:id;primary_key"` + MessageType int `json:"message_type" gorm:"column:message_type"` + QueueIndex uint64 `json:"queue_index" gorm:"column:queue_index"` + TxStatus int `json:"tx_status" gorm:"column:tx_status"` + RollupStatus int `json:"rollup_status" gorm:"column:rollup_status"` + TokenType int `json:"token_type" gorm:"column:token_type"` + Sender string `json:"sender" gorm:"column:sender"` + Receiver string `json:"receiver" gorm:"column:receiver"` + MessageHash string `json:"message_hash" gorm:"column:message_hash"` + L1TxHash string `json:"l1_tx_hash" gorm:"column:l1_tx_hash"` + L2TxHash string `json:"l2_tx_hash" gorm:"column:l2_tx_hash"` + L1BlockNumber uint64 `json:"l1_block_number" gorm:"column:l1_block_number"` + L2BlockNumber uint64 `json:"l2_block_number" gorm:"column:l2_block_number"` + L1TokenAddress string `json:"l1_token_address" gorm:"column:l1_token_address"` + L2TokenAddress string `json:"l2_token_address" gorm:"column:l2_token_address"` + TokenIDs string `json:"token_ids" gorm:"column:token_ids"` + TokenAmounts string `json:"token_amounts" gorm:"column:token_amounts"` + BlockTimestamp uint64 `json:"block_timestamp" gorm:"column:block_timestamp"` + MessageFrom string `json:"message_from" gorm:"column:message_from"` + MessageTo string `json:"message_to" gorm:"column:message_to"` + MessageValue string `json:"message_value" gorm:"column:message_value"` + MessageNonce uint64 `json:"message_nonce" gorm:"column:message_nonce"` + MessageData string `json:"message_data" gorm:"column:message_data"` + MerkleProof []byte `json:"merkle_proof" gorm:"column:merkle_proof"` + BatchIndex uint64 `json:"batch_index" gorm:"column:batch_index"` + CreatedAt time.Time `json:"created_at" gorm:"column:created_at"` + UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"` + DeletedAt *time.Time `json:"deleted_at" gorm:"column:deleted_at"` +} + +// TableName returns the table name for the CrossMessage model. +func (*CrossMessage) TableName() string { + return "cross_message" +} + +// NewCrossMessage returns a new instance of CrossMessage. +func NewCrossMessage(db *gorm.DB) *CrossMessage { + return &CrossMessage{db: db} +} + +// GetLatestMessage returns the latest processed cross message from the database for a given message type. +func (c *CrossMessage) GetLatestMessage(ctx context.Context, messageType MessageType) (*CrossMessage, error) { + var message CrossMessage + db := c.db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + db = db.Where("message_type = ?", messageType) + db = db.Where("tx_status != ?", TxStatusTypeSentFailed) + db = db.Order("id DESC") + if err := db.First(&message).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return nil, fmt.Errorf("failed to get latest l1 processed height, error: %w", err) + } + return &message, nil +} + +// GetMessagesByTxHashes retrieves all cross messages from the database that match the provided transaction hashes. +func (c *CrossMessage) GetMessagesByTxHashes(ctx context.Context, txHashes []string) ([]*CrossMessage, error) { + var messages []*CrossMessage + db := c.db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + db = db.Where("l1_tx_hash IN (?) OR l2_tx_hash IN (?)", txHashes, txHashes) + if err := db.Find(&messages).Error; err != nil { + return nil, fmt.Errorf("failed to get l2 messages by tx hashes, tx hashes: %v, error: %w", txHashes, err) + } + return messages, nil +} + +// GetL2ClaimableWithdrawalsByAddress retrieves all l2 claimable withdrawal messages for a given sender address. +func (c *CrossMessage) GetL2ClaimableWithdrawalsByAddress(ctx context.Context, sender string) ([]*CrossMessage, error) { + var messages []*CrossMessage + db := c.db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + db = db.Where("message_type = ?", MessageTypeL2) + db = db.Where("tx_status = ?", TxStatusTypeSent) + db = db.Where("rollup_status = ?", RollupStatusTypeFinalized) + db = db.Where("sender = ?", sender) + db = db.Order("block_timestamp DESC") + db = db.Limit(500) + if err := db.Find(&messages).Error; err != nil { + return nil, fmt.Errorf("failed to get l2 claimable withdrawal messages by sender address, sender: %v, error: %w", sender, err) + } + return messages, nil +} + +// GetL2WithdrawalsByAddress retrieves all l2 claimable withdrawal messages for a given sender address. +func (c *CrossMessage) GetL2WithdrawalsByAddress(ctx context.Context, sender string) ([]*CrossMessage, error) { + var messages []*CrossMessage + db := c.db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + db = db.Where("message_type = ?", MessageTypeL2) + db = db.Where("sender = ?", sender) + db = db.Order("block_timestamp DESC") + db = db.Limit(500) + if err := db.Find(&messages).Error; err != nil { + return nil, fmt.Errorf("failed to get l2 withdrawal messages by sender address, sender: %v, error: %w", sender, err) + } + return messages, nil +} + +// GetTxsByAddress retrieves all txs for a given sender address. +func (c *CrossMessage) GetTxsByAddress(ctx context.Context, sender string) ([]*CrossMessage, error) { + var messages []*CrossMessage + db := c.db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + db = db.Where("sender = ?", sender) + db = db.Order("block_timestamp DESC") + db = db.Limit(500) + if err := db.Find(&messages).Error; err != nil { + return nil, fmt.Errorf("failed to get all txs by sender address, sender: %v, error: %w", sender, err) + } + return messages, nil +} + +// UpdateL1MessageQueueEventsInfo updates the information about l1 message queue events in the database. +func (c *CrossMessage) UpdateL1MessageQueueEventsInfo(ctx context.Context, l1MessageQueueEvents []*MessageQueueEvent, dbTX ...*gorm.DB) error { + originalDB := c.db + if len(dbTX) > 0 && dbTX[0] != nil { + originalDB = dbTX[0] + } + originalDB = originalDB.WithContext(ctx) + originalDB = originalDB.Model(&CrossMessage{}) + for _, l1MessageQueueEvent := range l1MessageQueueEvents { + db := originalDB + if l1MessageQueueEvent.Type == MessageQueueEventTypeQueueTransaction { + updateFields := make(map[string]interface{}) + // Update tx hash if it's a message replay. + updateFields["l1_tx_hash"] = l1MessageQueueEvent.TxHash + updateFields["queue_index"] = l1MessageQueueEvent.QueueIndex + db = db.Where("message_hash = ?", l1MessageQueueEvent.MessageHash) + if err := db.Updates(updateFields).Error; err != nil { + return fmt.Errorf("failed to update l1 tx hash of QueueTransaction, event: %+v, error: %w", l1MessageQueueEvent, err) + } + } + if l1MessageQueueEvent.Type == MessageQueueEventTypeDequeueTransaction { + updateFields := make(map[string]interface{}) + updateFields["tx_status"] = TxStatusTypeSkipped + db = db.Where("queue_index = ?", l1MessageQueueEvent.QueueIndex) + if err := db.Updates(updateFields).Error; err != nil { + return fmt.Errorf("failed to update message status as skipped, event: %+v, error: %w", l1MessageQueueEvent, err) + } + } + if l1MessageQueueEvent.Type == MessageQueueEventTypeDropTransaction { + updateFields := make(map[string]interface{}) + updateFields["tx_status"] = TxStatusTypeDropped + db = db.Where("queue_index = ?", l1MessageQueueEvent.QueueIndex) + if err := db.Updates(updateFields).Error; err != nil { + return fmt.Errorf("failed to update message status as dropped, event: %+v, error: %w", l1MessageQueueEvent, err) + } + } + } + return nil +} + +// InsertMessages inserts a list of cross messages into the database. +func (c *CrossMessage) InsertMessages(ctx context.Context, messages []*CrossMessage, dbTX ...*gorm.DB) error { + db := c.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + for _, message := range messages { + if err := db.Create(message).Error; err != nil { + return fmt.Errorf("failed to insert message, message: %+v, error: %w", message, err) + } + } + return nil +} + +// UpdateL1RelayedMessagesOfL2Withdrawals updates the database with a list of l1 relayed messages related to l2 withdrawals. +func (c *CrossMessage) UpdateL1RelayedMessagesOfL2Withdrawals(ctx context.Context, l1RelayedMessages []*CrossMessage, dbTX ...*gorm.DB) error { + db := c.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + db = db.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "message_hash"}}, + DoUpdates: clause.AssignmentColumns([]string{"l1_block_number", "l1_tx_hash", "tx_status"}), + }) + for _, l1RelayedMessage := range l1RelayedMessages { + result := db.Create(l1RelayedMessage) + if result.Error != nil { + return fmt.Errorf("failed to update l1 relayed message of l2 withdraw, l1 relayed message: %+v, error: %w", l1RelayedMessage, result.Error) + } + } + return nil +} + +// UpdateBatchIndexOfL2Withdrawals updates the batch index and rollup status of l2 withdrawals in the database according to a list of batch events. +func (c *CrossMessage) UpdateBatchIndexOfL2Withdrawals(ctx context.Context, l1BatchEvents []*BatchEvent, dbTX ...*gorm.DB) error { + originalDB := c.db + if len(dbTX) > 0 && dbTX[0] != nil { + originalDB = dbTX[0] + } + originalDB = originalDB.WithContext(ctx) + originalDB = originalDB.Model(&CrossMessage{}) + + for _, l1BatchEvent := range l1BatchEvents { + db := originalDB + updateFields := make(map[string]interface{}) + if l1BatchEvent.Type == BatchEventTypeCommitBatch { + db = db.Where("l1_block_number BETWEEN ? AND ?", l1BatchEvent.StartBlockNumber, l1BatchEvent.EndBlockNumber) + updateFields["batch_index"] = l1BatchEvent.BatchIndex + updateFields["rollup_status"] = RollupStatusTypeCommitted + } + if l1BatchEvent.Type == BatchEventTypeRevertBatch { + db = db.Where("batch_index = ?", l1BatchEvent.BatchIndex) + updateFields["batch_index"] = 0 + updateFields["rollup_status"] = RollupStatusTypeUncommitted + } + if l1BatchEvent.Type == BatchEventTypeFinalizeBatch { + db = db.Where("batch_index = ?", l1BatchEvent.BatchIndex) + updateFields["rollup_status"] = RollupStatusTypeFinalized + } + if err := db.Updates(updateFields).Error; err != nil { + return fmt.Errorf("failed to update batch index of l2 withdrawals, batch: %+v, error: %w", l1BatchEvent, err) + } + } + return nil +} + +// UpdateL2RelayedMessagesOfL1Deposits updates the database with a list of l2 relayed messages related to l1 deposits. +func (c *CrossMessage) UpdateL2RelayedMessagesOfL1Deposits(ctx context.Context, l2RelayedMessages []*CrossMessage, dbTX ...*gorm.DB) error { + db := c.db.WithContext(ctx) + db = db.Model(&CrossMessage{}) + db = db.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "message_hash"}}, + DoUpdates: clause.AssignmentColumns([]string{"l2_block_number", "l2_tx_hash", "tx_status"}), + }) + for _, l2RelayedMessage := range l2RelayedMessages { + result := db.Create(l2RelayedMessage) + if result.Error != nil { + return fmt.Errorf("failed to update l2 relayed message of l1 deposit, l2 relayed message: %+v, error: %w", l2RelayedMessage, result.Error) + } + } + return nil +} diff --git a/bridge-history-api/orm/cross_msg.go b/bridge-history-api/orm/cross_msg.go deleted file mode 100644 index b989720d51..0000000000 --- a/bridge-history-api/orm/cross_msg.go +++ /dev/null @@ -1,381 +0,0 @@ -package orm - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" -) - -// AssetType can be ETH/ERC20/ERC1155/ERC721 -type AssetType int - -// MsgType can be layer1/layer2 msg -type MsgType int - -func (a AssetType) String() string { - switch a { - case ETH: - return "ETH" - case ERC20: - return "ERC20" - case ERC1155: - return "ERC1155" - case ERC721: - return "ERC721" - } - return "Unknown Asset Type" -} - -const ( - // ETH = 0 - ETH AssetType = iota - // ERC20 = 1 - ERC20 - // ERC721 = 2 - ERC721 - // ERC1155 = 3 - ERC1155 -) - -const ( - // UnknownMsg = 0 - UnknownMsg MsgType = iota - // Layer1Msg = 1 - Layer1Msg - // Layer2Msg = 2 - Layer2Msg -) - -// CrossMsg represents a cross message from layer 1 to layer 2 -type CrossMsg struct { - db *gorm.DB `gorm:"column:-"` - - ID uint64 `json:"id" gorm:"column:id"` - MsgHash string `json:"msg_hash" gorm:"column:msg_hash"` - Height uint64 `json:"height" gorm:"column:height"` - Sender string `json:"sender" gorm:"column:sender"` - Target string `json:"target" gorm:"column:target"` - Amount string `json:"amount" gorm:"column:amount"` - Layer1Hash string `json:"layer1_hash" gorm:"column:layer1_hash;default:''"` - Layer2Hash string `json:"layer2_hash" gorm:"column:layer2_hash;default:''"` - Layer1Token string `json:"layer1_token" gorm:"column:layer1_token;default:''"` - Layer2Token string `json:"layer2_token" gorm:"column:layer2_token;default:''"` - TokenIDs string `json:"token_ids" gorm:"column:token_ids;default:''"` - TokenAmounts string `json:"token_amounts" gorm:"column:token_amounts;default:''"` - Asset int `json:"asset" gorm:"column:asset"` - MsgType int `json:"msg_type" gorm:"column:msg_type"` - Timestamp *time.Time `json:"timestamp" gorm:"column:block_timestamp;default;NULL"` - CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"` - UpdatedAt *time.Time `json:"updated_at" gorm:"column:updated_at"` - DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"column:deleted_at;default:NULL"` -} - -// TableName returns the table name for the CrossMsg model. -func (*CrossMsg) TableName() string { - return "cross_message" -} - -// NewCrossMsg returns a new instance of CrossMsg. -func NewCrossMsg(db *gorm.DB) *CrossMsg { - return &CrossMsg{db: db} -} - -// L1 Cross Msgs Operations - -// GetL1CrossMsgByHash returns layer1 cross message by given hash -func (c *CrossMsg) GetL1CrossMsgByHash(ctx context.Context, l1Hash common.Hash) (*CrossMsg, error) { - var result CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer1_hash = ? AND msg_type = ?", l1Hash.String(), Layer1Msg).First(&result).Error - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil - } - return nil, fmt.Errorf("CrossMsg.GetL1CrossMsgByHash error: %w", err) - } - return &result, nil -} - -// GetLatestL1ProcessedHeight returns the latest processed height of layer1 cross messages -func (c *CrossMsg) GetLatestL1ProcessedHeight(ctx context.Context) (uint64, error) { - var result CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("msg_type = ?", Layer1Msg). - Select("height"). - Order("id DESC"). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("CrossMsg.GetLatestL1ProcessedHeight error: %w", err) - } - return result.Height, nil -} - -// GetL1EarliestNoBlockTimestampHeight returns the earliest layer1 cross message height which has no block timestamp -func (c *CrossMsg) GetL1EarliestNoBlockTimestampHeight(ctx context.Context) (uint64, error) { - var result CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Where("block_timestamp IS NULL AND msg_type = ?", Layer1Msg). - Select("height"). - Order("height ASC"). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("CrossMsg.GetL1EarliestNoBlockTimestampHeight error: %w", err) - } - return result.Height, nil -} - -// InsertL1CrossMsg batch insert layer1 cross messages into db -func (c *CrossMsg) InsertL1CrossMsg(ctx context.Context, messages []*CrossMsg, dbTx ...*gorm.DB) error { - if len(messages) == 0 { - return nil - } - db := c.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&CrossMsg{}).Create(&messages).Error - if err != nil { - l1hashes := make([]string, 0, len(messages)) - heights := make([]uint64, 0, len(messages)) - for _, msg := range messages { - l1hashes = append(l1hashes, msg.Layer1Hash) - heights = append(heights, msg.Height) - } - log.Error("failed to insert l1 cross messages", "l1hashes", l1hashes, "heights", heights, "err", err) - return fmt.Errorf("CrossMsg.InsertL1CrossMsg error: %w", err) - } - return nil -} - -// UpdateL1CrossMsgHash update l1 cross msg hash in db, no need to check msg_type since layer1_hash wont be empty if its layer1 msg -func (c *CrossMsg) UpdateL1CrossMsgHash(ctx context.Context, l1Hash, msgHash common.Hash, dbTx ...*gorm.DB) error { - db := c.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := c.db.Model(&CrossMsg{}).Where("layer1_hash = ?", l1Hash.Hex()).Update("msg_hash", msgHash.Hex()).Error - if err != nil { - return fmt.Errorf("CrossMsg.UpdateL1CrossMsgHash error: %w", err) - } - return nil - -} - -// UpdateL1BlockTimestamp update layer1 block timestamp -func (c *CrossMsg) UpdateL1BlockTimestamp(ctx context.Context, height uint64, timestamp time.Time) error { - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Where("height = ? AND msg_type = ?", height, Layer1Msg). - Update("block_timestamp", timestamp).Error - if err != nil { - return fmt.Errorf("CrossMsg.UpdateL1BlockTimestamp error: %w", err) - } - return err -} - -// DeleteL1CrossMsgAfterHeight soft delete layer1 cross messages after given height -func (c *CrossMsg) DeleteL1CrossMsgAfterHeight(ctx context.Context, height uint64, dbTx ...*gorm.DB) error { - db := c.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Delete(&CrossMsg{}, "height > ? AND msg_type = ?", height, Layer1Msg).Error - if err != nil { - return fmt.Errorf("CrossMsg.DeleteL1CrossMsgAfterHeight error: %w", err) - } - return nil -} - -// L2 Cross Msgs Operations - -// GetL2CrossMsgByHash returns layer2 cross message by given hash -func (c *CrossMsg) GetL2CrossMsgByHash(ctx context.Context, l2Hash common.Hash) (*CrossMsg, error) { - var result CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer2_hash = ? AND msg_type = ?", l2Hash.String(), Layer2Msg).First(&result).Error - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil - } - return nil, fmt.Errorf("CrossMsg.GetL2CrossMsgByHash error: %w", err) - } - return &result, nil -} - -// GetLatestL2ProcessedHeight returns the latest processed height of layer2 cross messages -func (c *CrossMsg) GetLatestL2ProcessedHeight(ctx context.Context) (uint64, error) { - var result CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Select("height"). - Where("msg_type = ?", Layer2Msg). - Order("id DESC"). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("CrossMsg.GetLatestL2ProcessedHeight error: %w", err) - } - return result.Height, nil -} - -// GetL2CrossMsgByMsgHashList returns layer2 cross messages under given msg hashes -func (c *CrossMsg) GetL2CrossMsgByMsgHashList(ctx context.Context, msgHashList []string) ([]*CrossMsg, error) { - var results []*CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Where("msg_hash IN (?) AND msg_type = ?", msgHashList, Layer2Msg). - Find(&results). - Error - - if err != nil { - return nil, fmt.Errorf("CrossMsg.GetL2CrossMsgByMsgHashList error: %w", err) - } - if len(results) == 0 { - log.Debug("no CrossMsg under given msg hashes", "msg hash list", msgHashList) - } - return results, nil -} - -// GetL2EarliestNoBlockTimestampHeight returns the earliest layer2 cross message height which has no block timestamp -func (c *CrossMsg) GetL2EarliestNoBlockTimestampHeight(ctx context.Context) (uint64, error) { - var result CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Where("block_timestamp IS NULL AND msg_type = ?", Layer2Msg). - Select("height"). - Order("height ASC"). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("CrossMsg.GetL2EarliestNoBlockTimestampHeight error: %w", err) - } - return result.Height, nil -} - -// InsertL2CrossMsg batch insert layer2 cross messages -func (c *CrossMsg) InsertL2CrossMsg(ctx context.Context, messages []*CrossMsg, dbTx ...*gorm.DB) error { - if len(messages) == 0 { - return nil - } - db := c.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&CrossMsg{}).Create(&messages).Error - if err != nil { - l2hashes := make([]string, 0, len(messages)) - heights := make([]uint64, 0, len(messages)) - for _, msg := range messages { - l2hashes = append(l2hashes, msg.Layer2Hash) - heights = append(heights, msg.Height) - } - log.Error("failed to insert l2 cross messages", "l2hashes", l2hashes, "heights", heights, "err", err) - return fmt.Errorf("CrossMsg.InsertL2CrossMsg error: %w", err) - } - return nil -} - -// UpdateL2CrossMsgHash update layer2 cross message hash -func (c *CrossMsg) UpdateL2CrossMsgHash(ctx context.Context, l2Hash, msgHash common.Hash, dbTx ...*gorm.DB) error { - db := c.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&CrossMsg{}). - Where("layer2_hash = ?", l2Hash.String()). - Update("msg_hash", msgHash.String()). - Error - if err != nil { - return fmt.Errorf("CrossMsg.UpdateL2CrossMsgHash error: %w", err) - } - return nil -} - -// UpdateL2BlockTimestamp update layer2 cross message block timestamp -func (c *CrossMsg) UpdateL2BlockTimestamp(ctx context.Context, height uint64, timestamp time.Time) error { - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Where("height = ? AND msg_type = ?", height, Layer2Msg). - Update("block_timestamp", timestamp).Error - if err != nil { - return fmt.Errorf("CrossMsg.UpdateL2BlockTimestamp error: %w", err) - } - return nil -} - -// DeleteL2CrossMsgFromHeight delete layer2 cross messages from given height -func (c *CrossMsg) DeleteL2CrossMsgFromHeight(ctx context.Context, height uint64, dbTx ...*gorm.DB) error { - db := c.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&CrossMsg{}).Delete("height > ? AND msg_type = ?", height, Layer2Msg).Error - if err != nil { - return fmt.Errorf("CrossMsg.DeleteL2CrossMsgFromHeight error: %w", err) - - } - return nil -} - -// General Operations - -// GetTotalCrossMsgCountByAddress get total cross msg count by address -func (c *CrossMsg) GetTotalCrossMsgCountByAddress(ctx context.Context, sender string) (uint64, error) { - var count int64 - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Where("sender = ?", sender). - Count(&count). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("CrossMsg.GetTotalCrossMsgCountByAddress error: %w", err) - - } - return uint64(count), nil -} - -// GetCrossMsgsByAddressWithOffset get cross msgs by address with offset -func (c *CrossMsg) GetCrossMsgsByAddressWithOffset(ctx context.Context, sender string, offset int, limit int) ([]CrossMsg, error) { - var messages []CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}). - Where("sender = ?", sender). - Order("block_timestamp DESC NULLS FIRST, id DESC"). - Limit(limit). - Offset(offset). - Find(&messages). - Error - if err != nil { - return nil, fmt.Errorf("CrossMsg.GetCrossMsgsByAddressWithOffset error: %w", err) - } - return messages, nil -} - -// GetCrossMsgsByHashes retrieves a list of cross messages identified by their Layer 1 or Layer 2 hashes. -func (c *CrossMsg) GetCrossMsgsByHashes(ctx context.Context, hashes []string) ([]*CrossMsg, error) { - var results []*CrossMsg - err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer1_hash IN (?) OR layer2_hash IN (?)", hashes, hashes).Find(&results).Error - if err != nil { - return nil, fmt.Errorf("CrossMsg.GetCrossMsgsByHashes error: %w", err) - } - - return results, nil -} diff --git a/bridge-history-api/orm/l2_sent_msg.go b/bridge-history-api/orm/l2_sent_msg.go deleted file mode 100644 index 5717b67259..0000000000 --- a/bridge-history-api/orm/l2_sent_msg.go +++ /dev/null @@ -1,268 +0,0 @@ -package orm - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" -) - -// L2SentMsg defines the struct for l2_sent_msg table record -type L2SentMsg struct { - db *gorm.DB `gorm:"column:-"` - - ID uint64 `json:"id" gorm:"column:id"` - OriginalSender string `json:"original_sender" gorm:"column:original_sender;default:''"` - TxHash string `json:"tx_hash" gorm:"column:tx_hash"` - MsgHash string `json:"msg_hash" gorm:"column:msg_hash"` - Sender string `json:"sender" gorm:"column:sender"` - Target string `json:"target" gorm:"column:target"` - Value string `json:"value" gorm:"column:value"` - Height uint64 `json:"height" gorm:"column:height"` - Nonce uint64 `json:"nonce" gorm:"column:nonce"` - BatchIndex uint64 `json:"batch_index" gorm:"column:batch_index;default:0"` - MsgProof string `json:"msg_proof" gorm:"column:msg_proof;default:''"` - MsgData string `json:"msg_data" gorm:"column:msg_data;default:''"` - CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"` - UpdatedAt *time.Time `json:"updated_at" gorm:"column:updated_at"` - DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"column:deleted_at;default:NULL"` -} - -// NewL2SentMsg create an NewL2SentMsg instance -func NewL2SentMsg(db *gorm.DB) *L2SentMsg { - return &L2SentMsg{db: db} -} - -// TableName returns the table name for the L2SentMsg model. -func (*L2SentMsg) TableName() string { - return "l2_sent_msg" -} - -// GetL2SentMsgByHash get l2 sent msg by hash -func (l *L2SentMsg) GetL2SentMsgByHash(ctx context.Context, msgHash string) (*L2SentMsg, error) { - var result L2SentMsg - err := l.db.WithContext(ctx).Model(&L2SentMsg{}). - Where("msg_hash = ?", msgHash). - First(&result). - Error - if err != nil { - return nil, fmt.Errorf("L2SentMsg.GetL2SentMsgByHash error: %w", err) - } - return &result, nil -} - -// GetL2SentMsgsByHashes get l2 sent msgs by hashes -func (l *L2SentMsg) GetL2SentMsgsByHashes(ctx context.Context, msgHashes []string) ([]*L2SentMsg, error) { - var results []*L2SentMsg - err := l.db.WithContext(ctx).Model(&L2SentMsg{}). - Where("msg_hash IN (?)", msgHashes). - Find(&results). - Error - if err != nil { - return nil, fmt.Errorf("L2SentMsg.GetL2SentMsgsByHashes error: %w", err) - } - return results, nil -} - -// GetLatestSentMsgHeightOnL2 get latest sent msg height on l2 -func (l *L2SentMsg) GetLatestSentMsgHeightOnL2(ctx context.Context) (uint64, error) { - var result L2SentMsg - err := l.db.WithContext(ctx).Model(&L2SentMsg{}). - Select("height"). - Order("nonce DESC"). - First(&result).Error - - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("L2SentMsg.GetLatestSentMsgHeightOnL2 error: %w", err) - - } - return result.Height, nil -} - -// GetClaimableL2SentMsgByAddress returns both the total number of unclaimed messages and a paginated list of those messages. -// TODO: Add metrics about the result set sizes (total/claimed/unclaimed messages). -func (l *L2SentMsg) GetClaimableL2SentMsgByAddress(ctx context.Context, address string) ([]*L2SentMsg, error) { - var totalMsgs []*L2SentMsg - db := l.db.WithContext(ctx) - db = db.Table("l2_sent_msg") - db = db.Where("original_sender = ? OR sender = ?", address, address) - db = db.Where("msg_proof != ''") - db = db.Where("deleted_at IS NULL") - db = db.Order("id DESC") - tx := db.Find(&totalMsgs) - if tx.Error != nil || tx.RowsAffected == 0 { - return nil, tx.Error - } - - // Note on the use of IN vs VALUES in SQL Queries: - // ------------------------------------------------ - // When using the IN predicate with a large list (>100) of values, performance may suffer. - // An alternative approach is to use constant subqueries with the VALUES construct. - // For more details and optimization tips, visit: - // https://postgres.cz/wiki/PostgreSQL_SQL_Tricks_I#Predicate_IN_optimalization - // - // Example using IN: - // SELECT * FROM tab WHERE x IN (1,2,3,...,n); -- where n > 70 - // - // Optimized example using VALUES: - // SELECT * FROM tab WHERE x IN (VALUES(10), (20)); - // - var valuesStr string - for _, msg := range totalMsgs { - valuesStr += fmt.Sprintf("('%s'),", msg.MsgHash) - } - valuesStr = strings.TrimSuffix(valuesStr, ",") - - var claimedMsgHashes []string - db = l.db.WithContext(ctx) - db = db.Table("relayed_msg") - db = db.Where(fmt.Sprintf("msg_hash IN (VALUES %s)", valuesStr)) - db = db.Where("deleted_at IS NULL") - if err := db.Pluck("msg_hash", &claimedMsgHashes).Error; err != nil { - return nil, err - } - - claimedMsgHashSet := make(map[string]struct{}) - for _, hash := range claimedMsgHashes { - claimedMsgHashSet[hash] = struct{}{} - } - var unclaimedL2Msgs []*L2SentMsg - for _, msg := range totalMsgs { - if _, found := claimedMsgHashSet[msg.MsgHash]; !found { - unclaimedL2Msgs = append(unclaimedL2Msgs, msg) - } - } - - return unclaimedL2Msgs, nil -} - -// GetLatestL2SentMsgBatchIndex get latest l2 sent msg batch index -func (l *L2SentMsg) GetLatestL2SentMsgBatchIndex(ctx context.Context) (int64, error) { - var result L2SentMsg - err := l.db.WithContext(ctx).Model(&L2SentMsg{}). - Where("batch_index != 0"). - Order("batch_index DESC"). - Select("batch_index"). - First(&result). - Error - if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { - return -1, nil - } - if err != nil { - return -1, fmt.Errorf("L2SentMsg.GetLatestL2SentMsgBatchIndex error: %w", err) - } - // Watch for overflow, tho its not likely to happen - return int64(result.BatchIndex), nil -} - -// GetL2SentMsgMsgHashByHeightRange get l2 sent msg msg hash by height range -func (l *L2SentMsg) GetL2SentMsgMsgHashByHeightRange(ctx context.Context, startHeight, endHeight uint64) ([]*L2SentMsg, error) { - var results []*L2SentMsg - err := l.db.WithContext(ctx).Model(&L2SentMsg{}). - Where("height >= ? AND height <= ?", startHeight, endHeight). - Order("nonce ASC"). - Find(&results). - Error - if err != nil { - return nil, fmt.Errorf("L2SentMsg.GetL2SentMsgMsgHashByHeightRange error: %w", err) - } - return results, nil -} - -// GetL2SentMessageByNonce get l2 sent message by nonce -func (l *L2SentMsg) GetL2SentMessageByNonce(ctx context.Context, nonce uint64) (*L2SentMsg, error) { - var result L2SentMsg - err := l.db.WithContext(ctx).Model(&L2SentMsg{}). - Where("nonce = ?", nonce). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, fmt.Errorf("L2SentMsg.GetL2SentMessageByNonce error: %w", err) - - } - return &result, nil -} - -// GetLatestL2SentMsgLEHeight get latest l2 sent msg less than or equal to end block number -func (l *L2SentMsg) GetLatestL2SentMsgLEHeight(ctx context.Context, endBlockNumber uint64) (*L2SentMsg, error) { - var result L2SentMsg - err := l.db.WithContext(ctx).Model(&L2SentMsg{}). - Where("height <= ?", endBlockNumber). - Order("nonce DESC"). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, fmt.Errorf("L2SentMsg.GetLatestL2SentMsgLEHeight error: %w", err) - - } - return &result, nil -} - -// InsertL2SentMsg batch insert l2 sent msg -func (l *L2SentMsg) InsertL2SentMsg(ctx context.Context, messages []*L2SentMsg, dbTx ...*gorm.DB) error { - if len(messages) == 0 { - return nil - } - db := l.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&L2SentMsg{}).Create(&messages).Error - if err != nil { - l2hashes := make([]string, 0, len(messages)) - heights := make([]uint64, 0, len(messages)) - for _, msg := range messages { - l2hashes = append(l2hashes, msg.TxHash) - heights = append(heights, msg.Height) - } - log.Error("failed to insert l2 sent messages", "l2hashes", l2hashes, "heights", heights, "err", err) - return fmt.Errorf("L2SentMsg.InsertL2SentMsg error: %w", err) - } - return nil -} - -// UpdateL2MessageProof update l2 message proof in db tx -func (l *L2SentMsg) UpdateL2MessageProof(ctx context.Context, msgHash string, proof string, batchIndex uint64, dbTx ...*gorm.DB) error { - db := l.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&L2SentMsg{}). - Where("msg_hash = ?", msgHash). - Updates(map[string]interface{}{ - "msg_proof": proof, - "batch_index": batchIndex, - }).Error - if err != nil { - return fmt.Errorf("L2SentMsg.UpdateL2MessageProof error: %w", err) - } - return nil -} - -// DeleteL2SentMsgAfterHeight delete l2 sent msg after height -func (l *L2SentMsg) DeleteL2SentMsgAfterHeight(ctx context.Context, height uint64, dbTx ...*gorm.DB) error { - db := l.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - err := db.WithContext(ctx).Model(&L2SentMsg{}).Delete("height > ?", height).Error - if err != nil { - return fmt.Errorf("L2SentMsg.DeleteL2SentMsgAfterHeight error: %w", err) - } - return nil -} diff --git a/bridge-history-api/orm/l2_sent_msg_test.go b/bridge-history-api/orm/l2_sent_msg_test.go deleted file mode 100644 index 8cf1c67a36..0000000000 --- a/bridge-history-api/orm/l2_sent_msg_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package orm - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - - "bridge-history-api/orm/migrate" - - "scroll-tech/common/database" - "scroll-tech/common/docker" -) - -func TestGetClaimableL2SentMsgByAddress(t *testing.T) { - base := docker.NewDockerApp() - base.RunDBImage(t) - - db, err := database.InitDB( - &database.Config{ - DSN: base.DBConfig.DSN, - DriverName: base.DBConfig.DriverName, - MaxOpenNum: base.DBConfig.MaxOpenNum, - MaxIdleNum: base.DBConfig.MaxIdleNum, - }, - ) - assert.NoError(t, err) - - sqlDB, err := db.DB() - assert.NoError(t, err) - assert.NoError(t, migrate.ResetDB(sqlDB)) - - l2SentMsgOrm := NewL2SentMsg(db) - relayedMsgOrm := NewRelayedMsg(db) - - msgs, err := l2SentMsgOrm.GetClaimableL2SentMsgByAddress(context.Background(), "sender1") - assert.NoError(t, err) - assert.Len(t, msgs, 0) - - l2SentMsgs := []*L2SentMsg{ - { - Sender: "sender1", - MsgHash: "hash1", - MsgProof: "proof1", - Nonce: 0, - }, - { - OriginalSender: "sender1", - MsgHash: "hash2", - MsgProof: "proof2", - Nonce: 1, - }, - { - OriginalSender: "sender1", - MsgHash: "hash3", - MsgProof: "", - Nonce: 2, - }, - } - relayedMsgs := []*RelayedMsg{ - { - MsgHash: "hash2", - }, - { - MsgHash: "hash3", - }, - } - err = l2SentMsgOrm.InsertL2SentMsg(context.Background(), l2SentMsgs) - assert.NoError(t, err) - err = relayedMsgOrm.InsertRelayedMsg(context.Background(), relayedMsgs) - assert.NoError(t, err) - - msgs, err = l2SentMsgOrm.GetClaimableL2SentMsgByAddress(context.Background(), "sender1") - assert.NoError(t, err) - assert.Len(t, msgs, 1) - assert.Equal(t, "hash1", msgs[0].MsgHash) -} diff --git a/bridge-history-api/orm/migrate/migrations/00001_cross_message.sql b/bridge-history-api/orm/migrate/migrations/00001_cross_message.sql new file mode 100644 index 0000000000..2e96916dea --- /dev/null +++ b/bridge-history-api/orm/migrate/migrations/00001_cross_message.sql @@ -0,0 +1,44 @@ +-- +goose Up +-- +goose StatementBegin +create table cross_message +( + id BIGSERIAL PRIMARY KEY, + message_type SMALLINT NOT NULL, + queue_index BIGINT NOT NULL, + tx_status SMALLINT NOT NULL, + rollup_status SMALLINT NOT NULL, + token_type SMALLINT NOT NULL, + sender VARCHAR NOT NULL, + receiver VARCHAR NOT NULL, + + message_hash VARCHAR DEFAULT NULL, -- NULL for failed txs + l1_tx_hash VARCHAR DEFAULT NULL, + l2_tx_hash VARCHAR DEFAULT NULL, + l1_block_number BIGINT DEFAULT NULL, + l2_block_number BIGINT DEFAULT NULL, + l1_token_address VARCHAR DEFAULT NULL, + l2_token_address VARCHAR DEFAULT NULL, + token_ids VARCHAR DEFAULT NULL, + token_amounts VARCHAR NOT NULL, + block_timestamp BIGINT NOT NULL, -- timestamp to sort L1 Deposit & L2 Withdraw events altogether + +--- claim info + message_from VARCHAR DEFAULT NULL, + message_to VARCHAR DEFAULT NULL, + message_value VARCHAR DEFAULT NULL, + message_nonce BIGINT DEFAULT NULL, + message_data VARCHAR DEFAULT NULL, + merkle_proof BYTEA DEFAULT NULL, + batch_index BIGINT DEFAULT NULL, + +-- metadata + created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP(0) DEFAULT NULL +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +drop table if exists cross_message; +-- +goose StatementEnd diff --git a/bridge-history-api/orm/migrate/migrations/00001_cross_msg.sql b/bridge-history-api/orm/migrate/migrations/00001_cross_msg.sql deleted file mode 100644 index b22859634d..0000000000 --- a/bridge-history-api/orm/migrate/migrations/00001_cross_msg.sql +++ /dev/null @@ -1,57 +0,0 @@ --- +goose Up --- +goose StatementBegin -create table cross_message -( - id BIGSERIAL PRIMARY KEY, - msg_hash VARCHAR NOT NULL, - height BIGINT NOT NULL, - sender VARCHAR NOT NULL, - target VARCHAR NOT NULL, - amount VARCHAR NOT NULL, - layer1_hash VARCHAR NOT NULL DEFAULT '', - layer2_hash VARCHAR NOT NULL DEFAULT '', - layer1_token VARCHAR NOT NULL DEFAULT '', - layer2_token VARCHAR NOT NULL DEFAULT '', - asset SMALLINT NOT NULL, - msg_type SMALLINT NOT NULL, - token_ids TEXT NOT NULL DEFAULT '', - token_amounts TEXT NOT NULL DEFAULT '', - block_timestamp TIMESTAMP(0) DEFAULT NULL, - created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP(0) DEFAULT NULL -); - -create unique index uk_msg_hash_msg_type -on cross_message (msg_hash, msg_type) where deleted_at IS NULL; - -comment -on column cross_message.asset is 'ETH, ERC20, ERC721, ERC1155'; - -comment -on column cross_message.msg_type is 'unknown, l1msg, l2msg'; - -CREATE INDEX idx_l1_msg_index ON cross_message (layer1_hash, deleted_at); - -CREATE INDEX idx_l2_msg_index ON cross_message (layer2_hash, deleted_at); - -CREATE INDEX idx_height_msg_type_index ON cross_message (height, msg_type, deleted_at); - -CREATE OR REPLACE FUNCTION update_timestamp() -RETURNS TRIGGER AS $$ -BEGIN - NEW.updated_at = CURRENT_TIMESTAMP; - RETURN NEW; -END; -$$ language 'plpgsql'; - -CREATE TRIGGER update_timestamp BEFORE UPDATE -ON cross_message FOR EACH ROW EXECUTE PROCEDURE -update_timestamp(); - --- +goose StatementEnd - --- +goose Down --- +goose StatementBegin -drop table if exists cross_message; --- +goose StatementEnd diff --git a/bridge-history-api/orm/migrate/migrations/00002_relayed_msg.sql b/bridge-history-api/orm/migrate/migrations/00002_relayed_msg.sql deleted file mode 100644 index 27f6557d2d..0000000000 --- a/bridge-history-api/orm/migrate/migrations/00002_relayed_msg.sql +++ /dev/null @@ -1,41 +0,0 @@ --- +goose Up --- +goose StatementBegin -create table relayed_msg -( - id BIGSERIAL PRIMARY KEY, - msg_hash VARCHAR NOT NULL, - height BIGINT NOT NULL, - layer1_hash VARCHAR NOT NULL DEFAULT '', - layer2_hash VARCHAR NOT NULL DEFAULT '', - created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP(0) DEFAULT NULL -); - -create unique index uk_msg_hash_l1_hash_l2_hash -on relayed_msg (msg_hash, layer1_hash, layer2_hash) where deleted_at IS NULL; - -CREATE INDEX idx_l1_msg_relayed_msg ON relayed_msg (layer1_hash, deleted_at); - -CREATE INDEX idx_l2_msg_relayed_msg ON relayed_msg (layer2_hash, deleted_at); - -CREATE INDEX idx_msg_hash_deleted_at_relayed_msg on relayed_msg (msg_hash, deleted_at); - -CREATE OR REPLACE FUNCTION update_timestamp() -RETURNS TRIGGER AS $$ -BEGIN - NEW.updated_at = CURRENT_TIMESTAMP; - RETURN NEW; -END; -$$ language 'plpgsql'; - -CREATE TRIGGER update_timestamp BEFORE UPDATE -ON relayed_msg FOR EACH ROW EXECUTE PROCEDURE -update_timestamp(); - --- +goose StatementEnd - --- +goose Down --- +goose StatementBegin -drop table if exists relayed_msg; --- +goose StatementEnd \ No newline at end of file diff --git a/bridge-history-api/orm/migrate/migrations/00003_l2_sent_msg.sql b/bridge-history-api/orm/migrate/migrations/00003_l2_sent_msg.sql deleted file mode 100644 index 9903e09a0b..0000000000 --- a/bridge-history-api/orm/migrate/migrations/00003_l2_sent_msg.sql +++ /dev/null @@ -1,47 +0,0 @@ --- +goose Up --- +goose StatementBegin -create table l2_sent_msg -( - id BIGSERIAL PRIMARY KEY, - original_sender VARCHAR NOT NULL DEFAULT '', - tx_hash VARCHAR NOT NULL, - sender VARCHAR NOT NULL, - target VARCHAR NOT NULL, - value VARCHAR NOT NULL, - msg_hash VARCHAR NOT NULL, - height BIGINT NOT NULL, - nonce BIGINT NOT NULL, - batch_index BIGINT NOT NULL DEFAULT 0, - msg_proof TEXT NOT NULL DEFAULT '', - msg_data TEXT NOT NULL DEFAULT '', - created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP(0) DEFAULT NULL -); - -create unique index uk_msg_hash -on l2_sent_msg (msg_hash) where deleted_at IS NULL; - -create unique index uk_nonce -on l2_sent_msg (nonce) where deleted_at IS NULL; - -CREATE INDEX idx_msg_hash_deleted_at_l2_sent_msg on l2_sent_msg (msg_hash, deleted_at); - -CREATE OR REPLACE FUNCTION update_timestamp() -RETURNS TRIGGER AS $$ -BEGIN - NEW.updated_at = CURRENT_TIMESTAMP; - RETURN NEW; -END; -$$ language 'plpgsql'; - -CREATE TRIGGER update_timestamp BEFORE UPDATE -ON l2_sent_msg FOR EACH ROW EXECUTE PROCEDURE -update_timestamp(); - --- +goose StatementEnd - --- +goose Down --- +goose StatementBegin -drop table if exists l2_sent_msg; --- +goose StatementEnd \ No newline at end of file diff --git a/bridge-history-api/orm/migrate/migrations/00004_rollup_batch.sql b/bridge-history-api/orm/migrate/migrations/00004_rollup_batch.sql deleted file mode 100644 index ac3e344033..0000000000 --- a/bridge-history-api/orm/migrate/migrations/00004_rollup_batch.sql +++ /dev/null @@ -1,40 +0,0 @@ --- +goose Up --- +goose StatementBegin -create table rollup_batch -( - id BIGSERIAL PRIMARY KEY, - batch_index BIGINT NOT NULL, - commit_height BIGINT NOT NULL, - start_block_number BIGINT NOT NULL, - end_block_number BIGINT NOT NULL, - batch_hash VARCHAR NOT NULL, - withdraw_root TEXT DEFAULT NULL, - created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP(0) DEFAULT NULL -); - -create unique index uk_batch_index -on rollup_batch (batch_index) where deleted_at IS NULL; - -create unique index uk_batch_hash -on rollup_batch (batch_hash) where deleted_at IS NULL; - -CREATE OR REPLACE FUNCTION update_timestamp() -RETURNS TRIGGER AS $$ -BEGIN - NEW.updated_at = CURRENT_TIMESTAMP; - RETURN NEW; -END; -$$ language 'plpgsql'; - -CREATE TRIGGER update_timestamp BEFORE UPDATE -ON rollup_batch FOR EACH ROW EXECUTE PROCEDURE -update_timestamp(); - --- +goose StatementEnd - --- +goose Down --- +goose StatementBegin -drop table if exists rollup_batch; --- +goose StatementEnd \ No newline at end of file diff --git a/bridge-history-api/orm/relayed_msg.go b/bridge-history-api/orm/relayed_msg.go deleted file mode 100644 index 43f2459d76..0000000000 --- a/bridge-history-api/orm/relayed_msg.go +++ /dev/null @@ -1,155 +0,0 @@ -package orm - -import ( - "context" - "fmt" - "time" - - "github.com/ethereum/go-ethereum/log" - "gorm.io/gorm" -) - -// RelayedMsg is the struct for relayed_msg table -type RelayedMsg struct { - db *gorm.DB `gorm:"column:-"` - - ID uint64 `json:"id" gorm:"column:id"` - MsgHash string `json:"msg_hash" gorm:"column:msg_hash"` - Height uint64 `json:"height" gorm:"column:height"` - Layer1Hash string `json:"layer1_hash" gorm:"column:layer1_hash;default:''"` - Layer2Hash string `json:"layer2_hash" gorm:"column:layer2_hash;default:''"` - CreatedAt *time.Time `json:"created_at" gorm:"column:created_at"` - UpdatedAt *time.Time `json:"updated_at" gorm:"column:updated_at"` - DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"column:deleted_at;default:NULL"` -} - -// NewRelayedMsg create an NewRelayedMsg instance -func NewRelayedMsg(db *gorm.DB) *RelayedMsg { - return &RelayedMsg{db: db} -} - -// TableName returns the table name for the RelayedMsg model. -func (*RelayedMsg) TableName() string { - return "relayed_msg" -} - -// GetRelayedMsgByHash get relayed msg by hash -func (r *RelayedMsg) GetRelayedMsgByHash(ctx context.Context, msgHash string) (*RelayedMsg, error) { - var result RelayedMsg - err := r.db.WithContext(ctx).Model(&RelayedMsg{}). - Where("msg_hash = ?", msgHash). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, fmt.Errorf("RelayedMsg.GetRelayedMsgByHash error: %w", err) - } - return &result, nil -} - -// GetRelayedMsgsByHashes get relayed msg by hash array -func (r *RelayedMsg) GetRelayedMsgsByHashes(ctx context.Context, msgHashes []string) ([]*RelayedMsg, error) { - var results []*RelayedMsg - err := r.db.WithContext(ctx).Model(&RelayedMsg{}). - Where("msg_hash IN (?)", msgHashes). - Find(&results). - Error - if err != nil { - return nil, fmt.Errorf("RelayedMsg.GetRelayedMsgsByHashes error: %w", err) - } - return results, nil -} - -// GetLatestRelayedHeightOnL1 get latest relayed height on l1 -func (r *RelayedMsg) GetLatestRelayedHeightOnL1(ctx context.Context) (uint64, error) { - var result RelayedMsg - err := r.db.WithContext(ctx).Model(&RelayedMsg{}). - Select("height"). - Where("layer1_hash != ''"). - Order("height DESC"). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("RelayedMsg.GetLatestRelayedHeightOnL1 error: %w", err) - } - return result.Height, err -} - -// GetLatestRelayedHeightOnL2 get latest relayed height on l2 -func (r *RelayedMsg) GetLatestRelayedHeightOnL2(ctx context.Context) (uint64, error) { - var result RelayedMsg - err := r.db.WithContext(ctx).Model(&RelayedMsg{}). - Select("height"). - Where("layer2_hash != ''"). - Order("height DESC"). - First(&result). - Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return 0, nil - } - return 0, fmt.Errorf("RelayedMsg.GetLatestRelayedHeightOnL2 error: %w", err) - } - return result.Height, nil -} - -// InsertRelayedMsg batch insert relayed msg into db and return the transaction -func (r *RelayedMsg) InsertRelayedMsg(ctx context.Context, messages []*RelayedMsg, dbTx ...*gorm.DB) error { - if len(messages) == 0 { - return nil - } - db := r.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&RelayedMsg{}).Create(&messages).Error - if err != nil { - l2hashes := make([]string, 0, len(messages)) - l1hashes := make([]string, 0, len(messages)) - heights := make([]uint64, 0, len(messages)) - for _, msg := range messages { - l2hashes = append(l2hashes, msg.Layer2Hash) - l1hashes = append(l1hashes, msg.Layer1Hash) - heights = append(heights, msg.Height) - } - log.Error("failed to insert l2 sent messages", "l2hashes", l2hashes, "l1hashes", l1hashes, "heights", heights, "err", err) - return fmt.Errorf("RelayedMsg.InsertRelayedMsg error: %w", err) - } - return nil -} - -// DeleteL1RelayedHashAfterHeight delete l1 relayed hash after height -func (r *RelayedMsg) DeleteL1RelayedHashAfterHeight(ctx context.Context, height uint64, dbTx ...*gorm.DB) error { - db := r.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&RelayedMsg{}). - Delete("height > ? AND layer1_hash != ''", height).Error - if err != nil { - return fmt.Errorf("RelayedMsg.DeleteL1RelayedHashAfterHeight error: %w", err) - } - return nil -} - -// DeleteL2RelayedHashAfterHeight delete l2 relayed hash after heights -func (r *RelayedMsg) DeleteL2RelayedHashAfterHeight(ctx context.Context, height uint64, dbTx ...*gorm.DB) error { - db := r.db - if len(dbTx) > 0 && dbTx[0] != nil { - db = dbTx[0] - } - db.WithContext(ctx) - err := db.Model(&RelayedMsg{}). - Delete("height > ? AND layer2_hash != ''", height).Error - if err != nil { - return fmt.Errorf("RelayedMsg.DeleteL2RelayedHashAfterHeight error: %w", err) - } - return nil -} diff --git a/bridge-history-api/testdata/commit-batches-0x3095e91db7ba4a6fbf4654d607db322e58ff5579c502219c8024acaea74cf311.txt b/bridge-history-api/testdata/commit-batches-0x3095e91db7ba4a6fbf4654d607db322e58ff5579c502219c8024acaea74cf311.txt deleted file mode 100644 index 53d526d942..0000000000 --- a/bridge-history-api/testdata/commit-batches-0x3095e91db7ba4a6fbf4654d607db322e58ff5579c502219c8024acaea74cf311.txt +++ /dev/null @@ -1 +0,0 @@ -cb9054990000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000009a000000000000000000000000000000000000000000000000000000000000013c00000000000000000000000000000000000000000000000000000000000001824000000000000000000000000000000000000000000000000000000000000184e000000000000000000000000000000000000000000000000000000000000000e010f873a64d3b6a6158f89ff72b969cea899c9bedc925524bc1d3cd365a44045527180fe7df79de88f2f90ea850e2b9240bdd33857de21552556b4a84b4025ac3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015ba2a6259d2fe40d3ab23f5c6e958e2ef834913795e6a4696d1248054263f1d50000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000551b28c5737f1dd384ae6affebb07bfa89e9852427d0575448f6ed57f37958efda4fc62b9b0643e345bdcebe457b3ae898bef59c7203c3db269200055e037afda00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000063f86a2b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f22f2cb861f3177d15fc39575f626ef2ff7730523f23f3b73d0aa5afa722fb8351b28c5737f1dd384ae6affebb07bfa89e9852427d0575448f6ed57f37958efd00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000063f86a60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fe1a1a964246c96c2dbd38cbfee7cc7e8c269af494dfd4b479791aa8b2b0ee02f22f2cb861f3177d15fc39575f626ef2ff7730523f23f3b73d0aa5afa722fb8300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000063f86a63000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000077834f1f68d9d8e2be5fd63e32c27b7676e8b947fd234b14ef6cb79cd60329edfe1a1a964246c96c2dbd38cbfee7cc7e8c269af494dfd4b479791aa8b2b0ee0200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000063f86a97000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067758c6eae01e299f3a8daebd916cb128532b150bed3ce36d0d6dedf4baaaa4377834f1f68d9d8e2be5fd63e32c27b7676e8b947fd234b14ef6cb79cd60329ed00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000063f87227000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009339000007f5f907f28001830960be8080b907a1608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6107238061007e6000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b3660046104ed565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee366004610511565b610254565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f366004610560565b6102de565b34801561013057600080fd5b506100d161013f366004610511565b61036f565b34801561015057600080fd5b506100d161015f3660046104ed565b6103c7565b34801561017057600080fd5b506100a061017f3660046104ed565b610462565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d9190610636565b949350505050565b6000546001600160a01b031633146102485760405162461bcd60e51b815260040161023f90610653565b60405180910390fd5b6102526000610488565b565b6000546001600160a01b0316331461027e5760405162461bcd60e51b815260040161023f90610653565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b1580156102c257600080fd5b505af11580156102d6573d6000803e3d6000fd5b505050505050565b6000546001600160a01b031633146103085760405162461bcd60e51b815260040161023f90610653565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906103389086908690600401610688565b6000604051808303818588803b15801561035157600080fd5b505af1158015610365573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b031633146103995760405162461bcd60e51b815260040161023f90610653565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe6906024016102a8565b6000546001600160a01b031633146103f15760405162461bcd60e51b815260040161023f90610653565b6001600160a01b0381166104565760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161023f565b61045f81610488565b50565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116811461045f57600080fd5b6000602082840312156104ff57600080fd5b813561050a816104d8565b9392505050565b6000806040838503121561052457600080fd5b823561052f816104d8565b9150602083013561053f816104d8565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561057557600080fd5b8335610580816104d8565b92506020840135610590816104d8565b9150604084013567ffffffffffffffff808211156105ad57600080fd5b818601915086601f8301126105c157600080fd5b8135818111156105d3576105d361054a565b604051601f8201601f19908116603f011681019083821181831017156105fb576105fb61054a565b8160405282815289602084870101111561061457600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561064857600080fd5b815161050a816104d8565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60018060a01b038316815260006020604081840152835180604085015260005b818110156106c4578581018301518582016060015282016106a8565b818111156106d6576000606083870101525b50601f01601f19169290920160600194935050505056fea2646970667358221220ebed7a44095d7c5c9a2c2a6392cfbcd8c3dd7c4c5c4e2ee634396071ee50181464736f6c634300080a003383104ec6a08e3d88aab00a364cb802ebc54a85fa3c266d132afd086b5f3d97830a8a156c68a064769f5ec5766e2e049d1be9568d6988cb6a485776b80f9e786bf0cea3ab17ea00002499f92496010183274add8080b9244560e06040523480156200001157600080fd5b50604051620023e5380380620023e583398101604081905262000034916200006f565b6001600160a01b0392831660805290821660a0521660c052620000b9565b80516001600160a01b03811681146200006a57600080fd5b919050565b6000806000606084860312156200008557600080fd5b620000908462000052565b9250620000a06020850162000052565b9150620000b06040850162000052565b90509250925092565b60805160a05160c0516122d96200010c600039600081816101ef0152818161104101526111690152600081816102fa0152610eac0152600081816103c7015281816108090152610d0101526122d96000f3fe60806040526004361061016a5760003560e01c8063715018a6116100d15780638da5cb5b1161008a5780639a362e75116100645780639a362e751461048c578063b0d0643a146104ac578063b2267a7b146104d9578063f2fde38b146104ec57600080fd5b80638da5cb5b1461042e5780638ef1332e1461044c57806393e59dc11461046c57600080fd5b8063715018a614610360578063797594b0146103755780637cf2e9ea1461039557806380953acd146103b55780638456cb59146103e957806384a7d81f146103fe57600080fd5b8063478222c211610123578063478222c214610289578063485cc955146102a95780635c975abb146102c95780635d62a8dd146102e85780636d2ab1831461031c5780636e296e451461034057600080fd5b806302345b50146101765780632a6cccb2146101bb5780633b70c18a146101dd5780633bf99aa6146102295780633d0f963e146102495780633e8ff0761461026957600080fd5b3661017157005b600080fd5b34801561018257600080fd5b506101a6610191366004611d0b565b609b6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156101c757600080fd5b506101db6101d6366004611d40565b61050c565b005b3480156101e957600080fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101b2565b34801561023557600080fd5b506101db610244366004611e05565b6105a5565b34801561025557600080fd5b506101db610264366004611d40565b610762565b34801561027557600080fd5b506101a6610284366004611ea3565b6107e6565b34801561029557600080fd5b50606854610211906001600160a01b031681565b3480156102b557600080fd5b506101db6102c4366004611f23565b61093f565b3480156102d557600080fd5b50606854600160a01b900460ff166101a6565b3480156102f457600080fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b34801561032857600080fd5b50610332609d5481565b6040519081526020016101b2565b34801561034c57600080fd5b50606554610211906001600160a01b031681565b34801561036c57600080fd5b506101db610a24565b34801561038157600080fd5b50606754610211906001600160a01b031681565b3480156103a157600080fd5b506101db6103b0366004611d0b565b610a5a565b3480156103c157600080fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b3480156103f557600080fd5b506101db610abf565b34801561040a57600080fd5b506101a6610419366004611d0b565b609a6020526000908152604090205460ff1681565b34801561043a57600080fd5b506033546001600160a01b0316610211565b34801561045857600080fd5b506101db610467366004611f56565b610af1565b34801561047857600080fd5b50606654610211906001600160a01b031681565b34801561049857600080fd5b506101a66104a7366004611ea3565b610cde565b3480156104b857600080fd5b506103326104c7366004611d0b565b609c6020526000908152604090205481565b6101db6104e7366004611fc8565b610e24565b3480156104f857600080fd5b506101db610507366004611d40565b611231565b6033546001600160a01b0316331461053f5760405162461bcd60e51b815260040161053690612027565b60405180910390fd5b606654606880546001600160a01b0319166001600160a01b0384811691821790925560408051929093168083526020830191909152917f4aadc32827849f797733838c61302f7f56d2b6db28caa175eb3f7f8e5aba25f591015b60405180910390a15050565b606854600160a01b900460ff16156105cf5760405162461bcd60e51b81526004016105369061205c565b6065546001600160a01b03166001146106215760405162461bcd60e51b815260206004820152601460248201527320b63932b0b23c9034b71032bc32b1baba34b7b760611b6044820152606401610536565b600061063087878787876112cc565b80516020918201206000818152609b90925260409091205490915060ff161561069b5760405162461bcd60e51b815260206004820152601d60248201527f4d657373616765207375636365737366756c6c792065786563757465640000006044820152606401610536565b6000818152609c60205260409020546106f65760405162461bcd60e51b815260206004820152601a60248201527f4d657373616765206e6f742072656c61796564206265666f72650000000000006044820152606401610536565b6107098235826102846020860186612086565b61074c5760405162461bcd60e51b815260206004820152601460248201527313595cdcd859d9481b9bdd081a5b98db1d59195960621b6044820152606401610536565b610759878787868561131c565b50505050505050565b6033546001600160a01b0316331461078c5760405162461bcd60e51b815260040161053690612027565b606680546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527f22d1c35fe072d2e42c3c8f9bd4a0d34aa84a0101d020a62517b33fdb3174e5f79101610599565b604051630596b06f60e31b81526004810185905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632cb5837890602401602060405180830381865afa158015610850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087491906120cd565b9050806108bb5760405162461bcd60e51b8152602060048201526015602482015274109b1bd8dac81a5cc81b9bdd081a5b5c1bdc9d1959605a1b6044820152606401610536565b600085815260696020526040812060675490919081906108e6906001600160a01b03168489896114f7565b915091508382146109305760405162461bcd60e51b81526020600482015260146024820152730a6e8c2e8ca40e4dedee8e640dad2e6dac2e8c6d60631b6044820152606401610536565b60011498975050505050505050565b600054610100900460ff1661095a5760005460ff161561095e565b303b155b6109c15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610536565b600054610100900460ff161580156109e3576000805461ffff19166101011790555b6109eb611b36565b6109f58383611b65565b6003609d55606580546001600160a01b03191660011790558015610a1f576000805461ff00191690555b505050565b6033546001600160a01b03163314610a4e5760405162461bcd60e51b815260040161053690612027565b610a586000611ba7565b565b6033546001600160a01b03163314610a845760405162461bcd60e51b815260040161053690612027565b609d8190556040518181527f012747345e9e2d3604e46c67be8d427fe303fbf6894d4847f5792d0fa97a4aad9060200160405180910390a150565b6033546001600160a01b03163314610ae95760405162461bcd60e51b815260040161053690612027565b610a58611bf9565b606854600160a01b900460ff1615610b1b5760405162461bcd60e51b81526004016105369061205c565b60665433906001600160a01b0316801580610b9b575060405163efc7840160e01b81526001600160a01b03838116600483015282169063efc7840190602401602060405180830381865afa158015610b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9b91906120e6565b610be05760405162461bcd60e51b81526020600482015260166024820152751cd95b99195c881b9bdd081dda1a5d195b1a5cdd195960521b6044820152606401610536565b6065546001600160a01b0316600114610c3b5760405162461bcd60e51b815260206004820152601f60248201527f4d65737361676520697320616c726561647920696e20657865637574696f6e006044820152606401610536565b6000610c4a88888888886112cc565b80516020918201206000818152609b90925260409091205490915060ff1615610cc75760405162461bcd60e51b815260206004820152602960248201527f4d6573736167652077617320616c7265616479207375636365737366756c6c7960448201526808195e1958dd5d195960ba1b6064820152608401610536565b610cd4888888878561131c565b5050505050505050565b604051630596b06f60e31b81526004810185905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632cb5837890602401602060405180830381865afa158015610d48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6c91906120cd565b905080610db05760405162461bcd60e51b8152602060048201526012602482015271109b1bd8dac81b9bdd081a5b5c1bdc9d195960721b6044820152606401610536565b6000858152606a602052604081206067549091908190610ddb906001600160a01b03168489896114f7565b915091508382146109305760405162461bcd60e51b81526020600482015260136024820152720a6e8c2e8ca40e4dedee840dad2e6dac2e8c6d606b1b6044820152606401610536565b606854600160a01b900460ff1615610e4e5760405162461bcd60e51b81526004016105369061205c565b6068546001600160a01b03163314610ea857615208811015610ea85760405162461bcd60e51b815260206004820152601360248201527219d85cc81b1a5b5a5d081d1bdbc81cdb585b1b606a1b6044820152606401610536565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663519b4bd36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2c91906120cd565b610f36908361211e565b9050610f42818561213d565b341015610f8a5760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e74206d73672e76616c756560501b6044820152606401610536565b801561103d576068546000906001600160a01b0316610fa98634612155565b604051600081818185875af1925050503d8060008114610fe5576040519150601f19603f3d011682016040523d82523d6000602084013e610fea565b606091505b505090508061103b5760405162461bcd60e51b815260206004820152601860248201527f4661696c656420746f20646564756374207468652066656500000000000000006044820152606401610536565b505b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166326aad7b76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561109d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c191906120cd565b905060006110d233888885896112cc565b80516020918201206000818152609a90925260409091205490915060ff16156111325760405162461bcd60e51b81526020600482015260126024820152714475706c696361746564206d65737361676560701b6044820152606401610536565b6000818152609a602052604090819020805460ff191660011790555163600a2e7760e01b8152600481018290526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063600a2e77906024016020604051808303816000875af11580156111b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d691906120cd565b50866001600160a01b0316336001600160a01b03167f104371f3b442861a2a7b82a070afbbaab748bb13757bf47769e170e37809ec1e8885888a60405161122094939291906121c8565b60405180910390a350505050505050565b6033546001600160a01b0316331461125b5760405162461bcd60e51b815260040161053690612027565b6001600160a01b0381166112c05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610536565b6112c981611ba7565b50565b606085858585856040516024016112e79594939291906121f7565b60408051601f198184030181529190526020810180516001600160e01b0316634778999760e11b179052905095945050505050565b6065546001600160a01b03868116911614156113735760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21036b2b9b9b0b3b29039b2b73232b960511b6044820152606401610536565b606580546001600160a01b0319166001600160a01b038781169190911790915560405160009186169085906113a990869061223c565b60006040518083038185875af1925050503d80600081146113e6576040519150601f19603f3d011682016040523d82523d6000602084013e6113eb565b606091505b5050606580546001600160a01b03191660011790559050801561144d576000828152609b6020526040808220805460ff191660011790555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a26114ef565b6000828152609c6020526040902054609d546001909101908111156114b45760405162461bcd60e51b815260206004820152601c60248201527f457863656564206d6178696d756d206661696c7572652074696d6573000000006044820152606401610536565b6000838152609c602052604080822092909255905183917f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f91a25b505050505050565b600080611904565b6308c379a060e01b60005260206004528060445260005b811561152b5760089190911b90600101611516565b60245260646000fd5b8061154257611542826114ff565b5050565b80608081101561155557611571565b602083111561156357611571565b60ff60071960088502011b19165b92915050565b600080823560001a60f78111156115b95760f78103602081111561159757fe5b60018581013560088302610100031c8201810196919095019094019392505050565b60bf8111156115d35760be19019360019390930192915050565b506115e867139bdd081b1a5cdd60c21b6114ff565b915091565b6000806000833560001a608081101561160d576001925084915050611680565b60b881101561162657607f190191505060018301611680565b60c081101561165c5760b78103600481111561163e57fe5b60018681013560088302610100031c94509086010191506116809050565b6001935060f881101561167457505060018301611680565b60f61901915050600183015b9193909250565b604051819060008061169884611577565b8186863781852090959092500184845b828710156116db576116b9876115ed565b93508381019850816116d457838160801b1783526020830192505b50506116a8565b8287146116e457fe5b60208682030494505050509193509193565b6000196004830290811c82169060206001851615611712575060035b610100919091031b1792915050565b60008260200282015162ffffff81168160801c9150601f82111561174c5701601f1901359050611571565b356020919091036008021c905092915050565b6000808360200283015162ffffff81168160801c9250601f83111561178e578201601f190135925061179c9050565b3560208390036008021c9250505b9250929050565b80600080808080806117b487611687565b98509250925096508881146117e2576117e27209cdec8ca40d2e8cadae640dad2e6dac2e8c6d606b1b6114ff565b506117ed898261175f565b925093506117fb8a8261175f565b9250925050945094509450945094565b600080600080859350833560001a600185019450600060015b828110156118ec57600080600061183a8a611687565b9350935093509950836001811461186c576118676c090c2e6d040dad2e6dac2e8c6d609b1b8a8414611534565b611870565b8199505b505080600281146118a057601181146118be5761189b6b496e76616c6964206e6f646560a01b6114ff565b6118e1565b6118ab60018461175f565b50835190985060801c94909401936118e1565b6004850260fc038b901c600f166118d5818561175f565b50985050600194909401935b505050600101611824565b506118f781886116f6565b9250505092959194509250565b600080600080600088600061191e8d6000526014600c2090565b611928838261180b565b985093509a5092505060008061193d84611687565b98509250925093506119717f4163636f756e74206c6561662068617368206d69736d61746368000000000000848814611534565b61199e7f4163636f756e74206c656166206e6f6465206d69736d6174636800000000000060028314611534565b6119a9600083611721565b97506119d77f4163636f756e7420656e636f6465642070617468206d69736d61746368000000898914611534565b602082015162ffffff1692506119ec83611687565b9850925092509250611a217f4163636f756e74206c656166206974656d73206d69736d61746368000000000060048314611534565b50611a2d600282611721565b975050506000611a438c60009081526020902090565b611a4d838261180b565b985096509250925050611a65600160006002856117a3565b96509a50975094509150611a9b7f53746f7261676520656e636f6465642070617468206d69736d61746368000000878714611534565b808015611acb57611ac6740a6e8dee4c2ceca40e4dedee840dad2e6dac2e8c6d605b1b898414611534565b611aef565b611aef740a6e8dee4c2ceca40e4dedee840dad2e6dac2e8c6d605b1b898714611534565b5050611afb8288611546565b9650888a018114611b2757611b27740a0e4dedecc40d8cadccee8d040dad2e6dac2e8c6d605b1b6114ff565b50505050505094509492505050565b600054610100900460ff16611b5d5760405162461bcd60e51b815260040161053690612258565b610a58611c7b565b611b6d611cb1565b606580546001600160a01b0319908116600117909155606780546001600160a01b0394851690831617905560688054929093169116179055565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606854600160a01b900460ff1615611c235760405162461bcd60e51b81526004016105369061205c565b6068805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611c5e3390565b6040516001600160a01b03909116815260200160405180910390a1565b600054610100900460ff16611ca25760405162461bcd60e51b815260040161053690612258565b6068805460ff60a01b19169055565b600054610100900460ff16611cd85760405162461bcd60e51b815260040161053690612258565b610a58600054610100900460ff16611d025760405162461bcd60e51b815260040161053690612258565b610a5833611ba7565b600060208284031215611d1d57600080fd5b5035919050565b80356001600160a01b0381168114611d3b57600080fd5b919050565b600060208284031215611d5257600080fd5b611d5b82611d24565b9392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112611d8957600080fd5b813567ffffffffffffffff80821115611da457611da4611d62565b604051601f8301601f19908116603f01168101908282118183101715611dcc57611dcc611d62565b81604052838152866020858801011115611de557600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c08789031215611e1e57600080fd5b611e2787611d24565b9550611e3560208801611d24565b94506040870135935060608701359250608087013567ffffffffffffffff80821115611e6057600080fd5b611e6c8a838b01611d78565b935060a0890135915080821115611e8257600080fd5b5087016040818a031215611e9557600080fd5b809150509295509295509295565b60008060008060608587031215611eb957600080fd5b8435935060208501359250604085013567ffffffffffffffff80821115611edf57600080fd5b818701915087601f830112611ef357600080fd5b813581811115611f0257600080fd5b886020828501011115611f1457600080fd5b95989497505060200194505050565b60008060408385031215611f3657600080fd5b611f3f83611d24565b9150611f4d60208401611d24565b90509250929050565b600080600080600060a08688031215611f6e57600080fd5b611f7786611d24565b9450611f8560208701611d24565b93506040860135925060608601359150608086013567ffffffffffffffff811115611faf57600080fd5b611fbb88828901611d78565b9150509295509295909350565b60008060008060808587031215611fde57600080fd5b611fe785611d24565b935060208501359250604085013567ffffffffffffffff81111561200a57600080fd5b61201687828801611d78565b949793965093946060013593505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6000808335601e1984360301811261209d57600080fd5b83018035915067ffffffffffffffff8211156120b857600080fd5b60200191503681900382131561179c57600080fd5b6000602082840312156120df57600080fd5b5051919050565b6000602082840312156120f857600080fd5b81518015158114611d5b57600080fd5b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561213857612138612108565b500290565b6000821982111561215057612150612108565b500190565b60008282101561216757612167612108565b500390565b60005b8381101561218757818101518382015260200161216f565b83811115612196576000848401525b50505050565b600081518084526121b481602086016020860161216c565b601f01601f19169290920160200192915050565b8481528360208201528260408201526080606082015260006121ed608083018461219c565b9695505050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906122319083018461219c565b979650505050505050565b6000825161224e81846020870161216c565b9190910192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220f45f9a43a6a230f9f6fce61e0c3100fbb1b5a146e6222f60a069450bce7ae59664736f6c634300080a003300000000000000000000000053000000000000000000000000000000000000010000000000000000000000005300000000000000000000000000000000000002000000000000000000000000530000000000000000000000000000000000000083104ec5a0e6de0bb04092b0f689188978fa7b8faffd753c13eb64555aad693e30f8464e0fa04d27de86a45472b08e51b622e68c8488e899e7f814e5fe4010bad0538a13acca0000103af910370201830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656400000000000000000000000018e11f06fd9ff56eff73ad50837d3d0662fc687d000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec5a0a51602f05bb15997263ad3f2a4e2c3a326b4c57b0b5f11a34c843159cc4956dba05f8430dfeb420a723c0ed1ee93416aeabc6c755070713926e7fafb2b6644f6a400000cdcf90cd90301830ea6688080b90c88608060405234801561001057600080fd5b50610c68806100206000396000f3fe60806040526004361061007b5760003560e01c8063797594b01161004e578063797594b0146100f7578063c0c53b8b1461011d578063c7cdea371461013d578063f887ea401461015057600080fd5b8063232e8748146100805780632fcc29fa146100955780633cb747bf146100a85780636dc24183146100e4575b600080fd5b61009361008e366004610809565b610170565b005b6100936100a33660046108a8565b610386565b3480156100b457600080fd5b506002546100c8906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b6100936100f236600461094c565b6103c4565b34801561010357600080fd5b506000546100c8906201000090046001600160a01b031681565b34801561012957600080fd5b506100936101383660046109f0565b6103d6565b61009361014b366004610a3b565b6104e8565b34801561015c57600080fd5b506001546100c8906001600160a01b031681565b6002546001600160a01b03163381146101d05760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206d657373656e6765722063616e2063616c6c00000000000000000060448201526064015b60405180910390fd5b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102329190610a5d565b6000546201000090046001600160a01b039081169116146102955760405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063616c6c20627920636f6e7465727061727400000000000000000060448201526064016101c7565b6000856001600160a01b03168560405160006040518083038185875af1925050503d80600081146102e2576040519150601f19603f3d011682016040523d82523d6000602084013e6102e7565b606091505b505090508061032e5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016101c7565b856001600160a01b0316876001600160a01b03167f9e86c356e14e24e26e3ce769bf8b87de38e0faa0ed0ca946fa09659aa606bd2d87878760405161037593929190610a81565b60405180910390a350505050505050565b6103bf838360005b6040519080825280601f01601f1916602001820160405280156103b8576020820181803683370190505b50846104f8565b505050565b6103d0848484846104f8565b50505050565b600054610100900460ff166103f15760005460ff16156103f5565b303b155b6104585760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016101c7565b600054610100900460ff1615801561047a576000805461ffff19166101011790555b6001600160a01b0383166104c65760405162461bcd60e51b81526020600482015260136024820152727a65726f20726f75746572206164647265737360681b60448201526064016101c7565b6104d18484846106e1565b80156103d0576000805461ff001916905550505050565b6104f43383600061038e565b5050565b6002600354141561054b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016101c7565b6002600355346105915760405162461bcd60e51b81526020600482015260116024820152700eed2e8d0c8e4c2ee40f4cae4de40cae8d607b1b60448201526064016101c7565b60015433906001600160a01b03168114156105bf57828060200190518101906105ba9190610ae3565b935090505b6000638eaac8a360e01b828787876040516024016105e09493929190610b9c565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600254600054925163b2267a7b60e01b81529193506001600160a01b039081169263b2267a7b9234926106559262010000900416908a9087908a90600401610bd9565b6000604051808303818588803b15801561066e57600080fd5b505af1158015610682573d6000803e3d6000fd5b5050505050856001600160a01b0316826001600160a01b03167fd8ed6eaa9a7a8980d7901e911fde6686810b989d3082182d1d3a3df6306ce20e87876040516106cc929190610c11565b60405180910390a35050600160035550505050565b6001600160a01b0383166107375760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e746572706172742061646472657373000000000000000060448201526064016101c7565b6001600160a01b0381166107865760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b60448201526064016101c7565b6000805462010000600160b01b031916620100006001600160a01b038681169190910291909117909155600280546001600160a01b0319168383161790558216156107e757600180546001600160a01b0319166001600160a01b0384161790555b5050600160035550565b6001600160a01b038116811461080657600080fd5b50565b60008060008060006080868803121561082157600080fd5b853561082c816107f1565b9450602086013561083c816107f1565b935060408601359250606086013567ffffffffffffffff8082111561086057600080fd5b818801915088601f83011261087457600080fd5b81358181111561088357600080fd5b89602082850101111561089557600080fd5b9699959850939650602001949392505050565b6000806000606084860312156108bd57600080fd5b83356108c8816107f1565b95602085013595506040909401359392505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561091c5761091c6108dd565b604052919050565b600067ffffffffffffffff82111561093e5761093e6108dd565b50601f01601f191660200190565b6000806000806080858703121561096257600080fd5b843561096d816107f1565b935060208501359250604085013567ffffffffffffffff81111561099057600080fd5b8501601f810187136109a157600080fd5b80356109b46109af82610924565b6108f3565b8181528860208385010111156109c957600080fd5b81602084016020830137600091810160200191909152949793965093946060013593505050565b600080600060608486031215610a0557600080fd5b8335610a10816107f1565b92506020840135610a20816107f1565b91506040840135610a30816107f1565b809150509250925092565b60008060408385031215610a4e57600080fd5b50508035926020909101359150565b600060208284031215610a6f57600080fd5b8151610a7a816107f1565b9392505050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b60005b83811015610ad2578181015183820152602001610aba565b838111156103d05750506000910152565b60008060408385031215610af657600080fd5b8251610b01816107f1565b602084015190925067ffffffffffffffff811115610b1e57600080fd5b8301601f81018513610b2f57600080fd5b8051610b3d6109af82610924565b818152866020838501011115610b5257600080fd5b610b63826020830160208601610ab7565b8093505050509250929050565b60008151808452610b88816020860160208601610ab7565b601f01601f19169290920160200192915050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090610bcf90830184610b70565b9695505050505050565b60018060a01b0385168152836020820152608060408201526000610c006080830185610b70565b905082606083015295945050505050565b828152604060208201526000610c2a6040830184610b70565b94935050505056fea2646970667358221220ff7f35e15a0fcf94118a66b89ca1bd6799b61efd4b05a5cc0d18ba0e0d1b460264736f6c634300080a003383104ec6a02a6db21fd4594ecf497fe76dae2bf9a42f2125501843d779023f62472acaadcea03eeded58939848b5fd92ad52cd55f9a56be5f5c4ee151ad7c9ff29232867277a0000103af910370401830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564000000000000000000000000d9b95e24533d89a18fcf2ee875e762a6797bccfd000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec6a061577e4a717194fd60f62ab0bd06a8cf9aa3b6a5feb4804e9a585cb9df5bd047a061e2e5c9aad701d27bb13b8fd0437de6968f38e0f932b580b710304a89b0d10100001543f9154005018316be5d8080b914ef60c060405234801561001057600080fd5b506040516114af3803806114af83398101604081905261002f91610062565b6001600160a01b0391821660a05216608052610095565b80516001600160a01b038116811461005d57600080fd5b919050565b6000806040838503121561007557600080fd5b61007e83610046565b915061008c60208401610046565b90509250929050565b60805160a0516113c56100ea6000396000818160bb01528181610220015281816102b401528181610518015261080c01526000818161017a01528181610254015281816104a3015261092201526113c56000f3fe6080604052600436106100ab5760003560e01c8063a93a4af911610064578063a93a4af9146101fb578063ad5c46481461020e578063b32d8c6514610242578063c0c53b8b14610276578063c676ad2914610296578063f887ea40146102d657600080fd5b80633cb747bf1461012057806354bbd59c1461015c578063575361b61461019c5780636c07ea43146101af578063797594b0146101c25780638431f5c1146101e857600080fd5b3661011b57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101195760405162461bcd60e51b81526020600482015260096024820152680dedcd8f240ae8aa8960bb1b60448201526064015b60405180910390fd5b005b600080fd5b34801561012c57600080fd5b50600254610140906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b34801561016857600080fd5b50610140610177366004610e8c565b507f000000000000000000000000000000000000000000000000000000000000000090565b6101196101aa366004610ef2565b6102f6565b6101196101bd366004610f6d565b610342565b3480156101ce57600080fd5b50600054610140906201000090046001600160a01b031681565b6101196101f6366004610fa2565b610381565b61011961020936600461103a565b61069e565b34801561021a57600080fd5b506101407f000000000000000000000000000000000000000000000000000000000000000081565b34801561024e57600080fd5b506101407f000000000000000000000000000000000000000000000000000000000000000081565b34801561028257600080fd5b50610119610291366004611080565b6106b1565b3480156102a257600080fd5b506101406102b1366004610e8c565b507f000000000000000000000000000000000000000000000000000000000000000090565b3480156102e257600080fd5b50600154610140906001600160a01b031681565b61033a86868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508892506107c3915050565b505050505050565b61037c83338460005b6040519080825280601f01601f191660200182016040528015610375576020820181803683370190505b50856107c3565b505050565b6002546001600160a01b03163381146103dc5760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206d657373656e6765722063616e2063616c6c0000000000000000006044820152606401610110565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561041a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043e91906110e1565b6000546201000090046001600160a01b039081169116146104a15760405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063616c6c20627920636f6e746572706172740000000000000000006044820152606401610110565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316146105165760405162461bcd60e51b81526020600482015260116024820152700d86240e8ded6cadc40dcdee840ae8aa89607b1b6044820152606401610110565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b03161461058b5760405162461bcd60e51b81526020600482015260116024820152700d86440e8ded6cadc40dcdee840ae8aa89607b1b6044820152606401610110565b3484146105cf5760405162461bcd60e51b81526020600482015260126024820152710dae6ce5cecc2d8eaca40dad2e6dac2e8c6d60731b6044820152606401610110565b866001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b15801561060a57600080fd5b505af115801561061e573d6000803e3d6000fd5b50610639935050506001600160a01b03891690508686610a74565b856001600160a01b0316876001600160a01b0316896001600160a01b03167f165ba69f6ab40c50cade6f65431801e5f9c7d7830b7545391920db039133ba348888888860405161068c94939291906110fe565b60405180910390a45050505050505050565b6106ab848484600061034b565b50505050565b600054610100900460ff166106cc5760005460ff16156106d0565b303b155b6107335760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610110565b600054610100900460ff16158015610755576000805461ffff19166101011790555b6001600160a01b0383166107a15760405162461bcd60e51b81526020600482015260136024820152727a65726f20726f75746572206164647265737360681b6044820152606401610110565b6107ac848484610ad7565b80156106ab576000805461ff001916905550505050565b6000831161080a5760405162461bcd60e51b81526020600482015260146024820152731dda5d1a191c985dc81e995c9bc8185b5bdd5b9d60621b6044820152606401610110565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b0316146108825760405162461bcd60e51b81526020600482015260146024820152731bdb9b1e4815d15512081a5cc8185b1b1bddd95960621b6044820152606401610110565b60015433906001600160a01b03168114156108b057828060200190518101906108ab9190611172565b935090505b6108c56001600160a01b038716823087610be7565b604051632e1a7d4d60e01b8152600481018590526001600160a01b03871690632e1a7d4d90602401600060405180830381600087803b15801561090757600080fd5b505af115801561091b573d6000803e3d6000fd5b50506040517f000000000000000000000000000000000000000000000000000000000000000092506000915063084bd13b60e41b906109689084908b9087908c908c908c90602401611261565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526002549091506001600160a01b031663b2267a7b6109b834896112b0565b60005460405160e084901b6001600160e01b03191681526109f1916201000090046001600160a01b0316908b9087908b906004016112d6565b6000604051808303818588803b158015610a0a57600080fd5b505af1158015610a1e573d6000803e3d6000fd5b5050505050826001600160a01b0316886001600160a01b0316836001600160a01b03167fd8d3a3f4ab95694bef40475997598bcf8acd3ed9617a4c1013795429414c27e88a8a8a60405161068c9392919061130e565b6040516001600160a01b03831660248201526044810182905261037c90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610c1f565b6001600160a01b038316610b2d5760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e74657270617274206164647265737300000000000000006044820152606401610110565b6001600160a01b038116610b7c5760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b6044820152606401610110565b6000805462010000600160b01b031916620100006001600160a01b038681169190910291909117909155600280546001600160a01b031916838316179055821615610bdd57600180546001600160a01b0319166001600160a01b0384161790555b5050600160035550565b6040516001600160a01b03808516602483015283166044820152606481018290526106ab9085906323b872dd60e01b90608401610aa0565b6000610c74826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610cf19092919063ffffffff16565b80519091501561037c5780806020019051810190610c92919061133e565b61037c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610110565b6060610d008484600085610d0a565b90505b9392505050565b606082471015610d6b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610110565b6001600160a01b0385163b610dc25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610110565b600080866001600160a01b03168587604051610dde9190611360565b60006040518083038185875af1925050503d8060008114610e1b576040519150601f19603f3d011682016040523d82523d6000602084013e610e20565b606091505b5091509150610e30828286610e3b565b979650505050505050565b60608315610e4a575081610d03565b825115610e5a5782518084602001fd5b8160405162461bcd60e51b8152600401610110919061137c565b6001600160a01b0381168114610e8957600080fd5b50565b600060208284031215610e9e57600080fd5b8135610d0381610e74565b60008083601f840112610ebb57600080fd5b50813567ffffffffffffffff811115610ed357600080fd5b602083019150836020828501011115610eeb57600080fd5b9250929050565b60008060008060008060a08789031215610f0b57600080fd5b8635610f1681610e74565b95506020870135610f2681610e74565b945060408701359350606087013567ffffffffffffffff811115610f4957600080fd5b610f5589828a01610ea9565b979a9699509497949695608090950135949350505050565b600080600060608486031215610f8257600080fd5b8335610f8d81610e74565b95602085013595506040909401359392505050565b600080600080600080600060c0888a031215610fbd57600080fd5b8735610fc881610e74565b96506020880135610fd881610e74565b95506040880135610fe881610e74565b94506060880135610ff881610e74565b93506080880135925060a088013567ffffffffffffffff81111561101b57600080fd5b6110278a828b01610ea9565b989b979a50959850939692959293505050565b6000806000806080858703121561105057600080fd5b843561105b81610e74565b9350602085013561106b81610e74565b93969395505050506040820135916060013590565b60008060006060848603121561109557600080fd5b83356110a081610e74565b925060208401356110b081610e74565b915060408401356110c081610e74565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156110f357600080fd5b8151610d0381610e74565b6001600160a01b0385168152602081018490526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b60005b83811015611161578181015183820152602001611149565b838111156106ab5750506000910152565b6000806040838503121561118557600080fd5b825161119081610e74565b602084015190925067ffffffffffffffff808211156111ae57600080fd5b818501915085601f8301126111c257600080fd5b8151818111156111d4576111d46110cb565b604051601f8201601f19908116603f011681019083821181831017156111fc576111fc6110cb565b8160405282815288602084870101111561121557600080fd5b611226836020830160208801611146565b80955050505050509250929050565b6000815180845261124d816020860160208601611146565b601f01601f19169290920160200192915050565b6001600160a01b03878116825286811660208301528581166040830152841660608201526080810183905260c060a082018190526000906112a490830184611235565b98975050505050505050565b600082198211156112d157634e487b7160e01b600052601160045260246000fd5b500190565b60018060a01b03851681528360208201526080604082015260006112fd6080830185611235565b905082606083015295945050505050565b60018060a01b03841681528260208201526060604082015260006113356060830184611235565b95945050505050565b60006020828403121561135057600080fd5b81518015158114610d0357600080fd5b60008251611372818460208701611146565b9190910192915050565b602081526000610d03602083018461123556fea2646970667358221220105a40adda4e2447b99b728533ee1e8b50e1f0c377e18d67a099ecef07a0b44264736f6c634300080a00330000000000000000000000005300000000000000000000000000000000000004000000000000000000000000b4fbf271143f4fbf7b91a5ded31805e42b2208d683104ec5a07ab0a77c4b638d45f2ed4fd895293f779d9c4f6cab1bd8cca395983b9818bb18a06b414a31213185f68a49a1867194761597e61cb502f4f3275514c88ca62360ca0000103af910370601830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656400000000000000000000000065907adabf1cabd299629c4cacc49d35e9b2bfda000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec6a057af99450c7cd7ac36b2d9b51c456ebe2e06c1dc07eb95dd11386b6a3e116f77a03865254fcd68985873d6d7e2cbd961ace7d120b8f99720b1aec5c21abe24139b000013bef913bb0701831631af8080b9136a608060405234801561001057600080fd5b5061134a806100206000396000f3fe60806040526004361061009c5760003560e01c80638431f5c1116100645780638431f5c114610164578063a93a4af914610177578063c676ad291461018a578063e77772fe146101aa578063f887ea40146101ca578063f8c8765e146101ea57600080fd5b80633cb747bf146100a157806354bbd59c146100dd578063575361b6146101165780636c07ea431461012b578063797594b01461013e575b600080fd5b3480156100ad57600080fd5b506002546100c1906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b3480156100e957600080fd5b506100c16100f8366004610cef565b6001600160a01b039081166000908152600460205260409020541690565b610129610124366004610d5c565b61020a565b005b610129610139366004610dd7565b610256565b34801561014a57600080fd5b506000546100c1906201000090046001600160a01b031681565b610129610172366004610e0c565b610295565b610129610185366004610ea4565b61064a565b34801561019657600080fd5b506100c16101a5366004610cef565b61065d565b3480156101b657600080fd5b506005546100c1906001600160a01b031681565b3480156101d657600080fd5b506001546100c1906001600160a01b031681565b3480156101f657600080fd5b50610129610205366004610eea565b6106d8565b61024e86868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250889250610852915050565b505050505050565b61029083338460005b6040519080825280601f01601f191660200182016040528015610289576020820181803683370190505b5085610852565b505050565b6002546001600160a01b03163381146102f55760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206d657373656e6765722063616e2063616c6c00000000000000000060448201526064015b60405180910390fd5b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610333573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103579190610f5c565b6000546201000090046001600160a01b039081169116146103ba5760405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063616c6c20627920636f6e7465727061727400000000000000000060448201526064016102ec565b34156103fc5760405162461bcd60e51b81526020600482015260116024820152706e6f6e7a65726f206d73672e76616c756560781b60448201526064016102ec565b6005546040516361e98ca160e01b81523060048201526001600160a01b038a8116602483015260009216906361e98ca190604401602060405180830381865afa15801561044d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104719190610f5c565b9050806001600160a01b0316886001600160a01b0316146104c85760405162461bcd60e51b81526020600482015260116024820152700d86440e8ded6cadc40dad2e6dac2e8c6d607b1b60448201526064016102ec565b506001600160a01b03878116600090815260046020526040902054606091829116610530576001600160a01b03898116600090815260046020526040902080546001600160a01b031916918c1691909117905561052785850186611028565b9250905061056a565b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b6001600160a01b0389163b61058357610583828b610ac1565b6040516340c10f1960e01b81526001600160a01b038881166004830152602482018890528a16906340c10f1990604401600060405180830381600087803b1580156105cd57600080fd5b505af11580156105e1573d6000803e3d6000fd5b50505050876001600160a01b0316896001600160a01b03168b6001600160a01b03167f165ba69f6ab40c50cade6f65431801e5f9c7d7830b7545391920db039133ba348a8a86604051610636939291906110e4565b60405180910390a450505050505050505050565b610657848484600061025f565b50505050565b6005546040516361e98ca160e01b81523060048201526001600160a01b03838116602483015260009216906361e98ca190604401602060405180830381865afa1580156106ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d29190610f5c565b92915050565b600054610100900460ff166106f35760005460ff16156106f7565b303b155b61075a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016102ec565b600054610100900460ff1615801561077c576000805461ffff19166101011790555b6001600160a01b0384166107c85760405162461bcd60e51b81526020600482015260136024820152727a65726f20726f75746572206164647265737360681b60448201526064016102ec565b6107d3858585610bc7565b6001600160a01b03821661081e5760405162461bcd60e51b81526020600482015260126024820152717a65726f20746f6b656e20666163746f727960701b60448201526064016102ec565b600580546001600160a01b0319166001600160a01b038416179055801561084b576000805461ff00191690555b5050505050565b600083116108995760405162461bcd60e51b81526020600482015260146024820152731dda5d1a191c985dc81e995c9bc8185b5bdd5b9d60621b60448201526064016102ec565b60015433906001600160a01b03168114156108c757828060200190518101906108c29190611144565b935090505b6001600160a01b03808716600090815260046020526040902054168061092f5760405162461bcd60e51b815260206004820152601960248201527f6e6f20636f72726573706f6e64696e67206c3120746f6b656e0000000000000060448201526064016102ec565b604051632770a7eb60e21b81526001600160a01b03838116600483015260248201879052881690639dc29fac90604401600060405180830381600087803b15801561097957600080fd5b505af115801561098d573d6000803e3d6000fd5b5050505060006384bd13b060e01b8289858a8a8a6040516024016109b69695949392919061119f565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925260025460008054935163b2267a7b60e01b81529294506001600160a01b039182169363b2267a7b933493610a2c936201000090930416919087908b906004016111ee565b6000604051808303818588803b158015610a4557600080fd5b505af1158015610a59573d6000803e3d6000fd5b5050505050826001600160a01b0316886001600160a01b0316836001600160a01b03167fd8d3a3f4ab95694bef40475997598bcf8acd3ed9617a4c1013795429414c27e88a8a8a604051610aaf939291906110e4565b60405180910390a45050505050505050565b600554604051637bdbcbbf60e01b81523060048201526001600160a01b0383811660248301526000921690637bdbcbbf906044016020604051808303816000875af1158015610b14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b389190610f5c565b9050600080600085806020019051810190610b539190611246565b925092509250836001600160a01b031663c820f146838584308a6040518663ffffffff1660e01b8152600401610b8d9594939291906112c4565b600060405180830381600087803b158015610ba757600080fd5b505af1158015610bbb573d6000803e3d6000fd5b50505050505050505050565b6001600160a01b038316610c1d5760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e746572706172742061646472657373000000000000000060448201526064016102ec565b6001600160a01b038116610c6c5760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b60448201526064016102ec565b6000805462010000600160b01b031916620100006001600160a01b038681169190910291909117909155600280546001600160a01b031916838316179055821615610ccd57600180546001600160a01b0319166001600160a01b0384161790555b5050600160035550565b6001600160a01b0381168114610cec57600080fd5b50565b600060208284031215610d0157600080fd5b8135610d0c81610cd7565b9392505050565b60008083601f840112610d2557600080fd5b50813567ffffffffffffffff811115610d3d57600080fd5b602083019150836020828501011115610d5557600080fd5b9250929050565b60008060008060008060a08789031215610d7557600080fd5b8635610d8081610cd7565b95506020870135610d9081610cd7565b945060408701359350606087013567ffffffffffffffff811115610db357600080fd5b610dbf89828a01610d13565b979a9699509497949695608090950135949350505050565b600080600060608486031215610dec57600080fd5b8335610df781610cd7565b95602085013595506040909401359392505050565b600080600080600080600060c0888a031215610e2757600080fd5b8735610e3281610cd7565b96506020880135610e4281610cd7565b95506040880135610e5281610cd7565b94506060880135610e6281610cd7565b93506080880135925060a088013567ffffffffffffffff811115610e8557600080fd5b610e918a828b01610d13565b989b979a50959850939692959293505050565b60008060008060808587031215610eba57600080fd5b8435610ec581610cd7565b93506020850135610ed581610cd7565b93969395505050506040820135916060013590565b60008060008060808587031215610f0057600080fd5b8435610f0b81610cd7565b93506020850135610f1b81610cd7565b92506040850135610f2b81610cd7565b91506060850135610f3b81610cd7565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215610f6e57600080fd5b8151610d0c81610cd7565b604051601f8201601f1916810167ffffffffffffffff81118282101715610fa257610fa2610f46565b604052919050565b600067ffffffffffffffff821115610fc457610fc4610f46565b50601f01601f191660200190565b600082601f830112610fe357600080fd5b8135610ff6610ff182610faa565b610f79565b81815284602083860101111561100b57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561103b57600080fd5b823567ffffffffffffffff8082111561105357600080fd5b61105f86838701610fd2565b9350602085013591508082111561107557600080fd5b5061108285828601610fd2565b9150509250929050565b60005b838110156110a757818101518382015260200161108f565b838111156106575750506000910152565b600081518084526110d081602086016020860161108c565b601f01601f19169290920160200192915050565b60018060a01b038416815282602082015260606040820152600061110b60608301846110b8565b95945050505050565b6000611122610ff184610faa565b905082815283838301111561113657600080fd5b610d0c83602083018461108c565b6000806040838503121561115757600080fd5b825161116281610cd7565b602084015190925067ffffffffffffffff81111561117f57600080fd5b8301601f8101851361119057600080fd5b61108285825160208401611114565b6001600160a01b03878116825286811660208301528581166040830152841660608201526080810183905260c060a082018190526000906111e2908301846110b8565b98975050505050505050565b60018060a01b038516815283602082015260806040820152600061121560808301856110b8565b905082606083015295945050505050565b600082601f83011261123757600080fd5b610d0c83835160208501611114565b60008060006060848603121561125b57600080fd5b835167ffffffffffffffff8082111561127357600080fd5b61127f87838801611226565b9450602086015191508082111561129557600080fd5b506112a286828701611226565b925050604084015160ff811681146112b957600080fd5b809150509250925092565b60a0815260006112d760a08301886110b8565b82810360208401526112e981886110b8565b60ff96909616604084015250506001600160a01b03928316606082015291166080909101529291505056fea2646970667358221220427b9a9b5120c3c05d0eb7f2958eb539b0c4c9f5ea6ed6fddf859a9bee223d6f64736f6c634300080a003383104ec5a0b81b72ef3c165129d1d0373f99127beac5763a4e66d7ab699eb8b887d4e3cf02a075bfddec122eaa8b99d7ec255045e9c94c9709e68761f9bcfd5f93d48503b2760000000000000000000000000000000000000000000000000000000000000000000000000000e027180fe7df79de88f2f90ea850e2b9240bdd33857de21552556b4a84b4025ac32d9ce8e5269e364dcc4cff641032e7f79945f20826385a083976ef93af5eadd600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002efd7b7a8d410dadcd0487bbf2739012f8ffb3f974580559935ce38540954ad6100000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001e3b568958b1eaa4e93f68204e8669e79933afdd9e5665ff6c99d9543ecf95b8f67758c6eae01e299f3a8daebd916cb128532b150bed3ce36d0d6dedf4baaaa4300000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000063f8722a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009fd90000103af910370801830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564000000000000000000000000e369674c74364f5df17d089b6458b196411a4499000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec5a0588148cb4703c97f5af47f1a6ba0e8261bf285c24fb92e9c261ddc7b8178e0e3a0099da5c5ec27434719946405226902f144b156a5f95544d3c88fe80fd71c5dce000013bbf913b80901831631718080b91367608060405234801561001057600080fd5b50611347806100206000396000f3fe60806040526004361061012a5760003560e01c80636dc24183116100ab5780638da5cb5b1161006f5780638da5cb5b146102e5578063a93a4af914610303578063c676ad2914610316578063c7cdea3714610336578063ce8c3e0614610349578063f2fde38b1461036957600080fd5b80636dc2418314610259578063705b05b81461026c578063715018a6146102a25780638431f5c1146102b75780638c00ce73146102c557600080fd5b806354bbd59c116100f257806354bbd59c146101d3578063575361b6146101f35780635dfd5b9a14610206578063635c8637146102265780636c07ea431461024657600080fd5b8063232e87481461012f5780632fcc29fa146101445780633d1d31c71461015757806343c6674114610177578063485cc955146101b3575b600080fd5b61014261013d366004610cc8565b610389565b005b610142610152366004610d3b565b6103cf565b34801561016357600080fd5b50610142610172366004610d70565b61040d565b34801561018357600080fd5b50610197610192366004610d70565b610481565b6040516001600160a01b03909116815260200160405180910390f35b3480156101bf57600080fd5b506101426101ce366004610d8d565b6104b7565b3480156101df57600080fd5b506101976101ee366004610d70565b6105fb565b610142610201366004610e7d565b610691565b34801561021257600080fd5b50610142610221366004610d70565b610781565b34801561023257600080fd5b50610142610241366004610f7a565b6107f5565b610142610254366004610d3b565b61096e565b610142610267366004610fde565b6109a8565b34801561027857600080fd5b50610197610287366004610d70565b6067602052600090815260409020546001600160a01b031681565b3480156102ae57600080fd5b50610142610a8c565b61014261013d36600461103f565b3480156102d157600080fd5b50606554610197906001600160a01b031681565b3480156102f157600080fd5b506033546001600160a01b0316610197565b6101426103113660046110d7565b610ac2565b34801561032257600080fd5b50610197610331366004610d70565b610ad5565b61014261034436600461111d565b610b0e565b34801561035557600080fd5b50606654610197906001600160a01b031681565b34801561037557600080fd5b50610142610384366004610d70565b610b1e565b60405162461bcd60e51b81526020600482015260166024820152751cda1bdd5b19081b995d995c8818994818d85b1b195960521b60448201526064015b60405180910390fd5b610408838360005b6040519080825280601f01601f191660200182016040528015610401576020820181803683370190505b50846109a8565b505050565b6033546001600160a01b031633146104375760405162461bcd60e51b81526004016103c69061113f565b606580546001600160a01b0319166001600160a01b0383169081179091556040517fadf5b643c52781d8c742887e4a7a282a5bf2beb794ae3582fdf97e05df00301890600090a250565b6001600160a01b03808216600090815260676020526040812054909116806104b157506066546001600160a01b03165b92915050565b600054610100900460ff166104d25760005460ff16156104d6565b303b155b6105395760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016103c6565b600054610100900460ff1615801561055b576000805461ffff19166101011790555b610563610bb9565b6001600160a01b0382161561058e57606680546001600160a01b0319166001600160a01b0384161790555b6001600160a01b038316156105e557606580546001600160a01b0319166001600160a01b0385169081179091556040517fadf5b643c52781d8c742887e4a7a282a5bf2beb794ae3582fdf97e05df00301890600090a25b8015610408576000805461ff0019169055505050565b60008061060783610481565b90506001600160a01b0381166106205750600092915050565b60405163152ef56760e21b81526001600160a01b0384811660048301528216906354bbd59c90602401602060405180830381865afa158015610666573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068a9190611174565b9392505050565b600061069c86610481565b90506001600160a01b0381166106eb5760405162461bcd60e51b81526020600482015260146024820152736e6f206761746577617920617661696c61626c6560601b60448201526064016103c6565b600033846040516020016107009291906111de565b60408051601f1981840301815290829052632ba9b0db60e11b825291506001600160a01b0383169063575361b6903490610746908b908b908b9088908b9060040161120a565b6000604051808303818588803b15801561075f57600080fd5b505af1158015610773573d6000803e3d6000fd5b505050505050505050505050565b6033546001600160a01b031633146107ab5760405162461bcd60e51b81526004016103c69061113f565b606680546001600160a01b0319166001600160a01b0383169081179091556040517f08338857eef8e29b906267c37965aff1fdcdb2c18d0f7b52de3b2eb71474d35c90600090a250565b6033546001600160a01b0316331461081f5760405162461bcd60e51b81526004016103c69061113f565b80518251146108625760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b60448201526064016103c6565b60005b8251811015610408578181815181106108805761088061124f565b60200260200101516067600085848151811061089e5761089e61124f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508181815181106108fc576108fc61124f565b60200260200101516001600160a01b031683828151811061091f5761091f61124f565b60200260200101516001600160a01b03167f5b0c89ecf574aa07194121c4f4dd1cfbaaf37d303c22522c9498a0aaf678668d60405160405180910390a38061096681611265565b915050610865565b61040883338460005b6040519080825280601f01601f1916602001820160405280156109a1576020820181803683370190505b5085610691565b6065546001600160a01b0316806109f95760405162461bcd60e51b8152602060048201526015602482015274657468206761746577617920617661696c61626c6560581b60448201526064016103c6565b60003384604051602001610a0e9291906111de565b60408051601f1981840301815290829052636dc2418360e01b825291506001600160a01b03831690636dc24183903490610a52908a908a9087908a9060040161128e565b6000604051808303818588803b158015610a6b57600080fd5b505af1158015610a7f573d6000803e3d6000fd5b5050505050505050505050565b6033546001600160a01b03163314610ab65760405162461bcd60e51b81526004016103c69061113f565b610ac06000610be8565b565b610acf8484846000610977565b50505050565b60405162461bcd60e51b815260206004820152600b60248201526a1d5b9cdd5c1c1bdc9d195960aa1b60448201526000906064016103c6565b610b1a338360006103d7565b5050565b6033546001600160a01b03163314610b485760405162461bcd60e51b81526004016103c69061113f565b6001600160a01b038116610bad5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103c6565b610bb681610be8565b50565b600054610100900460ff16610be05760405162461bcd60e51b81526004016103c6906112c6565b610ac0610c3a565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16610c615760405162461bcd60e51b81526004016103c6906112c6565b610ac033610be8565b6001600160a01b0381168114610bb657600080fd5b60008083601f840112610c9157600080fd5b50813567ffffffffffffffff811115610ca957600080fd5b602083019150836020828501011115610cc157600080fd5b9250929050565b600080600080600060808688031215610ce057600080fd5b8535610ceb81610c6a565b94506020860135610cfb81610c6a565b935060408601359250606086013567ffffffffffffffff811115610d1e57600080fd5b610d2a88828901610c7f565b969995985093965092949392505050565b600080600060608486031215610d5057600080fd5b8335610d5b81610c6a565b95602085013595506040909401359392505050565b600060208284031215610d8257600080fd5b813561068a81610c6a565b60008060408385031215610da057600080fd5b8235610dab81610c6a565b91506020830135610dbb81610c6a565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610e0557610e05610dc6565b604052919050565b600082601f830112610e1e57600080fd5b813567ffffffffffffffff811115610e3857610e38610dc6565b610e4b601f8201601f1916602001610ddc565b818152846020838601011115610e6057600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215610e9557600080fd5b8535610ea081610c6a565b94506020860135610eb081610c6a565b935060408601359250606086013567ffffffffffffffff811115610ed357600080fd5b610edf88828901610e0d565b95989497509295608001359392505050565b600082601f830112610f0257600080fd5b8135602067ffffffffffffffff821115610f1e57610f1e610dc6565b8160051b610f2d828201610ddc565b9283528481018201928281019087851115610f4757600080fd5b83870192505b84831015610f6f578235610f6081610c6a565b82529183019190830190610f4d565b979650505050505050565b60008060408385031215610f8d57600080fd5b823567ffffffffffffffff80821115610fa557600080fd5b610fb186838701610ef1565b93506020850135915080821115610fc757600080fd5b50610fd485828601610ef1565b9150509250929050565b60008060008060808587031215610ff457600080fd5b8435610fff81610c6a565b935060208501359250604085013567ffffffffffffffff81111561102257600080fd5b61102e87828801610e0d565b949793965093946060013593505050565b600080600080600080600060c0888a03121561105a57600080fd5b873561106581610c6a565b9650602088013561107581610c6a565b9550604088013561108581610c6a565b9450606088013561109581610c6a565b93506080880135925060a088013567ffffffffffffffff8111156110b857600080fd5b6110c48a828b01610c7f565b989b979a50959850939692959293505050565b600080600080608085870312156110ed57600080fd5b84356110f881610c6a565b9350602085013561110881610c6a565b93969395505050506040820135916060013590565b6000806040838503121561113057600080fd5b50508035926020909101359150565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60006020828403121561118657600080fd5b815161068a81610c6a565b6000815180845260005b818110156111b75760208185018101518683018201520161119b565b818111156111c9576000602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b038316815260406020820181905260009061120290830184611191565b949350505050565b6001600160a01b038681168252851660208201526040810184905260a06060820181905260009061123d90830185611191565b90508260808301529695505050505050565b634e487b7160e01b600052603260045260246000fd5b600060001982141561128757634e487b7160e01b600052601160045260246000fd5b5060010190565b60018060a01b03851681528360208201526080604082015260006112b56080830185611191565b905082606083015295945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea26469706673582212203347acf5da800d41c761438be0419fb6efef247b69734396f07c8748b797f08664736f6c634300080a003383104ec5a0647b9699fe9b89985608634a276f6436a8a28a4dda21180675443e6ad58ed5faa05ec6d2f37c23a22a28a5b8f26fa6d5c6409db3adb62eaf66680eb146233970a80000103af910370a01830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656400000000000000000000000043695ef7bc361713e7c615659f826655434f7b88000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec6a00263438d787304bd66a110c99882dcc551af3ee6736e74ab6cf81a87507bd7aca05566b38368c4bffc1bfc96229dbf6b94735eabe91ae91ea4fda37e423c94c3ba0000195ef9195b0b01831c609b8080b9190a608060405234801561001057600080fd5b506118ea806100206000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c806370a08231116100ad578063a457c2d711610071578063a457c2d71461028e578063a9059cbb146102a1578063c820f146146102b4578063d505accf146102c7578063dd62ed3e146102da57600080fd5b806370a0823114610224578063797594b01461024d5780637ecebe001461026057806395d89b41146102735780639dc29fac1461027b57600080fd5b8063313ce567116100f4578063313ce567146101c25780633644e515146101e157806339509351146101e95780634000aea0146101fc57806340c10f191461020f57600080fd5b806306fdde0314610131578063095ea7b31461014f578063116191b61461017257806318160ddd1461019d57806323b872dd146101af575b600080fd5b610139610313565b6040516101469190611484565b60405180910390f35b61016261015d3660046114ba565b6103a5565b6040519015158152602001610146565b60cc54610185906001600160a01b031681565b6040516001600160a01b039091168152602001610146565b6035545b604051908152602001610146565b6101626101bd3660046114e4565b6103bd565b60cd54600160a01b900460ff1660405160ff9091168152602001610146565b6101a16103e1565b6101626101f73660046114ba565b6103f0565b61016261020a366004611520565b61042f565b61022261021d3660046114ba565b610484565b005b6101a16102323660046115a7565b6001600160a01b031660009081526033602052604090205490565b60cd54610185906001600160a01b031681565b6101a161026e3660046115a7565b6104e0565b610139610500565b6102226102893660046114ba565b61050f565b61016261029c3660046114ba565b610562565b6101626102af3660046114ba565b6105f4565b6102226102c2366004611676565b610602565b6102226102d536600461170c565b61071a565b6101a16102e8366004611776565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b606060368054610322906117a9565b80601f016020809104026020016040519081016040528092919081815260200182805461034e906117a9565b801561039b5780601f106103705761010080835404028352916020019161039b565b820191906000526020600020905b81548152906001019060200180831161037e57829003601f168201915b5050505050905090565b6000336103b3818585610860565b5060019392505050565b6000336103cb858285610985565b6103d6858585610a17565b506001949350505050565b60006103eb610be5565b905090565b3360008181526034602090815260408083206001600160a01b03871684529091528120549091906103b3908290869061042a9087906117f4565b610860565b600061043b85856105f4565b50843b156103d6576103d6858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610c6092505050565b60cc546001600160a01b031633146104d25760405162461bcd60e51b815260206004820152600c60248201526b4f6e6c79204761746577617960a01b60448201526064015b60405180910390fd5b6104dc8282610cca565b5050565b6001600160a01b0381166000908152609960205260408120545b92915050565b606060378054610322906117a9565b60cc546001600160a01b031633146105585760405162461bcd60e51b815260206004820152600c60248201526b4f6e6c79204761746577617960a01b60448201526064016104c9565b6104dc8282610da9565b3360008181526034602090815260408083206001600160a01b0387168452909152812054909190838110156105e75760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016104c9565b6103d68286868403610860565b6000336103b3818585610a17565b600054610100900460ff1661061d5760005460ff1615610621565b303b155b6106845760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c9565b600054610100900460ff161580156106a6576000805461ffff19166101011790555b6106af86610ef4565b6106b98686610f4a565b60cd805460cc80546001600160a01b038088166001600160a01b03199283161790925590851660ff8816600160a01b02919091166001600160a81b0319909216919091171790558015610712576000805461ff00191690555b505050505050565b8342111561076a5760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016104c9565b6000609a5488888861077b8c610f7b565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e00160405160208183030381529060405280519060200120905060006107d682610fa3565b905060006107e682878787610ff1565b9050896001600160a01b0316816001600160a01b0316146108495760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016104c9565b6108548a8a8a610860565b50505050505050505050565b6001600160a01b0383166108c25760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016104c9565b6001600160a01b0382166109235760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104c9565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b038381166000908152603460209081526040808320938616835292905220546000198114610a115781811015610a045760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104c9565b610a118484848403610860565b50505050565b6001600160a01b038316610a7b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104c9565b6001600160a01b038216610add5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104c9565b6001600160a01b03831660009081526033602052604090205481811015610b555760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104c9565b6001600160a01b03808516600090815260336020526040808220858503905591851681529081208054849290610b8c9084906117f4565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610bd891815260200190565b60405180910390a3610a11565b60006103eb7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f610c1460655490565b6066546040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b604051635260769b60e11b815283906001600160a01b0382169063a4c0ed3690610c929033908790879060040161180c565b600060405180830381600087803b158015610cac57600080fd5b505af1158015610cc0573d6000803e3d6000fd5b5050505050505050565b6001600160a01b038216610d205760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016104c9565b8060356000828254610d3291906117f4565b90915550506001600160a01b03821660009081526033602052604081208054839290610d5f9084906117f4565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001600160a01b038216610e095760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016104c9565b6001600160a01b03821660009081526033602052604090205481811015610e7d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016104c9565b6001600160a01b0383166000908152603360205260408120838303905560358054849290610eac90849061183c565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610978565b505050565b600054610100900460ff16610f1b5760405162461bcd60e51b81526004016104c990611853565b610f3e81604051806040016040528060018152602001603160f81b815250611019565b610f478161105a565b50565b600054610100900460ff16610f715760405162461bcd60e51b81526004016104c990611853565b6104dc82826110a8565b6001600160a01b03811660009081526099602052604090208054600181018255905b50919050565b60006104fa610fb0610be5565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000806000611002878787876110f6565b9150915061100f816111e3565b5095945050505050565b600054610100900460ff166110405760405162461bcd60e51b81526004016104c990611853565b815160209283012081519190920120606591909155606655565b600054610100900460ff166110815760405162461bcd60e51b81526004016104c990611853565b507f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9609a55565b600054610100900460ff166110cf5760405162461bcd60e51b81526004016104c990611853565b81516110e290603690602085019061139e565b508051610eef90603790602084019061139e565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561112d57506000905060036111da565b8460ff16601b1415801561114557508460ff16601c14155b1561115657506000905060046111da565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156111aa573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166111d3576000600192509250506111da565b9150600090505b94509492505050565b60008160048111156111f7576111f761189e565b14156112005750565b60018160048111156112145761121461189e565b14156112625760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016104c9565b60028160048111156112765761127661189e565b14156112c45760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016104c9565b60038160048111156112d8576112d861189e565b14156113315760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016104c9565b60048160048111156113455761134561189e565b1415610f475760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016104c9565b8280546113aa906117a9565b90600052602060002090601f0160209004810192826113cc5760008555611412565b82601f106113e557805160ff1916838001178555611412565b82800160010185558215611412579182015b828111156114125782518255916020019190600101906113f7565b5061141e929150611422565b5090565b5b8082111561141e5760008155600101611423565b6000815180845260005b8181101561145d57602081850181015186830182015201611441565b8181111561146f576000602083870101525b50601f01601f19169290920160200192915050565b6020815260006114976020830184611437565b9392505050565b80356001600160a01b03811681146114b557600080fd5b919050565b600080604083850312156114cd57600080fd5b6114d68361149e565b946020939093013593505050565b6000806000606084860312156114f957600080fd5b6115028461149e565b92506115106020850161149e565b9150604084013590509250925092565b6000806000806060858703121561153657600080fd5b61153f8561149e565b935060208501359250604085013567ffffffffffffffff8082111561156357600080fd5b818701915087601f83011261157757600080fd5b81358181111561158657600080fd5b88602082850101111561159857600080fd5b95989497505060200194505050565b6000602082840312156115b957600080fd5b6114978261149e565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126115e957600080fd5b813567ffffffffffffffff80821115611604576116046115c2565b604051601f8301601f19908116603f0116810190828211818310171561162c5761162c6115c2565b8160405283815286602085880101111561164557600080fd5b836020870160208301376000602085830101528094505050505092915050565b803560ff811681146114b557600080fd5b600080600080600060a0868803121561168e57600080fd5b853567ffffffffffffffff808211156116a657600080fd5b6116b289838a016115d8565b965060208801359150808211156116c857600080fd5b506116d5888289016115d8565b9450506116e460408701611665565b92506116f26060870161149e565b91506117006080870161149e565b90509295509295909350565b600080600080600080600060e0888a03121561172757600080fd5b6117308861149e565b965061173e6020890161149e565b9550604088013594506060880135935061175a60808901611665565b925060a0880135915060c0880135905092959891949750929550565b6000806040838503121561178957600080fd5b6117928361149e565b91506117a06020840161149e565b90509250929050565b600181811c908216806117bd57607f821691505b60208210811415610f9d57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115611807576118076117de565b500190565b60018060a01b03841681528260208201526060604082015260006118336060830184611437565b95945050505050565b60008282101561184e5761184e6117de565b500390565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052602160045260246000fdfea26469706673582212202b07f710c9cf1804584777652b1341e9dfb5fb6c87078d0ae916c80f07eec4b164736f6c634300080a003383104ec5a031ef9b29d7ea5286dc6a9790d031b76b14aae03fde4d19309468fd3551576be7a016ee0b1c15f6f776b57c307ab4b01c0db5053891d4f82af1d0e892b41960667b000006b6f906b30c01830788a08080b90662608060405234801561001057600080fd5b5060405161064238038061064283398101604081905261002f91610107565b610038336100b7565b6001600160a01b0381166100925760405162461bcd60e51b815260206004820152601b60248201527f7a65726f20696d706c656d656e746174696f6e20616464726573730000000000604482015260640160405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055610137565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561011957600080fd5b81516001600160a01b038116811461013057600080fd5b9392505050565b6104fc806101466000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80635c60da1b1461006757806361e98ca114610096578063715018a6146100a95780637bdbcbbf146100b35780638da5cb5b146100c6578063f2fde38b146100d7575b600080fd5b60015461007a906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b61007a6100a4366004610443565b6100ea565b6100b161011a565b005b61007a6100c1366004610443565b610159565b6000546001600160a01b031661007a565b6100b16100e5366004610476565b6101a9565b6000806100f78484610244565b600154909150610110906001600160a01b0316826102ca565b9150505b92915050565b6000546001600160a01b0316331461014d5760405162461bcd60e51b815260040161014490610491565b60405180910390fd5b6101576000610337565b565b600080546001600160a01b031633146101845760405162461bcd60e51b815260040161014490610491565b60006101908484610244565b600154909150610110906001600160a01b031682610387565b6000546001600160a01b031633146101d35760405162461bcd60e51b815260040161014490610491565b6001600160a01b0381166102385760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610144565b61024181610337565b50565b6040516bffffffffffffffffffffffff19606083901b1660208201526000908390603401604051602081830303815290604052805190602001206040516020016102ac92919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b60405160208183030381529060405280519060200120905092915050565b6000610330838330604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b8152606093841b60148201526f5af43d82803e903d91602b57fd5bf3ff60801b6028820152921b6038830152604c8201526037808220606c830152605591012090565b9392505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b0381166101145760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401610144565b80356001600160a01b038116811461043e57600080fd5b919050565b6000806040838503121561045657600080fd5b61045f83610427565b915061046d60208401610427565b90509250929050565b60006020828403121561048857600080fd5b61033082610427565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea264697066735822122048e180d3bf138a23835ff5a47862fb56a14aa7622da00c39f5ed29ff33813fcb64736f6c634300080a00330000000000000000000000004afeda25e80d4292f2dbefce8215df4dde94db3a83104ec6a07f85f6072ad1ad801f029ad16b2db387194c56d6372054ccc6db68fbda66f244a0665e33a0b77a613098202095b504ff5d7d9e2dece7e6926a657e16d16f8372430000131df9131a0d018315836b8080b912c9608060405234801561001057600080fd5b506112a9806100206000396000f3fe6080604052600436106100e85760003560e01c80638da5cb5b1161008a578063c676ad2911610059578063c676ad2914610259578063f2fde38b14610279578063f887ea4014610299578063fac752eb146102b957600080fd5b80638da5cb5b146101d2578063a93a4af9146101f0578063ba27f50b14610203578063c0c53b8b1461023957600080fd5b80636c07ea43116100c65780636c07ea4314610177578063715018a61461018a578063797594b01461019f5780638431f5c1146101bf57600080fd5b80633cb747bf146100ed57806354bbd59c14610129578063575361b614610162575b600080fd5b3480156100f957600080fd5b5060675461010d906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b34801561013557600080fd5b5061010d610144366004610d27565b6001600160a01b039081166000908152606960205260409020541690565b610175610170366004610d94565b6102d9565b005b610175610185366004610e0f565b610325565b34801561019657600080fd5b50610175610364565b3480156101ab57600080fd5b5060655461010d906001600160a01b031681565b6101756101cd366004610e44565b6103a3565b3480156101de57600080fd5b506033546001600160a01b031661010d565b6101756101fe366004610edc565b610626565b34801561020f57600080fd5b5061010d61021e366004610d27565b6069602052600090815260409020546001600160a01b031681565b34801561024557600080fd5b50610175610254366004610f22565b610639565b34801561026557600080fd5b5061010d610274366004610d27565b610753565b34801561028557600080fd5b50610175610294366004610d27565b61078e565b3480156102a557600080fd5b5060665461010d906001600160a01b031681565b3480156102c557600080fd5b506101756102d4366004610f6d565b610829565b61031d86868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525088925061090a915050565b505050505050565b61035f83338460005b6040519080825280601f01601f191660200182016040528015610358576020820181803683370190505b508561090a565b505050565b6033546001600160a01b031633146103975760405162461bcd60e51b815260040161038e90610fbc565b60405180910390fd5b6103a16000610b61565b565b6067546001600160a01b03163381146103fe5760405162461bcd60e51b815260206004820152601760248201527f6f6e6c79206d657373656e6765722063616e2063616c6c000000000000000000604482015260640161038e565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561043c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104609190610ff1565b6065546001600160a01b039081169116146104bd5760405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063616c6c20627920636f6e74657270617274000000000000000000604482015260640161038e565b34156104ff5760405162461bcd60e51b81526020600482015260116024820152706e6f6e7a65726f206d73672e76616c756560781b604482015260640161038e565b6001600160a01b0380881660009081526069602052604090205489821691161461055f5760405162461bcd60e51b81526020600482015260116024820152700d86240e8ded6cadc40dad2e6dac2e8c6d607b1b604482015260640161038e565b6040516340c10f1960e01b81526001600160a01b038681166004830152602482018690528816906340c10f1990604401600060405180830381600087803b1580156105a957600080fd5b505af11580156105bd573d6000803e3d6000fd5b50505050856001600160a01b0316876001600160a01b0316896001600160a01b03167f165ba69f6ab40c50cade6f65431801e5f9c7d7830b7545391920db039133ba3488888888604051610614949392919061100e565b60405180910390a45050505050505050565b610633848484600061032e565b50505050565b600054610100900460ff166106545760005460ff1615610658565b303b155b6106bb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161038e565b600054610100900460ff161580156106dd576000805461ffff19166101011790555b6001600160a01b0383166107295760405162461bcd60e51b81526020600482015260136024820152727a65726f20726f75746572206164647265737360681b604482015260640161038e565b610731610bb3565b61073c848484610be2565b8015610633576000805461ff001916905550505050565b60405162461bcd60e51b815260206004820152600d60248201526c1d5b9a5b5c1b195b595b9d1959609a1b604482015260009060640161038e565b6033546001600160a01b031633146107b85760405162461bcd60e51b815260040161038e90610fbc565b6001600160a01b03811661081d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161038e565b61082681610b61565b50565b6033546001600160a01b031633146108535760405162461bcd60e51b815260040161038e90610fbc565b6001600160a01b03811661089f5760405162461bcd60e51b81526020600482015260136024820152726d617020746f207a65726f206164647265737360681b604482015260640161038e565b6001600160a01b0382811660008181526069602090815260409182902080546001600160a01b031916948616948517905581519283528201929092527fcb7d5959c6ea086e1e4326bb4745f80c494524693345a2ca0f1f1221d7cc77db910160405180910390a15050565b6001600160a01b0380861660009081526069602052604090205416806109725760405162461bcd60e51b815260206004820152601960248201527f6e6f20636f72726573706f6e64696e67206c3120746f6b656e00000000000000604482015260640161038e565b600084116109b95760405162461bcd60e51b81526020600482015260146024820152731dda5d1a191c985dc81e995c9bc8185b5bdd5b9d60621b604482015260640161038e565b60665433906001600160a01b03168114156109e757838060200190518101906109e29190611082565b945090505b604051632770a7eb60e21b81526001600160a01b03828116600483015260248201879052881690639dc29fac90604401600060405180830381600087803b158015610a3157600080fd5b505af1158015610a45573d6000803e3d6000fd5b5050505060006384bd13b060e01b8389848a8a8a604051602401610a6e96959493929190611171565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252606754606554925163b2267a7b60e01b81529193506001600160a01b039081169263b2267a7b923492610ade92169060009087908b906004016111c0565b6000604051808303818588803b158015610af757600080fd5b505af1158015610b0b573d6000803e3d6000fd5b5050505050816001600160a01b0316886001600160a01b0316846001600160a01b03167fd8d3a3f4ab95694bef40475997598bcf8acd3ed9617a4c1013795429414c27e88a8a8a604051610614939291906111f8565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16610bda5760405162461bcd60e51b815260040161038e90611228565b6103a1610ce2565b6001600160a01b038316610c385760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e7465727061727420616464726573730000000000000000604482015260640161038e565b6001600160a01b038116610c875760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b604482015260640161038e565b606580546001600160a01b038086166001600160a01b031992831617909255606780548484169216919091179055821615610cd857606680546001600160a01b0319166001600160a01b0384161790555b5050600160685550565b600054610100900460ff16610d095760405162461bcd60e51b815260040161038e90611228565b6103a133610b61565b6001600160a01b038116811461082657600080fd5b600060208284031215610d3957600080fd5b8135610d4481610d12565b9392505050565b60008083601f840112610d5d57600080fd5b50813567ffffffffffffffff811115610d7557600080fd5b602083019150836020828501011115610d8d57600080fd5b9250929050565b60008060008060008060a08789031215610dad57600080fd5b8635610db881610d12565b95506020870135610dc881610d12565b945060408701359350606087013567ffffffffffffffff811115610deb57600080fd5b610df789828a01610d4b565b979a9699509497949695608090950135949350505050565b600080600060608486031215610e2457600080fd5b8335610e2f81610d12565b95602085013595506040909401359392505050565b600080600080600080600060c0888a031215610e5f57600080fd5b8735610e6a81610d12565b96506020880135610e7a81610d12565b95506040880135610e8a81610d12565b94506060880135610e9a81610d12565b93506080880135925060a088013567ffffffffffffffff811115610ebd57600080fd5b610ec98a828b01610d4b565b989b979a50959850939692959293505050565b60008060008060808587031215610ef257600080fd5b8435610efd81610d12565b93506020850135610f0d81610d12565b93969395505050506040820135916060013590565b600080600060608486031215610f3757600080fd5b8335610f4281610d12565b92506020840135610f5281610d12565b91506040840135610f6281610d12565b809150509250925092565b60008060408385031215610f8057600080fd5b8235610f8b81610d12565b91506020830135610f9b81610d12565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60006020828403121561100357600080fd5b8151610d4481610d12565b6001600160a01b0385168152602081018490526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b60005b83811015611071578181015183820152602001611059565b838111156106335750506000910152565b6000806040838503121561109557600080fd5b82516110a081610d12565b602084015190925067ffffffffffffffff808211156110be57600080fd5b818501915085601f8301126110d257600080fd5b8151818111156110e4576110e4610fa6565b604051601f8201601f19908116603f0116810190838211818310171561110c5761110c610fa6565b8160405282815288602084870101111561112557600080fd5b611136836020830160208801611056565b80955050505050509250929050565b6000815180845261115d816020860160208601611056565b601f01601f19169290920160200192915050565b6001600160a01b03878116825286811660208301528581166040830152841660608201526080810183905260c060a082018190526000906111b490830184611145565b98975050505050505050565b60018060a01b03851681528360208201526080604082015260006111e76080830185611145565b905082606083015295945050505050565b60018060a01b038416815282602082015260606040820152600061121f6060830184611145565b95945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220e5b31147beb7149f943fd34ed82358681c86eefe32935965beeffd9511dca8cf64736f6c634300080a003383104ec6a075e3bea2bff92bcb4c53ac9abdc144dd8d1e610e65d76986de5cec433eee8289a001f1ac5ebf6c8fc7a182f76e0e8e3b19a91b199b5438d64d1338627fd5185ec50000103af910370e01830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656400000000000000000000000074ccd92ba10c9dbc320e8801d9d488f6d157767d000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec6a0fbbb5ddad530ae9b83f6f492739175927f38e4db5b31f2e1d6525c42d38cece9a00625deb6dfd651faf74061b127607abcf93cce73f24d6760dd2e1294adaf0a1e000017e1f917de0f01831abee58080b9178d608060405234801561001057600080fd5b5061176d806100206000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063982b151f11610097578063f2fde38b11610066578063f2fde38b14610235578063f887ea4014610248578063f8c3cf251461025b578063fac752eb1461026e57600080fd5b8063982b151f146101d3578063aa4c1158146101e6578063ba27f50b146101f9578063ee5a8db21461022257600080fd5b8063485cc955116100d3578063485cc95514610194578063715018a6146101a7578063797594b0146101af5780638da5cb5b146101c257600080fd5b8063150b7a02146101055780632a491247146101415780633cb747bf1461015657806346aa341114610181575b600080fd5b610123610113366004611144565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020015b60405180910390f35b61015461014f366004611224565b610281565b005b609954610169906001600160a01b031681565b6040516001600160a01b039091168152602001610138565b61015461018f3660046112a5565b610292565b6101546101a2366004611301565b6102a5565b610154610378565b609754610169906001600160a01b031681565b6033546001600160a01b0316610169565b6101546101e136600461133a565b6103ae565b6101546101f43660046113c8565b6105f3565b610169610207366004611435565b609b602052600090815260409020546001600160a01b031681565b610154610230366004611459565b610607565b610154610243366004611435565b610613565b609854610169906001600160a01b031681565b61015461026936600461149f565b6106ae565b61015461027c366004611301565b6108a2565b61028d83338484610983565b505050565b61029f8433858585610c20565b50505050565b600054610100900460ff166102c05760005460ff16156102c4565b303b155b61032c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b600054610100900460ff1615801561034e576000805461ffff19166101011790555b610356610f68565b61036283600084610f97565b801561028d576000805461ff0019169055505050565b6033546001600160a01b031633146103a25760405162461bcd60e51b815260040161032390611503565b6103ac6000611097565b565b6002609a5414156103d15760405162461bcd60e51b815260040161032390611538565b6002609a556099546001600160a01b031633811461042b5760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b6044820152606401610323565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610469573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048d919061156f565b6097546001600160a01b039081169116146104e45760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e4818d85b1b08189e4818dbdb9d195c9c185c9d604a1b6044820152606401610323565b60005b8281101561058b57866001600160a01b03166340c10f19868686858181106105115761051161158c565b6040516001600160e01b031960e087901b1681526001600160a01b0390941660048501526020029190910135602483015250604401600060405180830381600087803b15801561056057600080fd5b505af1158015610574573d6000803e3d6000fd5b505050508080610583906115a2565b9150506104e7565b50846001600160a01b0316866001600160a01b0316886001600160a01b03167fafa88b850da44ca05b319e813873eac8d08e7c041d2d9b3072db0f087e3cd29e8787876040516105dd93929190611601565b60405180910390a450506001609a555050505050565b6106008585858585610c20565b5050505050565b61029f84848484610983565b6033546001600160a01b0316331461063d5760405162461bcd60e51b815260040161032390611503565b6001600160a01b0381166106a25760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610323565b6106ab81611097565b50565b6002609a5414156106d15760405162461bcd60e51b815260040161032390611538565b6002609a556099546001600160a01b031633811461072b5760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b6044820152606401610323565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610769573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078d919061156f565b6097546001600160a01b039081169116146107e45760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e4818d85b1b08189e4818dbdb9d195c9c185c9d604a1b6044820152606401610323565b6040516340c10f1960e01b81526001600160a01b038481166004830152602482018490528616906340c10f1990604401600060405180830381600087803b15801561082e57600080fd5b505af1158015610842573d6000803e3d6000fd5b5050604080516001600160a01b03878116825260208201879052808916945089811693508a16917fc655ec1de34d98630aa4572239414f926d6b3d07653dde093a6df97377e31b4191015b60405180910390a450506001609a5550505050565b6033546001600160a01b031633146108cc5760405162461bcd60e51b815260040161032390611503565b6001600160a01b0381166109185760405162461bcd60e51b81526020600482015260136024820152726d617020746f207a65726f206164647265737360681b6044820152606401610323565b6001600160a01b038281166000818152609b602090815260409182902080546001600160a01b031916948616948517905581519283528201929092527fcb7d5959c6ea086e1e4326bb4745f80c494524693345a2ca0f1f1221d7cc77db910160405180910390a15050565b6002609a5414156109a65760405162461bcd60e51b815260040161032390611538565b6002609a556001600160a01b038085166000908152609b60205260409020541680610a095760405162461bcd60e51b81526020600482015260136024820152721d1bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606401610323565b6040516331a9108f60e11b81526004810184905233906001600160a01b03871690636352211e90602401602060405180830381865afa158015610a50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a74919061156f565b6001600160a01b031614610abc5760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd081bdddb9959608a1b6044820152606401610323565b604051630852cd8d60e31b8152600481018490526001600160a01b038616906342966c6890602401600060405180830381600087803b158015610afe57600080fd5b505af1158015610b12573d6000803e3d6000fd5b5050604080516001600160a01b0385811660248301528981166044830152336064830152888116608483015260a48083018990528351808403909101815260c490920183526020820180516001600160e01b0316633581ad3760e21b179052609954609754935163b2267a7b60e01b81529295508116935063b2267a7b92610ba59291169034908690899060040161162f565b600060405180830381600087803b158015610bbf57600080fd5b505af1158015610bd3573d6000803e3d6000fd5b5050604080516001600160a01b038981168252602082018990523394508a811693508616917fe9e85cf0c862dd491ecda3c9a230e12ada8956472028ebde4fdc4f8e2d77bcda910161088d565b6002609a541415610c435760405162461bcd60e51b815260040161032390611538565b6002609a5581610c8c5760405162461bcd60e51b81526020600482015260146024820152736e6f20746f6b656e20746f20776974686472617760601b6044820152606401610323565b6001600160a01b038086166000908152609b60205260409020541680610cea5760405162461bcd60e51b81526020600482015260136024820152721d1bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b6044820152606401610323565b60005b83811015610e5057336001600160a01b038816636352211e878785818110610d1757610d1761158c565b905060200201356040518263ffffffff1660e01b8152600401610d3c91815260200190565b602060405180830381865afa158015610d59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7d919061156f565b6001600160a01b031614610dc55760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd081bdddb9959608a1b6044820152606401610323565b866001600160a01b03166342966c68868684818110610de657610de661158c565b905060200201356040518263ffffffff1660e01b8152600401610e0b91815260200190565b600060405180830381600087803b158015610e2557600080fd5b505af1158015610e39573d6000803e3d6000fd5b505050508080610e48906115a2565b915050610ced565b506000639f0a68b360e01b828833898989604051602401610e76969594939291906116a3565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252609954609754925163b2267a7b60e01b81529193506001600160a01b039081169263b2267a7b923492610ee5921690839087908a9060040161162f565b6000604051808303818588803b158015610efe57600080fd5b505af1158015610f12573d6000803e3d6000fd5b5050505050336001600160a01b0316876001600160a01b0316836001600160a01b03167fbdb7b5cec70093e3ce49b258071951d245c0871c006fd9327778c69d0e9f244d8989896040516105dd93929190611601565b600054610100900460ff16610f8f5760405162461bcd60e51b8152600401610323906116ec565b6103ac6110e9565b6001600160a01b038316610fed5760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e74657270617274206164647265737300000000000000006044820152606401610323565b6001600160a01b03811661103c5760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b6044820152606401610323565b609780546001600160a01b038086166001600160a01b03199283161790925560998054848416921691909117905582161561108d57609880546001600160a01b0319166001600160a01b0384161790555b50506001609a5550565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166111105760405162461bcd60e51b8152600401610323906116ec565b6103ac33611097565b6001600160a01b03811681146106ab57600080fd5b634e487b7160e01b600052604160045260246000fd5b6000806000806080858703121561115a57600080fd5b843561116581611119565b9350602085013561117581611119565b925060408501359150606085013567ffffffffffffffff8082111561119957600080fd5b818701915087601f8301126111ad57600080fd5b8135818111156111bf576111bf61112e565b604051601f8201601f19908116603f011681019083821181831017156111e7576111e761112e565b816040528281528a602084870101111561120057600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060006060848603121561123957600080fd5b833561124481611119565b95602085013595506040909401359392505050565b60008083601f84011261126b57600080fd5b50813567ffffffffffffffff81111561128357600080fd5b6020830191508360208260051b850101111561129e57600080fd5b9250929050565b600080600080606085870312156112bb57600080fd5b84356112c681611119565b9350602085013567ffffffffffffffff8111156112e257600080fd5b6112ee87828801611259565b9598909750949560400135949350505050565b6000806040838503121561131457600080fd5b823561131f81611119565b9150602083013561132f81611119565b809150509250929050565b60008060008060008060a0878903121561135357600080fd5b863561135e81611119565b9550602087013561136e81611119565b9450604087013561137e81611119565b9350606087013561138e81611119565b9250608087013567ffffffffffffffff8111156113aa57600080fd5b6113b689828a01611259565b979a9699509497509295939492505050565b6000806000806000608086880312156113e057600080fd5b85356113eb81611119565b945060208601356113fb81611119565b9350604086013567ffffffffffffffff81111561141757600080fd5b61142388828901611259565b96999598509660600135949350505050565b60006020828403121561144757600080fd5b813561145281611119565b9392505050565b6000806000806080858703121561146f57600080fd5b843561147a81611119565b9350602085013561148a81611119565b93969395505050506040820135916060013590565b600080600080600060a086880312156114b757600080fd5b85356114c281611119565b945060208601356114d281611119565b935060408601356114e281611119565b925060608601356114f281611119565b949793965091946080013592915050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60006020828403121561158157600080fd5b815161145281611119565b634e487b7160e01b600052603260045260246000fd5b60006000198214156115c457634e487b7160e01b600052601160045260246000fd5b5060010190565b81835260006001600160fb1b038311156115e457600080fd5b8260051b8083602087013760009401602001938452509192915050565b6001600160a01b038416815260406020820181905260009061162690830184866115cb565b95945050505050565b60018060a01b038516815260006020858184015260806040840152845180608085015260005b818110156116715786810183015185820160a001528201611655565b8181111561168357600060a083870101525b5060608401949094525050601f91909101601f19160160a0019392505050565b6001600160a01b038781168252868116602083015285811660408301528416606082015260a0608082018190526000906116e090830184866115cb565b98975050505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220708f0ea5b7de8a003d2e40c40e2883d15dc5c244bb43c33e870b1671e7d65a0864736f6c634300080a003383104ec6a03103613ab5d4a517e73ef089156a8bfa276c2e3becd595bab2c95bd020d5342aa0543cccba0eea0612237f8c21f57ea0d24f2a04921526973f682ba5c55291f22c0000103af910371001830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564000000000000000000000000b305283ceacca11f19acbe8e49efee301f8a7aff000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec5a0bdf1317fec5d1310f56e0f1d9b963e80044d99c7e5608840ada6ec818aad3dc9a024cf05e5f950048f8cc3576303ea15c5acc3a55baf82f0900442ac184cdf06130000000000000000000000000000000000000000000000000000000000000000000000000000e02d9ce8e5269e364dcc4cff641032e7f79945f20826385a083976ef93af5eadd620b46cbd5ef0ce4f1cae852ab16d07da35553daccce248320b996d602453adac000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030106f5e8c059d121eddcc3e412044c72344a57619ca31a4dbbdbf79ed10418d70000000000000000000000000000000000000000000000000000000000000d00000000000000000000000000000000000000000000000000000000000000000cad27a68b8d7068184224b453308ba539f59215a066a35c8ba9f0a1c0c6fe71ebe3b568958b1eaa4e93f68204e8669e79933afdd9e5665ff6c99d9543ecf95b8f00000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000063f8722d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000981cfe02291f1f900973a4fe7505b196635afcb25a60dcb6e5ebdc58226e8448ad27a68b8d7068184224b453308ba539f59215a066a35c8ba9f0a1c0c6fe71eb00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000063f87230000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dd7db02bf3c3a95dc8dd120e6ee384555c98f7656afa6e9e465a3420de8dc13b981cfe02291f1f900973a4fe7505b196635afcb25a60dcb6e5ebdc58226e844800000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000063f87338000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000bb402abdc2e7f92a92a7dc17cf80608bfda0382cbd0515bd8cd0961b2eceb5ecdd7db02bf3c3a95dc8dd120e6ee384555c98f7656afa6e9e465a3420de8dc13b000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000063f8733b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046d4345c29c2fa00d72cb23d2a32a7209b43d4374c4435260e4eb78c4a8ba70dbb402abdc2e7f92a92a7dc17cf80608bfda0382cbd0515bd8cd0961b2eceb5ec000000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000063f8737d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000d7ee6d9485d5b7c9f935d0e858154e946c13631f51387d0bdeb5a9cd4464781c46d4345c29c2fa00d72cb23d2a32a7209b43d4374c4435260e4eb78c4a8ba70d000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000063f8738c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000c1d3ce3699fae6a0d828fd59f678fb04b3ad5386e0c9458682539ff41e522d7ee6d9485d5b7c9f935d0e858154e946c13631f51387d0bdeb5a9cd4464781c000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000063f87395000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000061137d5b560a9f139cb2117056867140da40ec11a16721cef1252c07cf13005f000c1d3ce3699fae6a0d828fd59f678fb04b3ad5386e0c9458682539ff41e522000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000063f87524000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000e697812777b5c89461c61187825daa85ca67f601d26f81acac81a675057ef0861137d5b560a9f139cb2117056867140da40ec11a16721cef1252c07cf13005f000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000063f87527000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bb956012ddb8a4b8146c27ab0f4e6a2a422f2e3b64bdc6b31d8558691c447c120e697812777b5c89461c61187825daa85ca67f601d26f81acac81a675057ef0800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000063f8752d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000097a0b2fa947a127adf88ea0290b046e9db6462ba916ff8bb75f3f14cdfcd2fabbb956012ddb8a4b8146c27ab0f4e6a2a422f2e3b64bdc6b31d8558691c447c1200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000063f8753f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a1200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000009ef696aa281d59deca384d813ba416325e8c0e7d30cdbda968e8972a98a3822097a0b2fa947a127adf88ea0290b046e9db6462ba916ff8bb75f3f14cdfcd2fab00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000063f8754b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a120000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000391b00001a89f91a861101831da8758080b91a35608060405234801561001057600080fd5b50611a15806100206000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c80638c23d5b2116100a2578063eaa72ad911610071578063eaa72ad91461026f578063f23a6e6114610282578063f2fde38b146102a1578063f887ea40146102b4578063fac752eb146102c757600080fd5b80638c23d5b2146101ea5780638da5cb5b146101fd578063ba27f50b1461020e578063bc197c811461023757600080fd5b80634764cc62116100e95780634764cc6214610196578063485cc955146101a957806348de03de146101bc578063715018a6146101cf578063797594b0146101d757600080fd5b806301ffc9a71461011b5780630f2da0801461014357806321fedfc9146101585780633cb747bf1461016b575b600080fd5b61012e610129366004611116565b6102da565b60405190151581526020015b60405180910390f35b61015661015136600461115c565b610311565b005b610156610166366004611197565b610324565b60fd5461017e906001600160a01b031681565b6040516001600160a01b03909116815260200161013a565b6101566101a43660046111e8565b610338565b6101566101b7366004611256565b610554565b6101566101ca3660046112db565b610623565b61015661063a565b60fb5461017e906001600160a01b031681565b6101566101f8366004611366565b610670565b6033546001600160a01b031661017e565b61017e61021c366004611404565b60ff602052600090815260409020546001600160a01b031681565b610256610245366004611558565b63bc197c8160e01b95945050505050565b6040516001600160e01b0319909116815260200161013a565b61015661027d366004611606565b610688565b6102566102903660046116c0565b63f23a6e6160e01b95945050505050565b6101566102af366004611404565b610891565b60fc5461017e906001600160a01b031681565b6101566102d5366004611256565b61092c565b60006001600160e01b03198216630271189760e51b148061030b57506301ffc9a760e01b6001600160e01b03198316145b92915050565b61031e8433858585610a0d565b50505050565b6103318585858585610a0d565b5050505050565b600260fe5414156103645760405162461bcd60e51b815260040161035b90611729565b60405180910390fd5b600260fe5560fd546001600160a01b03163381146103be5760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b604482015260640161035b565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104209190611760565b60fb546001600160a01b039081169116146104775760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e4818d85b1b08189e4818dbdb9d195c9c185c9d604a1b604482015260640161035b565b60405163731133e960e01b81526001600160a01b0385811660048301526024820185905260448201849052608060648301526000608483015287169063731133e99060a401600060405180830381600087803b1580156104d657600080fd5b505af11580156104ea573d6000803e3d6000fd5b5050604080516001600160a01b0388811682526020820188905291810186905281891693508982169250908a16907f5399dc7b86d085e50a28946dbc213966bb7a7ac78d312aedd6018c791ad6cef9906060015b60405180910390a45050600160fe555050505050565b600054610100900460ff1661056f5760005460ff1615610573565b303b155b6105d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161035b565b600054610100900460ff161580156105f8576000805461ffff19166101011790555b610600610c58565b61060c83600084610c87565b801561061e576000805461ff00191690555b505050565b61063286338787878787610d87565b505050505050565b6033546001600160a01b031633146106645760405162461bcd60e51b815260040161035b9061177d565b61066e6000611094565b565b61067f87878787878787610d87565b50505050505050565b600260fe5414156106ab5760405162461bcd60e51b815260040161035b90611729565b600260fe5560fd546001600160a01b03163381146107055760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e481b595cdcd95b99d95c8818d85b8818d85b1b604a1b604482015260640161035b565b806001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa158015610743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107679190611760565b60fb546001600160a01b039081169116146107be5760405162461bcd60e51b81526020600482015260176024820152761bdb9b1e4818d85b1b08189e4818dbdb9d195c9c185c9d604a1b604482015260640161035b565b604051635a455c5b60e11b81526001600160a01b0389169063b48ab8b6906107f290899089908990899089906004016117e8565b600060405180830381600087803b15801561080c57600080fd5b505af1158015610820573d6000803e3d6000fd5b50505050866001600160a01b0316886001600160a01b03168a6001600160a01b03167ff07745bfeb45fb1184165136e9148689adf57ba578a5b90dde949f26066b7756898989898960405161087995949392919061183e565b60405180910390a45050600160fe5550505050505050565b6033546001600160a01b031633146108bb5760405162461bcd60e51b815260040161035b9061177d565b6001600160a01b0381166109205760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161035b565b61092981611094565b50565b6033546001600160a01b031633146109565760405162461bcd60e51b815260040161035b9061177d565b6001600160a01b0381166109a25760405162461bcd60e51b81526020600482015260136024820152726d617020746f207a65726f206164647265737360681b604482015260640161035b565b6001600160a01b03828116600081815260ff602090815260409182902080546001600160a01b031916948616948517905581519283528201929092527fcb7d5959c6ea086e1e4326bb4745f80c494524693345a2ca0f1f1221d7cc77db910160405180910390a15050565b600260fe541415610a305760405162461bcd60e51b815260040161035b90611729565b600260fe5581610a795760405162461bcd60e51b81526020600482015260146024820152731dda5d1a191c985dc81e995c9bc8185b5bdd5b9d60621b604482015260640161035b565b6001600160a01b03808616600090815260ff60205260409020541680610ad75760405162461bcd60e51b81526020600482015260136024820152721d1bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161035b565b604051637a94c56560e11b815233600482015260248101859052604481018490526001600160a01b0387169063f5298aca90606401600060405180830381600087803b158015610b2657600080fd5b505af1158015610b3a573d6000803e3d6000fd5b5050604080516001600160a01b0385811660248301528a81166044830152336064830152898116608483015260a4820189905260c48083018990528351808403909101815260e490920183526020820180516001600160e01b031663730608b360e01b17905260fd5460fb54935163b2267a7b60e01b81529295508116935063b2267a7b92610bd492911690349086908990600401611882565b600060405180830381600087803b158015610bee57600080fd5b505af1158015610c02573d6000803e3d6000fd5b5050604080516001600160a01b038a81168252602082018a90529181018890523393508a82169250908516907f1f9dcda7fce6f73a13055f044ffecaed2032a7a844e0a37a3eb8bbb17488d01a9060600161053e565b600054610100900460ff16610c7f5760405162461bcd60e51b815260040161035b906118f6565b61066e6110e6565b6001600160a01b038316610cdd5760405162461bcd60e51b815260206004820152601860248201527f7a65726f20636f756e7465727061727420616464726573730000000000000000604482015260640161035b565b6001600160a01b038116610d2c5760405162461bcd60e51b81526020600482015260166024820152757a65726f206d657373656e676572206164647265737360501b604482015260640161035b565b60fb80546001600160a01b038086166001600160a01b03199283161790925560fd80548484169216919091179055821615610d7d5760fc80546001600160a01b0319166001600160a01b0384161790555b5050600160fe5550565b600260fe541415610daa5760405162461bcd60e51b815260040161035b90611729565b600260fe5583610df35760405162461bcd60e51b81526020600482015260146024820152736e6f20746f6b656e20746f20776974686472617760601b604482015260640161035b565b838214610e345760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b604482015260640161035b565b60005b82811015610eb0576000848483818110610e5357610e53611941565b9050602002013511610e9e5760405162461bcd60e51b81526020600482015260146024820152731dda5d1a191c985dc81e995c9bc8185b5bdd5b9d60621b604482015260640161035b565b80610ea881611957565b915050610e37565b506001600160a01b03808816600090815260ff60205260409020541680610f0f5760405162461bcd60e51b81526020600482015260136024820152721d1bdad95b881b9bdd081cdd5c1c1bdc9d1959606a1b604482015260640161035b565b604051637b75893d60e11b81526001600160a01b0389169063f6eb127a90610f439033908a908a908a908a9060040161183e565b600060405180830381600087803b158015610f5d57600080fd5b505af1158015610f71573d6000803e3d6000fd5b50505050600063f92748d360e01b828a338b8b8b8b8b604051602401610f9e989796959493929190611980565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925260fd5460fb54925163b2267a7b60e01b81529193506001600160a01b039081169263b2267a7b92349261100d921690839087908a90600401611882565b6000604051808303818588803b15801561102657600080fd5b505af115801561103a573d6000803e3d6000fd5b5050505050336001600160a01b0316896001600160a01b0316836001600160a01b03167f5d2d5d4cdbf7b115e43f0b9986644dd8b9514b10be6a019ab6a4a87f122909708b8b8b8b8b60405161087995949392919061183e565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff1661110d5760405162461bcd60e51b815260040161035b906118f6565b61066e33611094565b60006020828403121561112857600080fd5b81356001600160e01b03198116811461114057600080fd5b9392505050565b6001600160a01b038116811461092957600080fd5b6000806000806080858703121561117257600080fd5b843561117d81611147565b966020860135965060408601359560600135945092505050565b600080600080600060a086880312156111af57600080fd5b85356111ba81611147565b945060208601356111ca81611147565b94979496505050506040830135926060810135926080909101359150565b60008060008060008060c0878903121561120157600080fd5b863561120c81611147565b9550602087013561121c81611147565b9450604087013561122c81611147565b9350606087013561123c81611147565b9598949750929560808101359460a0909101359350915050565b6000806040838503121561126957600080fd5b823561127481611147565b9150602083013561128481611147565b809150509250929050565b60008083601f8401126112a157600080fd5b50813567ffffffffffffffff8111156112b957600080fd5b6020830191508360208260051b85010111156112d457600080fd5b9250929050565b600080600080600080608087890312156112f457600080fd5b86356112ff81611147565b9550602087013567ffffffffffffffff8082111561131c57600080fd5b6113288a838b0161128f565b9097509550604089013591508082111561134157600080fd5b5061134e89828a0161128f565b979a9699509497949695606090950135949350505050565b600080600080600080600060a0888a03121561138157600080fd5b873561138c81611147565b9650602088013561139c81611147565b9550604088013567ffffffffffffffff808211156113b957600080fd5b6113c58b838c0161128f565b909750955060608a01359150808211156113de57600080fd5b506113eb8a828b0161128f565b989b979a50959894979596608090950135949350505050565b60006020828403121561141657600080fd5b813561114081611147565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561146057611460611421565b604052919050565b600082601f83011261147957600080fd5b8135602067ffffffffffffffff82111561149557611495611421565b8160051b6114a4828201611437565b92835284810182019282810190878511156114be57600080fd5b83870192505b848310156114dd578235825291830191908301906114c4565b979650505050505050565b600082601f8301126114f957600080fd5b813567ffffffffffffffff81111561151357611513611421565b611526601f8201601f1916602001611437565b81815284602083860101111561153b57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561157057600080fd5b853561157b81611147565b9450602086013561158b81611147565b9350604086013567ffffffffffffffff808211156115a857600080fd5b6115b489838a01611468565b945060608801359150808211156115ca57600080fd5b6115d689838a01611468565b935060808801359150808211156115ec57600080fd5b506115f9888289016114e8565b9150509295509295909350565b60008060008060008060008060c0898b03121561162257600080fd5b883561162d81611147565b9750602089013561163d81611147565b9650604089013561164d81611147565b9550606089013561165d81611147565b9450608089013567ffffffffffffffff8082111561167a57600080fd5b6116868c838d0161128f565b909650945060a08b013591508082111561169f57600080fd5b506116ac8b828c0161128f565b999c989b5096995094979396929594505050565b600080600080600060a086880312156116d857600080fd5b85356116e381611147565b945060208601356116f381611147565b93506040860135925060608601359150608086013567ffffffffffffffff81111561171d57600080fd5b6115f9888289016114e8565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60006020828403121561177257600080fd5b815161114081611147565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b81835260006001600160fb1b038311156117cb57600080fd5b8260051b8083602087013760009401602001938452509192915050565b6001600160a01b038616815260806020820181905260009061180d90830186886117b2565b82810360408401526118208185876117b2565b83810360609094019390935250506000815260200195945050505050565b6001600160a01b038616815260606020820181905260009061186390830186886117b2565b82810360408401526118768185876117b2565b98975050505050505050565b60018060a01b038516815260006020858184015260806040840152845180608085015260005b818110156118c45786810183015185820160a0015282016118a8565b818111156118d657600060a083870101525b5060608401949094525050601f91909101601f19160160a0019392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060001982141561197957634e487b7160e01b600052601160045260246000fd5b5060010190565b6001600160a01b038981168252888116602083015287811660408301528616606082015260c0608082018190526000906119bd90830186886117b2565b82810360a08401526119d08185876117b2565b9b9a505050505050505050505056fea26469706673582212205332503f1a187cb7efe095e336d533a0f0789a5dad19022a2577ebbbc6cc9cff64736f6c634300080a003383104ec5a0ad653ff3edfa96ed61b776aa28a513086d6c6f3d092eed269ec2f87b58fbd40ba004bdccaa1102f4920d35c3cc9ef833347b73b1a51122bd7a7193d81a71f985030000103af910371201830bd4408080b90fe6608060405260405162000f6638038062000f66833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1f833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000eff83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3f6027913962000381565b9392505050565b60006200021a60008051602062000eff83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000eff83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1f83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086780620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106f1565b610118565b61005b61009336600461070c565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106f1565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b6060610285838360405180606001604052806027815260200161080b6027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f7565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051f565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055f565b60606001600160a01b0384163b6104825760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049d91906107bb565b600060405180830381855af49150503d80600081146104d8576040519150601f19603f3d011682016040523d82523d6000602084013e6104dd565b606091505b50915091506104ed828286610608565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b61052881610641565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c45760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610617575081610285565b8251156106275782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d7565b6001600160a01b0381163b6106ae5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e7565b80356001600160a01b03811681146106ec57600080fd5b919050565b60006020828403121561070357600080fd5b610285826106d5565b60008060006040848603121561072157600080fd5b61072a846106d5565b9250602084013567ffffffffffffffff8082111561074757600080fd5b818601915086601f83011261075b57600080fd5b81358181111561076a57600080fd5b87602082850101111561077c57600080fd5b6020830194508093505050509250925092565b60005b838110156107aa578181015183820152602001610792565b838111156103c05750506000910152565b600082516107cd81846020870161078f565b9190910192915050565b60208152600082518060208401526107f681604085016020870161078f565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220366737524a7ac8fa76e3b2cd04bb1e0b8aa75e165c32f59b0076ead59d529de564736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656400000000000000000000000029948f683be2702824346933a8408b515f42e232000000000000000000000000cf16a0bebb13045c91127cdf7325d6d0d1ca6e750000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000083104ec5a083f88930505c37de9dc88ac61048e628326492d3461aaaf3339e9855ac302ca0a057665cae3298318db248f754ee1acf48feef619d5db43b8eef6bbc35e149e88400000069f867130183132ce594530000000000000000000000000000000000000080848129fc1c83104ec6a0e42708ae312d832e6fec8c8f9507cfbd6078fcdf376d7f6d87d9d0037389a685a01e06416854e14b18966ebc0af5bd10b88e0f84431e40d1fdb39a24aed1c7383500000089f8871401830103e894530000000000000000000000000000000000000080a49e7adc79000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c83104ec5a04d1117fb534cbbd76b2cd80e5b1d5c3067a7fc0ae9f1ca5618b25f499a8af1b2a071fb827cc484eb9b1c7e472a7d801261807bf12ec73025227a018e60231b893600000088f8861501828d1994530000000000000000000000000000000000000580a49e7adc79000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c83104ec5a0744be6f310561603dc484353a25f15ad4996fd507158d792825f055e8fa8866da03ae0a9ec7489745ab327048e9df9263905aafc5e2e95324fa7de3d0c372d6f1700000088f886160182fe7994530000000000000000000000000000000000000180a43d0f963e000000000000000000000000530000000000000000000000000000000000000383104ec5a0fad76714d09ff2ac62dbc1212509674b958cd876fb37fde2d174f793608c9cc1a015c718cd6fb8c0952c19143b3ef4303a6fe57f588718ce9fbbeb2bae24c67ad100000089f887170183010d9294530000000000000000000000000000000000000280a43d0f963e000000000000000000000000530000000000000000000000000000000000000383104ec6a09b8049860389055b6800bdb15935ee035ebc637ab7de003f245f430c4a9f727da048d57148892a995cba441c942f55f92dc90cfca483fbda1dcf4ce7bd0690b10c000000aaf8a8180183037cf694b75d7e84517e1504c151b270255b087fd746d34c80b844485cc9550000000000000000000000005260e38080bfe97e6c4925d9209ecc5f964373b6000000000000000000000000530000000000000000000000000000000000000583104ec6a0ecef62ab2c30e1e4b925120d1fe68f64652a07d99075733ceaeb58d0dc0dd98ea029e0ec0a980a0c782e2faf7242e2ab833d58a3f17bfd21f7a23ee1dfbbec28ba00000089f88719018301380594b75d7e84517e1504c151b270255b087fd746d34c80a43d0f963e000000000000000000000000530000000000000000000000000000000000000383104ec5a063a7d16c9ddce03cb4e992765333c206f5861c05968f7bea393aa78fe497c906a06fa487ddfddf3ff8d2d57be16d1eb2a85435d2573d1216734313abef4bac9cc6000000aaf8a81a018302b8ee946d79aa2e4fbf80cf8543ad97e294861853fb064980b844485cc95500000000000000000000000032139b5c8838e94ffcd83e60dff95daa7f0ba14c000000000000000000000000b878f37bb278bf0e4974856ffe86f5e6f66bd72583104ec6a076bc8d7c7b869f5269497e554703eef89296c3ed68eafadb87cc99e0a2ccb35ba0351d991a9f9b9072c4800459f8264263bf35a8d045748ae40c5954b2cd2764bf000000caf8c81b0183037da694a07cb742657294c339fb4d5d6cdf3fdbee8c1c6880b864c0c53b8b000000000000000000000000920f906b814597cf5dc76f95100f09cbaf9c57480000000000000000000000006d79aa2e4fbf80cf8543ad97e294861853fb0649000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c83104ec5a0b91b8de785cff8699317ab0460938fb4396a39fd691116f99115836f1e762b75a0739211531492f4d50fdd0b7503ce891567524154b2d36917b93f646d06dce4a3000000aaf8a81c018303308c94fe5fc32777646bd123564c41f711ff708dd4836080b844485cc955000000000000000000000000d1be599aacbc21448fd6373bbc7c1b4c7806f135000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c83104ec6a014e5991eba47411be428e631f3db3be811639f1decd60172e53577359fd0ef26a03eba8a4d176114356f52b7492af4b901d97260b830ac69be54d619b84816beaa000000aaf8a81d018303030e948fee20e0c0ef16f2898a8073531a857d11b9c70080b844485cc9550000000000000000000000001c441dfc5c2ed7a2aa8636748a664e59cb029157000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c83104ec6a08e29df024a2d4f2669e07c818c75cfaf4eb1d557ab27d8164274100be5eaa192a027e5bdfb23c6825e87a88cdd0a27ac774f84d2016c647ef520c20424f983a20e000000caf8c81e01830285849432139b5c8838e94ffcd83e60dff95daa7f0ba14c80b864c0c53b8b000000000000000000000000429b73a21cf3bf1f3e696a21a95408161daf311f0000000000000000000000006d79aa2e4fbf80cf8543ad97e294861853fb0649000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c83104ec5a01a949aadc5ea461b7b135d694822603b6aa3fa869f0dbaa039dda394077eb2eea030be8135bfa5db7640d26ed995e91bcb46498ce586a6ee4341e7df0a07825394000000eaf8e81f0183032d6d94b878f37bb278bf0e4974856ffe86f5e6f66bd72580b884f8c8765e000000000000000000000000ef37207c1a1eff6d6a9d7bff3cf4270e406d319b0000000000000000000000006d79aa2e4fbf80cf8543ad97e294861853fb0649000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c0000000000000000000000004c79382bd84a1906de73ee9678f43f59724ad8b583104ec6a096d427d3fb4518275c74bb658210c674463c8ffcc675269d6c62c392be9609c3a029019768a3de66084252a542683dfbac22ae40b00b2db68bd2719465646e0dd7000000caf8c82001830285c194bb88bf582f2bba46702621dae5cb9271057bc85b80b864c0c53b8b0000000000000000000000008be69e499d8848dffb4cf9bac909f3e2cf2fefa00000000000000000000000006d79aa2e4fbf80cf8543ad97e294861853fb0649000000000000000000000000b75d7e84517e1504c151b270255b087fd746d34c83104ec6a082c6b4f496d315f642db905f2b05b8e2153d74248f631018ef41880abd79d431a00aa54aa317f4f39b46665b1a9a5cb641ec55e2dcdb4dd0dd61c82f4216747b5200000088f8862101829a77944c79382bd84a1906de73ee9678f43f59724ad8b580a4f2fde38b000000000000000000000000b878f37bb278bf0e4974856ffe86f5e6f66bd72583104ec6a0669d34b395e796feb08e7f2669805a132a7d168c5097121d2350b2357623633fa04231c536294ba7f2e6d2cb3d04d01c387c1132743dd44db6715bf2a8ca28e9cf000001acf901a922018302fc7a94530000000000000000000000000000000000000380b9014479586dd7000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007000000000000000000000000d69c917c7f1c0a724a51c189b4a8f4f8c8e8ca0a00000000000000000000000077fccf9536b810a11771a70128d3c9cd32e8a21c00000000000000000000000056eaba08988960856e229af0dcd1924c48259457000000000000000000000000c7bd1b9e89e24c9783900679dc91f7e9dca25539000000000000000000000000831a53b05bc02b11038307996564753d8366cc9300000000000000000000000089e31727c42646b88d5f2d576bc2859434e011440000000000000000000000004075a6bcad6c3c5b941c2482fda716a56608106b83104ec6a0fe9f58afa5ec697c105e6fe4aa067f583149e7fb89bb2f48d9ac3cf82faecb68a06239cf14912f5b9a6d6922d5488d19a98c5ba7054884f2f8c8facb29cf60978a00000088f886230182b6cb94530000000000000000000000000000000000000280a43577afc500000000000000000000000000000000000000000000000000000000000017d483104ec6a0184f3a4fd266cce02fe6f153c9bab53d9084134b83fea7fc2380e41b46123944a0765e99abce926cdd0664b63c3ad05dc41198c840dee3bd9fb849a3924bc219b500000088f886240182b79f94530000000000000000000000000000000000000280a470465597000000000000000000000000000000000000000000000000000000004a42fc8083104ec5a0ae8625cfa555adf68f7e5d17cb42846d8122be76f5db28af8edcf6eae38a5a1da0068847d119ad6f7432e0ede9588ed2e6a07f9f2a476f2cd314844b241955d91d0000006cf86a250182520894d69c917c7f1c0a724a51c189b4a8f4f8c8e8ca0a8814d1120d7b1600008083104ec5a0a1013fe1d8f464021cc42b417e5afca54d62a7329ce2889f8bc848813f280f14a00ce51b91d1723ffbfca34ca9bccd91e8308747a8d0eb41d3583560d5e63a655b0000006cf86a26018252089477fccf9536b810a11771a70128d3c9cd32e8a21c8814d1120d7b1600008083104ec6a074414edde9a3b2d3c3b74732f008fec72e43595a166dc82f908e3add20acd82ba057d40600c8388ca17e29dc7cd029fc4ed6a54b4eba3ffdb696238ae0cfd7c93f0000006cf86a27018252089456eaba08988960856e229af0dcd1924c482594578814d1120d7b1600008083104ec6a0c97205749bd4e839f371b809d54daa95c41352f43966a9d29785d146f9ec2d31a03807fab8d9e0653b571ec89df9691bede60e84513524922d46acacce3e81a9630000006cf86a280182520894c7bd1b9e89e24c9783900679dc91f7e9dca255398814d1120d7b1600008083104ec6a0674a0b7ce8a55e2f4d9b69dba6c8de4963dcd635e356b206ecbd223ed52ed040a0684e307cdba4afa38fecfda771dab4ebb07befadcc7822620153e2f4fe24739e000000000000000000000000000000000000000000000000000000000000000000000000e020b46cbd5ef0ce4f1cae852ab16d07da35553daccce248320b996d602453adac0c7dacdd1a024e662983999fb69a4fe2b65d58382af42655a5b51eafa1e7f84500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004abe34931e037f8fcbb756ab34ef73afb8373b7cc5b31a8eedca750cf534199e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000001c51b90d3dcbf89b5d9def03a02660780bc99a60bb21a9fb323ea7111b8e923d49ef696aa281d59deca384d813ba416325e8c0e7d30cdbda968e8972a98a3822000000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000063f87554000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700000006cf86a290182520894831a53b05bc02b11038307996564753d8366cc938814d1120d7b1600008083104ec6a0fc6288e0210c6fecc4f729d9571be16af518385f043f57f398cd4ee5c268adf6a00e0546c06491bb15f36a0494881ae2df151e9cbcfd250df3fc99b4bff847e2920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00c7dacdd1a024e662983999fb69a4fe2b65d58382af42655a5b51eafa1e7f845144a76f790609800dfb6cd76ab2d45a4c323290d6ffcfaa2b9ca1d2405ad7b4c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000531a81b5e39eac3c048c1925583c11c24e1b0873292d9cf77a0519eb092ccfa840000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000109a333d7a3018ac688a4ea5001137b718bf8cdf7f5fcee8da945a08acb630b81c51b90d3dcbf89b5d9def03a02660780bc99a60bb21a9fb323ea7111b8e923d400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000063f8755d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a12000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700000006cf86a2a018252089489e31727c42646b88d5f2d576bc2859434e011448814d1120d7b1600008083104ec5a094df3812e93780dc419edbbd19fe3284a768971525dec61e16514f001a8c4e41a07af73b29aec9c3fca97333aa6a69b44bf5766945b362476034d7198f067d7a4300000000000000000000000000000000 \ No newline at end of file diff --git a/bridge-history-api/utils/parse_event.go b/bridge-history-api/utils/parse_event.go deleted file mode 100644 index 08b518932d..0000000000 --- a/bridge-history-api/utils/parse_event.go +++ /dev/null @@ -1,383 +0,0 @@ -package utils - -import ( - "context" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/log" - - backendabi "bridge-history-api/abi" - "bridge-history-api/orm" -) - -// ParseBackendL1EventLogs parses L1 watched events -func ParseBackendL1EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedMsg, error) { - // Need use contract abi to parse event Log - // Can only be tested after we have our contracts set up - - var l1CrossMsg []*orm.CrossMsg - var relayedMsgs []*orm.RelayedMsg - var msgHash string - for _, vlog := range logs { - switch vlog.Topics[0] { - case backendabi.L1DepositETHSig: - event := backendabi.DepositETH{} - err := UnpackLog(backendabi.L1ETHGatewayABI, &event, "DepositETH", vlog) - if err != nil { - log.Warn("Failed to unpack DepositETH event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Amount: event.Amount.String(), - Asset: int(orm.ETH), - Layer1Hash: vlog.TxHash.Hex(), - MsgType: int(orm.Layer1Msg), - MsgHash: msgHash, - }) - case backendabi.L1DepositERC20Sig: - event := backendabi.ERC20MessageEvent{} - err := UnpackLog(backendabi.L1StandardERC20GatewayABI, &event, "DepositERC20", vlog) - if err != nil { - log.Warn("Failed to unpack DepositERC20 event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Amount: event.Amount.String(), - Asset: int(orm.ERC20), - Layer1Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - MsgType: int(orm.Layer1Msg), - MsgHash: msgHash, - }) - case backendabi.L1DepositERC721Sig: - event := backendabi.ERC721MessageEvent{} - err := UnpackLog(backendabi.L1ERC721GatewayABI, &event, "DepositERC721", vlog) - if err != nil { - log.Warn("Failed to unpack DepositERC721 event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC721), - Layer1Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - TokenIDs: event.TokenID.String(), - MsgType: int(orm.Layer1Msg), - MsgHash: msgHash, - }) - case backendabi.L1DepositERC1155Sig: - event := backendabi.ERC1155MessageEvent{} - err := UnpackLog(backendabi.L1ERC1155GatewayABI, &event, "DepositERC1155", vlog) - if err != nil { - log.Warn("Failed to unpack DepositERC1155 event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC1155), - Layer1Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - TokenIDs: event.TokenID.String(), - Amount: event.Amount.String(), - MsgType: int(orm.Layer1Msg), - MsgHash: msgHash, - }) - case backendabi.L1SentMessageEventSignature: - event := backendabi.L1SentMessageEvent{} - err := UnpackLog(backendabi.L1ScrollMessengerABI, &event, "SentMessage", vlog) - if err != nil { - log.Warn("Failed to unpack SentMessage event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - // since every deposit event will emit after a sent event, so can use this msg_hash as next withdraw event's msg_hash - msgHash = ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message).Hex() - case backendabi.L1BatchDepositERC721Sig: - event := backendabi.BatchERC721MessageEvent{} - err := UnpackLog(backendabi.L1ERC721GatewayABI, &event, "BatchDepositERC721", vlog) - if err != nil { - log.Warn("Failed to unpack BatchDepositERC721 event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC721), - Layer1Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - TokenIDs: convertBigIntArrayToString(event.TokenIDs), - MsgType: int(orm.Layer1Msg), - MsgHash: msgHash, - }) - case backendabi.L1BatchDepositERC1155Sig: - event := backendabi.BatchERC1155MessageEvent{} - err := UnpackLog(backendabi.L1ERC1155GatewayABI, &event, "BatchDepositERC1155", vlog) - if err != nil { - log.Warn("Failed to unpack BatchDepositERC1155 event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC1155), - Layer1Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - TokenIDs: convertBigIntArrayToString(event.TokenIDs), - TokenAmounts: convertBigIntArrayToString(event.TokenAmounts), - MsgType: int(orm.Layer1Msg), - MsgHash: msgHash, - }) - case backendabi.L1RelayedMessageEventSignature: - event := backendabi.L1RelayedMessageEvent{} - err := UnpackLog(backendabi.L1ScrollMessengerABI, &event, "RelayedMessage", vlog) - if err != nil { - log.Warn("Failed to unpack RelayedMessage event", "err", err) - return l1CrossMsg, relayedMsgs, err - } - relayedMsgs = append(relayedMsgs, &orm.RelayedMsg{ - MsgHash: event.MessageHash.String(), - Height: vlog.BlockNumber, - Layer1Hash: vlog.TxHash.Hex(), - }) - - } - - } - return l1CrossMsg, relayedMsgs, nil -} - -// ParseBackendL2EventLogs parses L2 watched events -func ParseBackendL2EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedMsg, []*orm.L2SentMsg, error) { - // Need use contract abi to parse event Log - // Can only be tested after we have our contracts set up - - var l2CrossMsg []*orm.CrossMsg - // this is use to confirm finalized l1 msg - var relayedMsgs []*orm.RelayedMsg - var l2SentMsgs []*orm.L2SentMsg - for _, vlog := range logs { - switch vlog.Topics[0] { - case backendabi.L2WithdrawETHSig: - event := backendabi.DepositETH{} - err := UnpackLog(backendabi.L2ETHGatewayABI, &event, "WithdrawETH", vlog) - if err != nil { - log.Warn("Failed to unpack WithdrawETH event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex() - l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Amount: event.Amount.String(), - Asset: int(orm.ETH), - Layer2Hash: vlog.TxHash.Hex(), - MsgType: int(orm.Layer2Msg), - MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash, - }) - case backendabi.L2WithdrawERC20Sig: - event := backendabi.ERC20MessageEvent{} - err := UnpackLog(backendabi.L2StandardERC20GatewayABI, &event, "WithdrawERC20", vlog) - if err != nil { - log.Warn("Failed to unpack WithdrawERC20 event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex() - l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Amount: event.Amount.String(), - Asset: int(orm.ERC20), - Layer2Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - MsgType: int(orm.Layer2Msg), - MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash, - }) - case backendabi.L2WithdrawERC721Sig: - event := backendabi.ERC721MessageEvent{} - err := UnpackLog(backendabi.L2ERC721GatewayABI, &event, "WithdrawERC721", vlog) - if err != nil { - log.Warn("Failed to unpack WithdrawERC721 event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex() - l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC721), - Layer2Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - TokenIDs: event.TokenID.String(), - MsgType: int(orm.Layer2Msg), - MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash, - }) - case backendabi.L2WithdrawERC1155Sig: - event := backendabi.ERC1155MessageEvent{} - err := UnpackLog(backendabi.L2ERC1155GatewayABI, &event, "WithdrawERC1155", vlog) - if err != nil { - log.Warn("Failed to unpack WithdrawERC1155 event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex() - l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC1155), - Layer2Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - TokenIDs: event.TokenID.String(), - Amount: event.Amount.String(), - MsgType: int(orm.Layer2Msg), - MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash, - }) - case backendabi.L2BatchWithdrawERC721Sig: - event := backendabi.BatchERC721MessageEvent{} - err := UnpackLog(backendabi.L2ERC721GatewayABI, &event, "BatchWithdrawERC721", vlog) - if err != nil { - log.Warn("Failed to unpack BatchWithdrawERC721 event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex() - l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC721), - Layer1Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - MsgType: int(orm.Layer2Msg), - TokenIDs: convertBigIntArrayToString(event.TokenIDs), - MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash, - }) - case backendabi.L2BatchWithdrawERC1155Sig: - event := backendabi.BatchERC1155MessageEvent{} - err := UnpackLog(backendabi.L2ERC1155GatewayABI, &event, "BatchWithdrawERC1155", vlog) - if err != nil { - log.Warn("Failed to unpack BatchWithdrawERC1155 event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex() - l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{ - Height: vlog.BlockNumber, - Sender: event.From.String(), - Target: event.To.String(), - Asset: int(orm.ERC1155), - Layer1Hash: vlog.TxHash.Hex(), - Layer1Token: event.L1Token.Hex(), - Layer2Token: event.L2Token.Hex(), - MsgType: int(orm.Layer2Msg), - TokenIDs: convertBigIntArrayToString(event.TokenIDs), - TokenAmounts: convertBigIntArrayToString(event.TokenAmounts), - MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash, - }) - case backendabi.L2SentMessageEventSignature: - event := backendabi.L2SentMessageEvent{} - err := UnpackLog(backendabi.L2ScrollMessengerABI, &event, "SentMessage", vlog) - if err != nil { - log.Warn("Failed to unpack SentMessage event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - // since every withdraw event will emit after a sent event, so can use this msg_hash as next withdraw event's msg_hash - msgHash := ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message) - l2SentMsgs = append(l2SentMsgs, - &orm.L2SentMsg{ - Sender: event.Sender.Hex(), - TxHash: vlog.TxHash.Hex(), - Target: event.Target.Hex(), - Value: event.Value.String(), - MsgHash: msgHash.Hex(), - Height: vlog.BlockNumber, - Nonce: event.MessageNonce.Uint64(), - MsgData: hexutil.Encode(event.Message), - }) - case backendabi.L2RelayedMessageEventSignature: - event := backendabi.L2RelayedMessageEvent{} - err := UnpackLog(backendabi.L2ScrollMessengerABI, &event, "RelayedMessage", vlog) - if err != nil { - log.Warn("Failed to unpack RelayedMessage event", "err", err) - return l2CrossMsg, relayedMsgs, l2SentMsgs, err - } - relayedMsgs = append(relayedMsgs, &orm.RelayedMsg{ - MsgHash: event.MessageHash.String(), - Height: vlog.BlockNumber, - Layer2Hash: vlog.TxHash.Hex(), - }) - - } - } - return l2CrossMsg, relayedMsgs, l2SentMsgs, nil -} - -// ParseBatchInfoFromScrollChain parses ScrollChain events -func ParseBatchInfoFromScrollChain(ctx context.Context, client *ethclient.Client, logs []types.Log) ([]*orm.RollupBatch, error) { - var rollupBatches []*orm.RollupBatch - for _, vlog := range logs { - switch vlog.Topics[0] { - case backendabi.L1CommitBatchEventSignature: - event := backendabi.L1CommitBatchEvent{} - err := UnpackLog(backendabi.ScrollChainABI, &event, "CommitBatch", vlog) - if err != nil { - log.Warn("Failed to unpack CommitBatch event", "err", err) - return rollupBatches, err - } - commitTx, isPending, err := client.TransactionByHash(ctx, vlog.TxHash) - if err != nil || isPending { - log.Warn("Failed to get commit Batch tx receipt or the tx is still pending", "err", err) - return rollupBatches, err - } - index, startBlock, endBlock, err := GetBatchRangeFromCalldataV2(commitTx.Data()) - if err != nil { - log.Warn("Failed to get batch range from calldata", "hash", commitTx.Hash().Hex(), "height", vlog.BlockNumber) - return rollupBatches, err - } - rollupBatches = append(rollupBatches, &orm.RollupBatch{ - CommitHeight: vlog.BlockNumber, - BatchIndex: index, - BatchHash: event.BatchHash.Hex(), - StartBlockNumber: startBlock, - EndBlockNumber: endBlock, - }) - - default: - continue - } - } - return rollupBatches, nil -} - -func convertBigIntArrayToString(array []*big.Int) string { - stringArray := make([]string, len(array)) - for i, num := range array { - stringArray[i] = num.String() - } - - result := strings.Join(stringArray, ", ") - return result -} diff --git a/bridge-history-api/utils/utils.go b/bridge-history-api/utils/utils.go index 1e4674ff06..6b5a3a864e 100644 --- a/bridge-history-api/utils/utils.go +++ b/bridge-history-api/utils/utils.go @@ -21,8 +21,8 @@ func Keccak2(a common.Hash, b common.Hash) common.Hash { return common.BytesToHash(crypto.Keccak256(append(a.Bytes()[:], b.Bytes()[:]...))) } -// GetSafeBlockNumber get the safe block number, which is the current block number minus the confirmations -func GetSafeBlockNumber(ctx context.Context, client *ethclient.Client, confirmations uint64) (uint64, error) { +// GetBlockNumber get the current block number minus the confirmations +func GetBlockNumber(ctx context.Context, client *ethclient.Client, confirmations uint64) (uint64, error) { number, err := client.BlockNumber(ctx) if err != nil || number <= confirmations { return 0, err @@ -59,7 +59,7 @@ func ComputeMessageHash( messageNonce *big.Int, message []byte, ) common.Hash { - data, _ := backendabi.L2ScrollMessengerABI.Pack("relayMessage", sender, target, value, messageNonce, message) + data, _ := backendabi.IL2ScrollMessengerABI.Pack("relayMessage", sender, target, value, messageNonce, message) return common.BytesToHash(crypto.Keccak256(data)) } @@ -70,13 +70,13 @@ type commitBatchArgs struct { SkippedL1MessageBitmap []byte } -// GetBatchRangeFromCalldataV2 find the block range from calldata, both inclusive. -func GetBatchRangeFromCalldataV2(calldata []byte) (uint64, uint64, uint64, error) { - method := backendabi.ScrollChainV2ABI.Methods["commitBatch"] +// GetBatchRangeFromCalldata find the block range from calldata, both inclusive. +func GetBatchRangeFromCalldata(calldata []byte) (uint64, uint64, uint64, error) { + method := backendabi.IScrollChainABI.Methods["commitBatch"] values, err := method.Inputs.Unpack(calldata[4:]) if err != nil { // special case: import genesis batch - method = backendabi.ScrollChainV2ABI.Methods["importGenesisBatch"] + method = backendabi.IScrollChainABI.Methods["importGenesisBatch"] _, err2 := method.Inputs.Unpack(calldata[4:]) if err2 == nil { // genesis batch diff --git a/bridge-history-api/utils/utils_test.go b/bridge-history-api/utils/utils_test.go index d457a87864..8518a5e9e6 100644 --- a/bridge-history-api/utils/utils_test.go +++ b/bridge-history-api/utils/utils_test.go @@ -19,23 +19,23 @@ func TestKeccak2(t *testing.T) { assert.Equal(t, "0xc0ffbd7f501bd3d49721b0724b2bff657cb2378f15d5a9b97cd7ea5bf630d512", c.Hex()) } -func TestGetBatchRangeFromCalldataV2(t *testing.T) { +func TestGetBatchRangeFromCalldata(t *testing.T) { // single chunk - batchIndex, start, finish, err := utils.GetBatchRangeFromCalldataV2(common.Hex2Bytes("1325aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003d0100000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000")) + batchIndex, start, finish, err := utils.GetBatchRangeFromCalldata(common.Hex2Bytes("1325aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003d0100000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000")) assert.NoError(t, err) assert.Equal(t, start, uint64(1)) assert.Equal(t, finish, uint64(1)) assert.Equal(t, batchIndex, uint64(1)) // multiple chunk - batchIndex, start, finish, err = utils.GetBatchRangeFromCalldataV2(common.Hex2Bytes("1325aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000007900000000000000000100000000000000010000000000000001038433daac85a0b03cd443ed50bc85e832c883061651ae2182b2984751e0b340119b828c2a2798d2c957228ebeaff7e10bb099ae0d4e224f3eeb779ff61cba610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004c01000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000010000000001000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b403000000000000000b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000300000000000000000b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00050000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c01000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa800000000000000000000000000000000000000000000000000000000000000aa")) + batchIndex, start, finish, err = utils.GetBatchRangeFromCalldata(common.Hex2Bytes("1325aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000007900000000000000000100000000000000010000000000000001038433daac85a0b03cd443ed50bc85e832c883061651ae2182b2984751e0b340119b828c2a2798d2c957228ebeaff7e10bb099ae0d4e224f3eeb779ff61cba610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004c01000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000010000000001000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b403000000000000000b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000300000000000000000b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00050000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c01000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000100000000010000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa800000000000000000000000000000000000000000000000000000000000000aa")) assert.NoError(t, err) assert.Equal(t, start, uint64(10)) assert.Equal(t, finish, uint64(20)) assert.Equal(t, batchIndex, uint64(2)) // genesis batch - batchIndex, start, finish, err = utils.GetBatchRangeFromCalldataV2(common.Hex2Bytes("3fdeecb200000000000000000000000000000000000000000000000000000000000000402dcb5308098d24a37fc1487a229fcedb09fa4343ede39cbad365bc925535bb09000000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000c252bc9780c4d83cf11f14b8cd03c92c4d18ce07710ba836d31d12da216c8330000000000000000000000000000000000000000000000000000000000000000000000000000000")) + batchIndex, start, finish, err = utils.GetBatchRangeFromCalldata(common.Hex2Bytes("3fdeecb200000000000000000000000000000000000000000000000000000000000000402dcb5308098d24a37fc1487a229fcedb09fa4343ede39cbad365bc925535bb09000000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000c252bc9780c4d83cf11f14b8cd03c92c4d18ce07710ba836d31d12da216c8330000000000000000000000000000000000000000000000000000000000000000000000000000000")) assert.NoError(t, err) assert.Equal(t, start, uint64(0)) assert.Equal(t, finish, uint64(0))