diff --git a/abis/ArbitrumBridgeInbox.json b/abis/ArbitrumBridgeInbox.json new file mode 100644 index 0000000..e0e0cf4 --- /dev/null +++ b/abis/ArbitrumBridgeInbox.json @@ -0,0 +1,492 @@ +[ + { + "inputs": [ + { "internalType": "uint256", "name": "dataLength", "type": "uint256" }, + { "internalType": "uint256", "name": "maxDataLength", "type": "uint256" } + ], + "name": "DataTooLarge", + "type": "error" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "expected", "type": "uint256" }, + { "internalType": "uint256", "name": "actual", "type": "uint256" } + ], + "name": "InsufficientSubmissionCost", + "type": "error" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "expected", "type": "uint256" }, + { "internalType": "uint256", "name": "actual", "type": "uint256" } + ], + "name": "InsufficientValue", + "type": "error" + }, + { "inputs": [], "name": "L1Forked", "type": "error" }, + { + "inputs": [ + { "internalType": "address", "name": "origin", "type": "address" } + ], + "name": "NotAllowedOrigin", + "type": "error" + }, + { "inputs": [], "name": "NotForked", "type": "error" }, + { "inputs": [], "name": "NotOrigin", "type": "error" }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "NotOwner", + "type": "error" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "rollup", "type": "address" }, + { "internalType": "address", "name": "owner", "type": "address" } + ], + "name": "NotRollupOrOwner", + "type": "error" + }, + { + "inputs": [ + { "internalType": "address", "name": "from", "type": "address" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "l2CallValue", "type": "uint256" }, + { "internalType": "uint256", "name": "deposit", "type": "uint256" }, + { + "internalType": "uint256", + "name": "maxSubmissionCost", + "type": "uint256" + }, + { + "internalType": "address", + "name": "excessFeeRefundAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "callValueRefundAddress", + "type": "address" + }, + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "RetryableData", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "val", + "type": "bool" + } + ], + "name": "AllowListAddressSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "isEnabled", + "type": "bool" + } + ], + "name": "AllowListEnabledUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "messageNum", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "InboxMessageDelivered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "messageNum", + "type": "uint256" + } + ], + "name": "InboxMessageDeliveredFromOrigin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "allowListEnabled", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bridge", + "outputs": [ + { "internalType": "contract IBridge", "name": "", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "dataLength", "type": "uint256" }, + { "internalType": "uint256", "name": "baseFee", "type": "uint256" } + ], + "name": "calculateRetryableSubmissionFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "l2CallValue", "type": "uint256" }, + { + "internalType": "uint256", + "name": "maxSubmissionCost", + "type": "uint256" + }, + { + "internalType": "address", + "name": "excessFeeRefundAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "callValueRefundAddress", + "type": "address" + }, + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "createRetryableTicket", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "l2CallValue", "type": "uint256" }, + { + "internalType": "uint256", + "name": "maxSubmissionCost", + "type": "uint256" + }, + { + "internalType": "address", + "name": "excessFeeRefundAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "callValueRefundAddress", + "type": "address" + }, + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "createRetryableTicketNoRefundAliasRewrite", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "depositEth", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "depositEth", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IBridge", + "name": "_bridge", + "type": "address" + }, + { + "internalType": "contract ISequencerInbox", + "name": "_sequencerInbox", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "isAllowed", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "contract IBridge", "name": "", "type": "address" } + ], + "name": "postUpgradeInit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "value", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "sendContractTransaction", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "sendL1FundedContractTransaction", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "sendL1FundedUnsignedTransaction", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "sendL1FundedUnsignedTransactionToFork", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes", "name": "messageData", "type": "bytes" } + ], + "name": "sendL2Message", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bytes", "name": "messageData", "type": "bytes" } + ], + "name": "sendL2MessageFromOrigin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "value", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "sendUnsignedTransaction", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "value", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "sendUnsignedTransactionToFork", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "uint256", "name": "nonce", "type": "uint256" }, + { "internalType": "uint256", "name": "value", "type": "uint256" }, + { "internalType": "address", "name": "withdrawTo", "type": "address" } + ], + "name": "sendWithdrawEthToFork", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sequencerInbox", + "outputs": [ + { + "internalType": "contract ISequencerInbox", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address[]", "name": "user", "type": "address[]" }, + { "internalType": "bool[]", "name": "val", "type": "bool[]" } + ], + "name": "setAllowList", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "bool", "name": "_allowListEnabled", "type": "bool" } + ], + "name": "setAllowListEnabled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to", "type": "address" }, + { "internalType": "uint256", "name": "l2CallValue", "type": "uint256" }, + { + "internalType": "uint256", + "name": "maxSubmissionCost", + "type": "uint256" + }, + { + "internalType": "address", + "name": "excessFeeRefundAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "callValueRefundAddress", + "type": "address" + }, + { "internalType": "uint256", "name": "gasLimit", "type": "uint256" }, + { "internalType": "uint256", "name": "maxFeePerGas", "type": "uint256" }, + { "internalType": "bytes", "name": "data", "type": "bytes" } + ], + "name": "unsafeCreateRetryableTicket", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + } +] diff --git a/abis/ArbitrumL2BridgeRouter.json b/abis/ArbitrumL2BridgeRouter.json new file mode 100644 index 0000000..5ee18ee --- /dev/null +++ b/abis/ArbitrumL2BridgeRouter.json @@ -0,0 +1,362 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newDefaultGateway", + "type": "address" + } + ], + "name": "DefaultGatewayUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "l1Token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "gateway", + "type": "address" + } + ], + "name": "GatewaySet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_userFrom", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_userTo", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "gateway", + "type": "address" + } + ], + "name": "TransferRouted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "_seqNum", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "TxToL2", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newSource", + "type": "address" + } + ], + "name": "WhitelistSourceUpdated", + "type": "event" + }, + { + "inputs": [ + { "internalType": "address", "name": "l1ERC20", "type": "address" } + ], + "name": "calculateL2TokenAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "counterpartGateway", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultGateway", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "bytes", "name": "", "type": "bytes" } + ], + "name": "finalizeInboundTransfer", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_token", "type": "address" } + ], + "name": "getGateway", + "outputs": [ + { "internalType": "address", "name": "gateway", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_token", "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": "getOutboundCalldata", + "outputs": [{ "internalType": "bytes", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "inbox", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_owner", "type": "address" }, + { + "internalType": "address", + "name": "_defaultGateway", + "type": "address" + }, + { "internalType": "address", "name": "", "type": "address" }, + { + "internalType": "address", + "name": "_counterpartGateway", + "type": "address" + }, + { "internalType": "address", "name": "_inbox", "type": "address" } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "l1TokenToGateway", + "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": "_amount", "type": "uint256" }, + { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, + { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, + { "internalType": "bytes", "name": "_data", "type": "bytes" } + ], + "name": "outboundTransfer", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_token", "type": "address" }, + { "internalType": "address", "name": "_refundTo", "type": "address" }, + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" }, + { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, + { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, + { "internalType": "bytes", "name": "_data", "type": "bytes" } + ], + "name": "outboundTransferCustomRefund", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "postUpgradeInit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "router", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newL1DefaultGateway", + "type": "address" + }, + { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, + { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, + { + "internalType": "uint256", + "name": "_maxSubmissionCost", + "type": "uint256" + } + ], + "name": "setDefaultGateway", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_gateway", "type": "address" }, + { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, + { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, + { + "internalType": "uint256", + "name": "_maxSubmissionCost", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_creditBackAddress", + "type": "address" + } + ], + "name": "setGateway", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_gateway", "type": "address" }, + { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, + { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, + { + "internalType": "uint256", + "name": "_maxSubmissionCost", + "type": "uint256" + } + ], + "name": "setGateway", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address[]", "name": "_token", "type": "address[]" }, + { "internalType": "address[]", "name": "_gateway", "type": "address[]" }, + { "internalType": "uint256", "name": "_maxGas", "type": "uint256" }, + { "internalType": "uint256", "name": "_gasPriceBid", "type": "uint256" }, + { + "internalType": "uint256", + "name": "_maxSubmissionCost", + "type": "uint256" + } + ], + "name": "setGateways", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "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": "newSource", "type": "address" } + ], + "name": "updateWhitelistSource", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "whitelist", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + } +] diff --git a/helpers.py b/helpers.py index 2f69dbb..9f629c9 100644 --- a/helpers.py +++ b/helpers.py @@ -1,6 +1,7 @@ +import json from webbrowser import get + from brownie.network.state import Chain -import json CHAIN_IDS = { "MAINNET": 1, @@ -9,7 +10,7 @@ "HARDHAT": 31337, "ARBITRUM": 42161, "EVMOS": 9001, - "KAVA": 2222 + "KAVA": 2222, } DEPLOYER_ADDRESS = "0x5bdb37d0ddea3a90f233c7b7f6b9394b6b2eef34" @@ -63,6 +64,11 @@ CHAIN_IDS["MAINNET"]: "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef", } +ARBITRUM_BRIDGE_INBOX = { + CHAIN_IDS["MAINNET"]: "0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", +} + + EVMOS_NOMAD_ERC20_BRIDGE_ROUTER = { CHAIN_IDS["MAINNET"]: "0x88A69B4E698A4B090DF6CF5Bd7B2D47325Ad30A3", } @@ -161,3 +167,5 @@ def intersection(lst1, lst2): POOL_REGISTRY_ABI = get_abi("PoolRegistry") MINICHEF_ABI = get_abi("MiniChefV2") SWAP_FLASH_LOAN_ABI = get_abi("SwapFlashLoan") +ARBITRUM_BRIDGE_INBOX_ABI = get_abi("ArbitrumBridgeInbox") +ARBITRUM_BRIDGE_ROUTER_ABI = get_abi("ArbitrumL2BridgeRouter") diff --git a/scripts/2022_10_04_send_500k_SDL_to_arb_minichef.py b/scripts/2022_10_04_send_500k_SDL_to_arb_minichef.py new file mode 100644 index 0000000..3fca997 --- /dev/null +++ b/scripts/2022_10_04_send_500k_SDL_to_arb_minichef.py @@ -0,0 +1,43 @@ +import math + +from ape_safe import ApeSafe +from brownie import accounts, network +from helpers import ( + CHAIN_IDS, + MINICHEF_ADDRESSES, + MULTISIG_ADDRESSES, + OPTIMISM_STANDARD_BRIDGE, + SDL_ADDRESSES, +) + +from scripts.utils import bridge_to_arbitrum_minichef, bridge_to_optimism + +TARGET_NETWORK = "MAINNET" + + +def main(): + """Sends 500k of SDL to Arbitrum & Optimism minichef""" + + print(f"You are using the '{network.show_active()}' network") + + multisig = ApeSafe(MULTISIG_ADDRESSES[CHAIN_IDS[TARGET_NETWORK]]) + deployer = accounts.load("deployer") # prompts for password + + sdl = multisig.contract(SDL_ADDRESSES[CHAIN_IDS[TARGET_NETWORK]]) + + # 500k SDL + amount_to_send = 500_000 * 1e18 + + starting_balance = sdl.balanceOf(deployer.address) + assert starting_balance >= amount_to_send + + # Send to Arbitrum minichef + bridge_to_arbitrum_minichef( + multisig, + sdl.address, + amount_to_send, + ) + + assert ( + sdl.balanceOf(deployer.address) == starting_balance - amount_to_send + ), "SDL was not sent to arbitrum" diff --git a/scripts/utils.py b/scripts/utils.py index 64f79ff..b0674e0 100644 --- a/scripts/utils.py +++ b/scripts/utils.py @@ -3,11 +3,22 @@ from urllib.error import URLError import click +import eth_abi from ape_safe import ApeSafe -from brownie import network +from brownie import Contract, chain, network from gnosis.safe.safe_tx import SafeTx -from helpers import (ARB_BRIDGE_INBOX, ARB_GATEWAY_ROUTER, CHAIN_IDS, - MULTISIG_ADDRESSES) +from helpers import ( + ARBITRUM_BRIDGE_INBOX, + ARBITRUM_BRIDGE_INBOX_ABI, + ARBITRUM_BRIDGE_ROUTER_ABI, + ARBITRUM_L2_BRIDGE_ROUTER, + CHAIN_IDS, + DEPLOYER_ADDRESS, + MINICHEF_ADDRESSES, + MULTISIG_ADDRESSES, + OPTIMISM_STANDARD_BRIDGE, + SDL_ADDRESSES, +) from pytest import console_main @@ -16,8 +27,7 @@ def confirm_posting_transaction(safe: ApeSafe, safe_tx: SafeTx): current_nonce = 0 try: - url = safe.base_url + \ - f"/api/v1/safes/{safe.address}/multisig-transactions/" + url = safe.base_url + f"/api/v1/safes/{safe.address}/multisig-transactions/" # fetch list of txs from gnosis api response = urllib.request.urlopen(url) @@ -29,10 +39,8 @@ def confirm_posting_transaction(safe: ApeSafe, safe_tx: SafeTx): current_nonce = result["nonce"] + 1 break except (URLError) as err: - console_main.log( - f"Fetching txs from gnosis api failed with error: {err}") - current_nonce = click.prompt( - "Please input current nonce manually:", type=int) + console_main.log(f"Fetching txs from gnosis api failed with error: {err}") + current_nonce = click.prompt("Please input current nonce manually:", type=int) pending_nonce = safe.pending_nonce() @@ -85,29 +93,111 @@ def confirm_posting_transaction(safe: ApeSafe, safe_tx: SafeTx): ) -def bridge_to_arbitrum(safe: ApeSafe, token_address: str, amount: int): +def bridge_to_arbitrum_minichef(safe: ApeSafe, token_address: str, amount: int): + print(f"Attempting to bridge tokens at {token_address} to Arbitrum") + + # Solidity code: + # https://github.com/saddle-finance/saddle-contract/blob/29c785ce8d7788fcbe781129ce925679f36771c4/contracts/xchainGauges/bridgers/ArbitrumBridger.sol#L102-L124 + # bridge to arbitrum token = safe.contract(token_address) + gateway_router = Contract.from_abi( + "GateWayRouter", + ARBITRUM_L2_BRIDGE_ROUTER[CHAIN_IDS["MAINNET"]], + ARBITRUM_BRIDGE_ROUTER_ABI, + owner=DEPLOYER_ADDRESS, + ) + # Find the the gate way for the token - gateway_router = safe.contract(ARB_GATEWAY_ROUTER[CHAIN_IDS["MAINNET"]]) + gateway_router = safe.contract(ARBITRUM_L2_BRIDGE_ROUTER[CHAIN_IDS["MAINNET"]]) + print("Fetching L2 token address") gateway_address = gateway_router.getGateway(token.address) - + print(f"L2 token address found at {gateway_address}") # Find the approval amount approval_amount = token.allowance(safe.address, gateway_address) # Approve more tokens to the gateway if needed - if (approval_amount < amount): + if approval_amount < amount: token.approve(gateway_address, amount) # Calcualte the outbound call data + print("Calculating outbound call data") outbound_calldata = gateway_router.getOutboundCalldata( - token_address, MULTISIG_ADDRESSES["ARBITRUM"], amount, b"") + token_address, + DEPLOYER_ADDRESS, + MULTISIG_ADDRESSES[CHAIN_IDS["ARBITRUM"]], + amount, + b"", + ) + print(f"Outbound call data: {outbound_calldata}") + + # Get current block and base fee (does not work when forking) + if network.show_active() == "mainnet-fork": + base_fee = 47211945345 + else: + block = chain.height + base_fee = chain[block].baseFeePerGas # Calculate retryable submission fee - inbox = safe.contract(ARB_BRIDGE_INBOX[CHAIN_IDS["MAINNET"]]) - inbox.calculateRetryableSubmissionFee(outbound_calldata + 256, ) + print("Attempting to get retryable submission fee") + inbox = Contract.from_abi( + "inbox", + (ARBITRUM_BRIDGE_INBOX[CHAIN_IDS["MAINNET"]]), + ARBITRUM_BRIDGE_INBOX_ABI, + ) - # TODO: Use the retryable submission fee as msg.value - # Solidity code: - # https://github.com/saddle-finance/saddle-contract/blob/29c785ce8d7788fcbe781129ce925679f36771c4/contracts/xchainGauges/bridgers/ArbitrumBridger.sol#L102-L124 + retryableFee = inbox.calculateRetryableSubmissionFee( + outbound_calldata + 256, + base_fee, # block base fee + ) + print("Retryable submission fee", retryableFee) + + # Gas price constants + gasLimitL2 = 1000000 + gasPriceL2 = 990000000 + + print("Submitting retryable transfer to Arbitrum L1 Router") + # Submit the retryable transaction + gateway_router.outboundTransferCustomRefund( + token_address, # L1 token + DEPLOYER_ADDRESS, # L1 owner (receier of gas refund) + MULTISIG_ADDRESSES[CHAIN_IDS["ARBITRUM"]], # to + amount, + gasLimitL2, + gasPriceL2, + "0x" + eth_abi.encode_abi(["uint256", "bytes32[]"], [retryableFee, []]).hex(), + {"value": gasLimitL2 * gasPriceL2 + retryableFee}, + ) + + +def bridge_to_optimism(safe: ApeSafe, token_address: str, amount: int): + token = safe.contract(token_address) + optimism_L1_standard_bridge = safe.contract( + OPTIMISM_STANDARD_BRIDGE[CHAIN_IDS["MAINNET"]] + ) + + # Find the approval amount + approval_amount = token.allowance(safe.address, optimism_L1_standard_bridge.address) + + # Approve more tokens to the gateway if needed + if approval_amount < amount: + token.approve(optimism_L1_standard_bridge, amount) + + # approve bridge + token.approve(optimism_L1_standard_bridge.address, amount) + + # gas limit required to complete the deposit on L2 + l2gas = "0x1e8480" # 2,000,000 + + # Optimism bride code https://etherscan.io/address/0x40e0c049f4671846e9cff93aaed88f2b48e527bb#code + # send to Optimism minichef + print("Sending tokens to Optimism minichef") + optimism_L1_standard_bridge.depositERC20To( + token_address, # _l1token + SDL_ADDRESSES[CHAIN_IDS["OPTIMISM"]], # _l2token + MINICHEF_ADDRESSES[CHAIN_IDS["OPTIMISM"]], # _to + amount, # _amount + l2gas, # _l2gas + "0x", # _data + )