From 0448c0c1cf2749bd6671f37b258e76c5b22f9685 Mon Sep 17 00:00:00 2001 From: srdtrk <59252793+srdtrk@users.noreply.github.com> Date: Thu, 30 Jan 2025 18:34:00 +0800 Subject: [PATCH] feat: switched to UUPS proxy pattern with admin management (#247) --- README.md | 12 +- abi/ICS20Transfer.json | 89 ++++ abi/ICS26Router.json | 170 ++++++++ abigen/ics20transfer/contract.go | 229 ++++++++++- abigen/ics26router/contract.go | 388 +++++++++++++++++- contracts/ICS20Transfer.sol | 11 +- contracts/ICS26Router.sol | 8 +- .../errors/IIBCUUPSUpgradeableErrors.sol | 7 + contracts/interfaces/IIBCUUPSUpgradeable.sol | 25 ++ contracts/utils/IBCUUPSUpgradeable.sol | 92 +++++ packages/relayer-lib/src/events/eureka.rs | 1 + scripts/E2ETestDeploy.s.sol | 9 +- test/solidity-ibc/FixtureTest.t.sol | 15 +- .../solidity-ibc/IBCUUPSUpgradeableTest.t.sol | 145 +++++++ test/solidity-ibc/ICS02ClientTest.t.sol | 7 +- test/solidity-ibc/ICS26RouterTest.t.sol | 13 +- test/solidity-ibc/IntegrationTest.t.sol | 13 +- test/solidity-ibc/MigrationTest.t.sol | 106 ----- .../solidity-ibc/mocks/DummyInitializable.sol | 9 +- 19 files changed, 1184 insertions(+), 165 deletions(-) create mode 100644 contracts/errors/IIBCUUPSUpgradeableErrors.sol create mode 100644 contracts/interfaces/IIBCUUPSUpgradeable.sol create mode 100644 contracts/utils/IBCUUPSUpgradeable.sol create mode 100644 test/solidity-ibc/IBCUUPSUpgradeableTest.t.sol delete mode 100644 test/solidity-ibc/MigrationTest.t.sol diff --git a/README.md b/README.md index 659edaed..7342756c 100644 --- a/README.md +++ b/README.md @@ -162,10 +162,10 @@ The following benchmarks are for a single packet transfer without aggregation. | **Contract** | **Method** | **Description** | **Gas (groth16)** | **Gas (plonk)** | |:---:|:---:|:---:|:---:|:---:| | `ICS26Router.sol` | `sendPacket` | Initiating an IBC transfer with an `ERC20`. | ~160,500 | ~160,500 | -| `ICS26Router.sol` | `recvPacket` | Receiving _back_ an `ERC20` token. | ~514,011 | ~597,875 | -| `ICS26Router.sol` | `recvPacket` | Receiving a _new_ Cosmos token for the first time. (Deploying an `ERC20` contract) | ~1,364,451 | ~1,448,027 | -| `ICS26Router.sol` | `ackPacket` | Acknowledging an ICS20 packet. | ~395,232 | ~478,997 | -| `ICS26Router.sol` | `timeoutPacket` | Timing out an ICS20 packet | ~452,661 | ~536,368 | +| `ICS26Router.sol` | `recvPacket` | Receiving _back_ an `ERC20` token. | ~514,404 | ~598,268 | +| `ICS26Router.sol` | `recvPacket` | Receiving a _new_ Cosmos token for the first time. (Deploying an `ERC20` contract) | ~1,364,844 | ~1,448,420 | +| `ICS26Router.sol` | `ackPacket` | Acknowledging an ICS20 packet. | ~395,625 | ~479,390 | +| `ICS26Router.sol` | `timeoutPacket` | Timing out an ICS20 packet | ~452,966 | ~536,673 | ### Aggregated Packet Benchmarks @@ -174,8 +174,8 @@ Since there is no meaningful difference in gas costs between plonk and groth16 i | **ICS26Router Method** | **Description** | **Avg Gas (25 packets)** | **Avg Gas (50 packets)** | |:---:|:---:|:---:|:---:| -| `multicall/recvPacket` | Receiving _back_ an `ERC20` token. | ~185,583 | ~179,324 | -| `multicall/ackPacket` | Acknowledging an ICS20 packet. | ~96,148 | ~90,485 | +| `multicall/recvPacket` | Receiving _back_ an `ERC20` token. | ~185,876 | ~179,615 | +| `multicall/ackPacket` | Acknowledging an ICS20 packet. | ~96,436 | ~90,776 | Note: These gas benchmarks are with Groth16. diff --git a/abi/ICS20Transfer.json b/abi/ICS20Transfer.json index 9f6ce1ad..059143aa 100644 --- a/abi/ICS20Transfer.json +++ b/abi/ICS20Transfer.json @@ -4,6 +4,19 @@ "inputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "escrow", @@ -452,6 +465,19 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "sendTransfer", @@ -508,6 +534,24 @@ ], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, { "type": "event", "name": "Initialized", @@ -521,6 +565,19 @@ ], "anonymous": false }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, { "type": "error", "name": "AddressEmptyCode", @@ -532,6 +589,22 @@ } ] }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, { "type": "error", "name": "FailedCall", @@ -665,5 +738,21 @@ "internalType": "address" } ] + }, + { + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ] } ] diff --git a/abi/ICS26Router.json b/abi/ICS26Router.json index 162f3686..de8fea6f 100644 --- a/abi/ICS26Router.json +++ b/abi/ICS26Router.json @@ -17,6 +17,19 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "string", + "internalType": "string" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "ackPacket", @@ -246,6 +259,19 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "getGovAdmin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "getIBCApp", @@ -284,6 +310,19 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "getTimelockedAdmin", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "grantRole", @@ -330,6 +369,11 @@ "type": "function", "name": "initialize", "inputs": [ + { + "name": "timelockedAdmin", + "type": "address", + "internalType": "address" + }, { "name": "portCustomizer", "type": "address", @@ -339,6 +383,25 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "isAdmin", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "migrateClient", @@ -376,6 +439,19 @@ ], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "recvPacket", @@ -571,6 +647,32 @@ ], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "setGovAdmin", + "inputs": [ + { + "name": "newGovAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setTimelockedAdmin", + "inputs": [ + { + "name": "newTimelockedAdmin", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, { "type": "function", "name": "submitMisbehaviour", @@ -746,6 +848,24 @@ "outputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { + "name": "data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, { "type": "event", "name": "AckPacket", @@ -1164,6 +1284,19 @@ ], "anonymous": false }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, { "type": "event", "name": "WriteAcknowledgement", @@ -1269,6 +1402,22 @@ } ] }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "ERC1967NonPayable", + "inputs": [] + }, { "type": "error", "name": "FailedCall", @@ -1478,6 +1627,27 @@ } ] }, + { + "type": "error", + "name": "UUPSUnauthorizedCallContext", + "inputs": [] + }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { + "name": "slot", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "type": "error", + "name": "Unauthorized", + "inputs": [] + }, { "type": "error", "name": "Unreachable", diff --git a/abigen/ics20transfer/contract.go b/abigen/ics20transfer/contract.go index 69216a5f..aa8a2420 100644 --- a/abigen/ics20transfer/contract.go +++ b/abigen/ics20transfer/contract.go @@ -95,7 +95,7 @@ type IICS26RouterMsgsPayload struct { // ContractMetaData contains all meta data concerning the Contract contract. var ContractMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"escrow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ibcERC20Contract\",\"inputs\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"ics26Router\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"multicall\",\"inputs\":[{\"name\":\"data\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"newMsgSendPacketV1\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS20TransferMsgs.SendTransferMsg\",\"components\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiver\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"memo\",\"type\":\"string\",\"internalType\":\"string\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgSendPacket\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"onAcknowledgementPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnAcknowledgementPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"acknowledgement\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"relayer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"onRecvPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnRecvPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"relayer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"onSendPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnSendPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"onTimeoutPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnTimeoutPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"relayer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"sendTransfer\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS20TransferMsgs.SendTransferMsg\",\"components\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiver\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"memo\",\"type\":\"string\",\"internalType\":\"string\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ICS20AbiEncodingFailure\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ICS20DenomNotFound\",\"inputs\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ICS20InvalidAddress\",\"inputs\":[{\"name\":\"addr\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ICS20InvalidAmount\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ICS20Unauthorized\",\"inputs\":[{\"name\":\"caller\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ICS20UnauthorizedPacketSender\",\"inputs\":[{\"name\":\"packetSender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ICS20UnexpectedERC20Balance\",\"inputs\":[{\"name\":\"expected\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actual\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ICS20UnexpectedVersion\",\"inputs\":[{\"name\":\"expected\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ICS20UnsupportedFeature\",\"inputs\":[{\"name\":\"feature\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ReentrancyGuardReentrantCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SafeERC20FailedOperation\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}]}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"escrow\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ibcERC20Contract\",\"inputs\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"ics26Router\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"multicall\",\"inputs\":[{\"name\":\"data\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"newMsgSendPacketV1\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS20TransferMsgs.SendTransferMsg\",\"components\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiver\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"memo\",\"type\":\"string\",\"internalType\":\"string\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgSendPacket\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"onAcknowledgementPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnAcknowledgementPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"acknowledgement\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"relayer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"onRecvPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnRecvPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"relayer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"onSendPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnSendPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"onTimeoutPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIIBCAppCallbacks.OnTimeoutPacketCallback\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destinationClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sequence\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payload\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Payload\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"relayer\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"sendTransfer\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS20TransferMsgs.SendTransferMsg\",\"components\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"receiver\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"memo\",\"type\":\"string\",\"internalType\":\"string\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ICS20AbiEncodingFailure\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ICS20DenomNotFound\",\"inputs\":[{\"name\":\"denom\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ICS20InvalidAddress\",\"inputs\":[{\"name\":\"addr\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ICS20InvalidAmount\",\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ICS20Unauthorized\",\"inputs\":[{\"name\":\"caller\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ICS20UnauthorizedPacketSender\",\"inputs\":[{\"name\":\"packetSender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ICS20UnexpectedERC20Balance\",\"inputs\":[{\"name\":\"expected\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actual\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ICS20UnexpectedVersion\",\"inputs\":[{\"name\":\"expected\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ICS20UnsupportedFeature\",\"inputs\":[{\"name\":\"feature\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ReentrancyGuardReentrantCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SafeERC20FailedOperation\",\"inputs\":[{\"name\":\"token\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]", } // ContractABI is the input ABI used to generate the binding from. @@ -244,6 +244,37 @@ func (_Contract *ContractTransactorRaw) Transact(opts *bind.TransactOpts, method return _Contract.Contract.contract.Transact(opts, method, params...) } +// UPGRADEINTERFACEVERSION is a free data retrieval call binding the contract method 0xad3cb1cc. +// +// Solidity: function UPGRADE_INTERFACE_VERSION() view returns(string) +func (_Contract *ContractCaller) UPGRADEINTERFACEVERSION(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "UPGRADE_INTERFACE_VERSION") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// UPGRADEINTERFACEVERSION is a free data retrieval call binding the contract method 0xad3cb1cc. +// +// Solidity: function UPGRADE_INTERFACE_VERSION() view returns(string) +func (_Contract *ContractSession) UPGRADEINTERFACEVERSION() (string, error) { + return _Contract.Contract.UPGRADEINTERFACEVERSION(&_Contract.CallOpts) +} + +// UPGRADEINTERFACEVERSION is a free data retrieval call binding the contract method 0xad3cb1cc. +// +// Solidity: function UPGRADE_INTERFACE_VERSION() view returns(string) +func (_Contract *ContractCallerSession) UPGRADEINTERFACEVERSION() (string, error) { + return _Contract.Contract.UPGRADEINTERFACEVERSION(&_Contract.CallOpts) +} + // Escrow is a free data retrieval call binding the contract method 0xe2fdcc17. // // Solidity: function escrow() view returns(address) @@ -337,6 +368,37 @@ func (_Contract *ContractCallerSession) NewMsgSendPacketV1(sender common.Address return _Contract.Contract.NewMsgSendPacketV1(&_Contract.CallOpts, sender, msg_) } +// ProxiableUUID is a free data retrieval call binding the contract method 0x52d1902d. +// +// Solidity: function proxiableUUID() view returns(bytes32) +func (_Contract *ContractCaller) ProxiableUUID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "proxiableUUID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// ProxiableUUID is a free data retrieval call binding the contract method 0x52d1902d. +// +// Solidity: function proxiableUUID() view returns(bytes32) +func (_Contract *ContractSession) ProxiableUUID() ([32]byte, error) { + return _Contract.Contract.ProxiableUUID(&_Contract.CallOpts) +} + +// ProxiableUUID is a free data retrieval call binding the contract method 0x52d1902d. +// +// Solidity: function proxiableUUID() view returns(bytes32) +func (_Contract *ContractCallerSession) ProxiableUUID() ([32]byte, error) { + return _Contract.Contract.ProxiableUUID(&_Contract.CallOpts) +} + // Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. // // Solidity: function initialize(address ics26Router) returns() @@ -484,6 +546,27 @@ func (_Contract *ContractTransactorSession) SendTransfer(msg_ IICS20TransferMsgs return _Contract.Contract.SendTransfer(&_Contract.TransactOpts, msg_) } +// UpgradeToAndCall is a paid mutator transaction binding the contract method 0x4f1ef286. +// +// Solidity: function upgradeToAndCall(address newImplementation, bytes data) payable returns() +func (_Contract *ContractTransactor) UpgradeToAndCall(opts *bind.TransactOpts, newImplementation common.Address, data []byte) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "upgradeToAndCall", newImplementation, data) +} + +// UpgradeToAndCall is a paid mutator transaction binding the contract method 0x4f1ef286. +// +// Solidity: function upgradeToAndCall(address newImplementation, bytes data) payable returns() +func (_Contract *ContractSession) UpgradeToAndCall(newImplementation common.Address, data []byte) (*types.Transaction, error) { + return _Contract.Contract.UpgradeToAndCall(&_Contract.TransactOpts, newImplementation, data) +} + +// UpgradeToAndCall is a paid mutator transaction binding the contract method 0x4f1ef286. +// +// Solidity: function upgradeToAndCall(address newImplementation, bytes data) payable returns() +func (_Contract *ContractTransactorSession) UpgradeToAndCall(newImplementation common.Address, data []byte) (*types.Transaction, error) { + return _Contract.Contract.UpgradeToAndCall(&_Contract.TransactOpts, newImplementation, data) +} + // ContractInitializedIterator is returned from FilterInitialized and is used to iterate over the raw logs and unpacked data for Initialized events raised by the Contract contract. type ContractInitializedIterator struct { Event *ContractInitialized // Event containing the contract specifics and raw log @@ -617,3 +700,147 @@ func (_Contract *ContractFilterer) ParseInitialized(log types.Log) (*ContractIni event.Raw = log return event, nil } + +// ContractUpgradedIterator is returned from FilterUpgraded and is used to iterate over the raw logs and unpacked data for Upgraded events raised by the Contract contract. +type ContractUpgradedIterator struct { + Event *ContractUpgraded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ContractUpgradedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ContractUpgraded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ContractUpgraded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ContractUpgradedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractUpgradedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractUpgraded represents a Upgraded event raised by the Contract contract. +type ContractUpgraded struct { + Implementation common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterUpgraded is a free log retrieval operation binding the contract event 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b. +// +// Solidity: event Upgraded(address indexed implementation) +func (_Contract *ContractFilterer) FilterUpgraded(opts *bind.FilterOpts, implementation []common.Address) (*ContractUpgradedIterator, error) { + + var implementationRule []interface{} + for _, implementationItem := range implementation { + implementationRule = append(implementationRule, implementationItem) + } + + logs, sub, err := _Contract.contract.FilterLogs(opts, "Upgraded", implementationRule) + if err != nil { + return nil, err + } + return &ContractUpgradedIterator{contract: _Contract.contract, event: "Upgraded", logs: logs, sub: sub}, nil +} + +// WatchUpgraded is a free log subscription operation binding the contract event 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b. +// +// Solidity: event Upgraded(address indexed implementation) +func (_Contract *ContractFilterer) WatchUpgraded(opts *bind.WatchOpts, sink chan<- *ContractUpgraded, implementation []common.Address) (event.Subscription, error) { + + var implementationRule []interface{} + for _, implementationItem := range implementation { + implementationRule = append(implementationRule, implementationItem) + } + + logs, sub, err := _Contract.contract.WatchLogs(opts, "Upgraded", implementationRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ContractUpgraded) + if err := _Contract.contract.UnpackLog(event, "Upgraded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseUpgraded is a log parse operation binding the contract event 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b. +// +// Solidity: event Upgraded(address indexed implementation) +func (_Contract *ContractFilterer) ParseUpgraded(log types.Log) (*ContractUpgraded, error) { + event := new(ContractUpgraded) + if err := _Contract.contract.UnpackLog(event, "Upgraded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/abigen/ics26router/contract.go b/abigen/ics26router/contract.go index e4db5eb6..34d62d70 100644 --- a/abigen/ics26router/contract.go +++ b/abigen/ics26router/contract.go @@ -90,7 +90,7 @@ type IICS26RouterMsgsPayload struct { // ContractMetaData contains all meta data concerning the Contract contract. var ContractMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ackPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgAckPacket\",\"components\":[{\"name\":\"packet\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"acknowledgement\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofAcked\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addClient\",\"inputs\":[{\"name\":\"clientType\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"counterpartyInfo\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.CounterpartyInfo\",\"components\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"merklePrefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]},{\"name\":\"client\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addIBCApp\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"app\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getClient\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractILightClient\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCommitment\",\"inputs\":[{\"name\":\"hashedPath\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCounterparty\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.CounterpartyInfo\",\"components\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"merklePrefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getIBCApp\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIIBCApp\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"portCustomizer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"migrateClient\",\"inputs\":[{\"name\":\"subjectClientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"substituteClientId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"multicall\",\"inputs\":[{\"name\":\"data\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"recvPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgRecvPacket\",\"components\":[{\"name\":\"packet\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"proofCommitment\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"sendPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgSendPacket\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"submitMisbehaviour\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"misbehaviourMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"timeoutPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgTimeoutPacket\",\"components\":[{\"name\":\"packet\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"proofTimeout\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateClient\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"updateMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumILightClientMsgs.UpdateResult\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeClient\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"upgradeMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"AckPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"acknowledgement\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"IBCAppAdded\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"app\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ICS02ClientAdded\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"counterpartyInfo\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS02ClientMsgs.CounterpartyInfo\",\"components\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"merklePrefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Noop\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RecvPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SendPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TimeoutPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WriteAcknowledgement\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"acknowledgements\",\"type\":\"bytes[]\",\"indexed\":false,\"internalType\":\"bytes[]\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"IBCAppNotFound\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCAsyncAcknowledgementNotSupported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"IBCClientNotFound\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCCounterpartyClientNotFound\",\"inputs\":[{\"name\":\"counterpartyClientId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidClientType\",\"inputs\":[{\"name\":\"clientType\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidCounterparty\",\"inputs\":[{\"name\":\"expected\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"actual\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidPortIdentifier\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidTimeoutDuration\",\"inputs\":[{\"name\":\"maxTimeoutDuration\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actualTimeoutDuration\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidTimeoutTimestamp\",\"inputs\":[{\"name\":\"timeoutTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"comparedTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"IBCMultiPayloadPacketNotSupported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"IBCPacketAcknowledgementAlreadyExists\",\"inputs\":[{\"name\":\"path\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"IBCPacketCommitmentAlreadyExists\",\"inputs\":[{\"name\":\"path\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"IBCPacketCommitmentMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"IBCPortAlreadyExists\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMerklePrefix\",\"inputs\":[{\"name\":\"prefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ReentrancyGuardReentrantCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StringsInsufficientHexLength\",\"inputs\":[{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"length\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"Unreachable\",\"inputs\":[]}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ackPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgAckPacket\",\"components\":[{\"name\":\"packet\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"acknowledgement\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofAcked\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addClient\",\"inputs\":[{\"name\":\"clientType\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"counterpartyInfo\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.CounterpartyInfo\",\"components\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"merklePrefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]},{\"name\":\"client\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addIBCApp\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"app\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getClient\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractILightClient\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCommitment\",\"inputs\":[{\"name\":\"hashedPath\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getCounterparty\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.CounterpartyInfo\",\"components\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"merklePrefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getGovAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getIBCApp\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIIBCApp\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getTimelockedAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"timelockedAdmin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"portCustomizer\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isAdmin\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"migrateClient\",\"inputs\":[{\"name\":\"subjectClientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"substituteClientId\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"multicall\",\"inputs\":[{\"name\":\"data\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"outputs\":[{\"name\":\"results\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"recvPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgRecvPacket\",\"components\":[{\"name\":\"packet\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"proofCommitment\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"sendPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgSendPacket\",\"components\":[{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGovAdmin\",\"inputs\":[{\"name\":\"newGovAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setTimelockedAdmin\",\"inputs\":[{\"name\":\"newTimelockedAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"submitMisbehaviour\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"misbehaviourMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"timeoutPacket\",\"inputs\":[{\"name\":\"msg_\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.MsgTimeoutPacket\",\"components\":[{\"name\":\"packet\",\"type\":\"tuple\",\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"proofTimeout\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateClient\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"updateMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumILightClientMsgs.UpdateResult\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeClient\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"upgradeMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"AckPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"acknowledgement\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"IBCAppAdded\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"app\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ICS02ClientAdded\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"counterpartyInfo\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS02ClientMsgs.CounterpartyInfo\",\"components\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"merklePrefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Noop\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RecvPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"SendPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"TimeoutPacket\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"WriteAcknowledgement\",\"inputs\":[{\"name\":\"packet\",\"type\":\"tuple\",\"indexed\":false,\"internalType\":\"structIICS26RouterMsgs.Packet\",\"components\":[{\"name\":\"sequence\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"sourceClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destClient\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"timeoutTimestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"payloads\",\"type\":\"tuple[]\",\"internalType\":\"structIICS26RouterMsgs.Payload[]\",\"components\":[{\"name\":\"sourcePort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"destPort\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"version\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"encoding\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"acknowledgements\",\"type\":\"bytes[]\",\"indexed\":false,\"internalType\":\"bytes[]\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"IBCAppNotFound\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCAsyncAcknowledgementNotSupported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"IBCClientNotFound\",\"inputs\":[{\"name\":\"clientId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCCounterpartyClientNotFound\",\"inputs\":[{\"name\":\"counterpartyClientId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidClientType\",\"inputs\":[{\"name\":\"clientType\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidCounterparty\",\"inputs\":[{\"name\":\"expected\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"actual\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidPortIdentifier\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidTimeoutDuration\",\"inputs\":[{\"name\":\"maxTimeoutDuration\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actualTimeoutDuration\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"IBCInvalidTimeoutTimestamp\",\"inputs\":[{\"name\":\"timeoutTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"comparedTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"IBCMultiPayloadPacketNotSupported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"IBCPacketAcknowledgementAlreadyExists\",\"inputs\":[{\"name\":\"path\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"IBCPacketCommitmentAlreadyExists\",\"inputs\":[{\"name\":\"path\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"IBCPacketCommitmentMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"IBCPortAlreadyExists\",\"inputs\":[{\"name\":\"portId\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMerklePrefix\",\"inputs\":[{\"name\":\"prefix\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ReentrancyGuardReentrantCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"StringsInsufficientHexLength\",\"inputs\":[{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"length\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Unreachable\",\"inputs\":[]}]", } // ContractABI is the input ABI used to generate the binding from. @@ -270,6 +270,37 @@ func (_Contract *ContractCallerSession) DEFAULTADMINROLE() ([32]byte, error) { return _Contract.Contract.DEFAULTADMINROLE(&_Contract.CallOpts) } +// UPGRADEINTERFACEVERSION is a free data retrieval call binding the contract method 0xad3cb1cc. +// +// Solidity: function UPGRADE_INTERFACE_VERSION() view returns(string) +func (_Contract *ContractCaller) UPGRADEINTERFACEVERSION(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "UPGRADE_INTERFACE_VERSION") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// UPGRADEINTERFACEVERSION is a free data retrieval call binding the contract method 0xad3cb1cc. +// +// Solidity: function UPGRADE_INTERFACE_VERSION() view returns(string) +func (_Contract *ContractSession) UPGRADEINTERFACEVERSION() (string, error) { + return _Contract.Contract.UPGRADEINTERFACEVERSION(&_Contract.CallOpts) +} + +// UPGRADEINTERFACEVERSION is a free data retrieval call binding the contract method 0xad3cb1cc. +// +// Solidity: function UPGRADE_INTERFACE_VERSION() view returns(string) +func (_Contract *ContractCallerSession) UPGRADEINTERFACEVERSION() (string, error) { + return _Contract.Contract.UPGRADEINTERFACEVERSION(&_Contract.CallOpts) +} + // GetClient is a free data retrieval call binding the contract method 0x7eb78932. // // Solidity: function getClient(string clientId) view returns(address) @@ -363,6 +394,37 @@ func (_Contract *ContractCallerSession) GetCounterparty(clientId string) (IICS02 return _Contract.Contract.GetCounterparty(&_Contract.CallOpts, clientId) } +// GetGovAdmin is a free data retrieval call binding the contract method 0x54a5979b. +// +// Solidity: function getGovAdmin() view returns(address) +func (_Contract *ContractCaller) GetGovAdmin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "getGovAdmin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetGovAdmin is a free data retrieval call binding the contract method 0x54a5979b. +// +// Solidity: function getGovAdmin() view returns(address) +func (_Contract *ContractSession) GetGovAdmin() (common.Address, error) { + return _Contract.Contract.GetGovAdmin(&_Contract.CallOpts) +} + +// GetGovAdmin is a free data retrieval call binding the contract method 0x54a5979b. +// +// Solidity: function getGovAdmin() view returns(address) +func (_Contract *ContractCallerSession) GetGovAdmin() (common.Address, error) { + return _Contract.Contract.GetGovAdmin(&_Contract.CallOpts) +} + // GetIBCApp is a free data retrieval call binding the contract method 0x2447af29. // // Solidity: function getIBCApp(string portId) view returns(address) @@ -425,6 +487,37 @@ func (_Contract *ContractCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, e return _Contract.Contract.GetRoleAdmin(&_Contract.CallOpts, role) } +// GetTimelockedAdmin is a free data retrieval call binding the contract method 0x365388a2. +// +// Solidity: function getTimelockedAdmin() view returns(address) +func (_Contract *ContractCaller) GetTimelockedAdmin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "getTimelockedAdmin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetTimelockedAdmin is a free data retrieval call binding the contract method 0x365388a2. +// +// Solidity: function getTimelockedAdmin() view returns(address) +func (_Contract *ContractSession) GetTimelockedAdmin() (common.Address, error) { + return _Contract.Contract.GetTimelockedAdmin(&_Contract.CallOpts) +} + +// GetTimelockedAdmin is a free data retrieval call binding the contract method 0x365388a2. +// +// Solidity: function getTimelockedAdmin() view returns(address) +func (_Contract *ContractCallerSession) GetTimelockedAdmin() (common.Address, error) { + return _Contract.Contract.GetTimelockedAdmin(&_Contract.CallOpts) +} + // HasRole is a free data retrieval call binding the contract method 0x91d14854. // // Solidity: function hasRole(bytes32 role, address account) view returns(bool) @@ -456,6 +549,68 @@ func (_Contract *ContractCallerSession) HasRole(role [32]byte, account common.Ad return _Contract.Contract.HasRole(&_Contract.CallOpts, role, account) } +// IsAdmin is a free data retrieval call binding the contract method 0x24d7806c. +// +// Solidity: function isAdmin(address account) view returns(bool) +func (_Contract *ContractCaller) IsAdmin(opts *bind.CallOpts, account common.Address) (bool, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "isAdmin", account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsAdmin is a free data retrieval call binding the contract method 0x24d7806c. +// +// Solidity: function isAdmin(address account) view returns(bool) +func (_Contract *ContractSession) IsAdmin(account common.Address) (bool, error) { + return _Contract.Contract.IsAdmin(&_Contract.CallOpts, account) +} + +// IsAdmin is a free data retrieval call binding the contract method 0x24d7806c. +// +// Solidity: function isAdmin(address account) view returns(bool) +func (_Contract *ContractCallerSession) IsAdmin(account common.Address) (bool, error) { + return _Contract.Contract.IsAdmin(&_Contract.CallOpts, account) +} + +// ProxiableUUID is a free data retrieval call binding the contract method 0x52d1902d. +// +// Solidity: function proxiableUUID() view returns(bytes32) +func (_Contract *ContractCaller) ProxiableUUID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "proxiableUUID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// ProxiableUUID is a free data retrieval call binding the contract method 0x52d1902d. +// +// Solidity: function proxiableUUID() view returns(bytes32) +func (_Contract *ContractSession) ProxiableUUID() ([32]byte, error) { + return _Contract.Contract.ProxiableUUID(&_Contract.CallOpts) +} + +// ProxiableUUID is a free data retrieval call binding the contract method 0x52d1902d. +// +// Solidity: function proxiableUUID() view returns(bytes32) +func (_Contract *ContractCallerSession) ProxiableUUID() ([32]byte, error) { + return _Contract.Contract.ProxiableUUID(&_Contract.CallOpts) +} + // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) @@ -571,25 +726,25 @@ func (_Contract *ContractTransactorSession) GrantRole(role [32]byte, account com return _Contract.Contract.GrantRole(&_Contract.TransactOpts, role, account) } -// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// Initialize is a paid mutator transaction binding the contract method 0x485cc955. // -// Solidity: function initialize(address portCustomizer) returns() -func (_Contract *ContractTransactor) Initialize(opts *bind.TransactOpts, portCustomizer common.Address) (*types.Transaction, error) { - return _Contract.contract.Transact(opts, "initialize", portCustomizer) +// Solidity: function initialize(address timelockedAdmin, address portCustomizer) returns() +func (_Contract *ContractTransactor) Initialize(opts *bind.TransactOpts, timelockedAdmin common.Address, portCustomizer common.Address) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "initialize", timelockedAdmin, portCustomizer) } -// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// Initialize is a paid mutator transaction binding the contract method 0x485cc955. // -// Solidity: function initialize(address portCustomizer) returns() -func (_Contract *ContractSession) Initialize(portCustomizer common.Address) (*types.Transaction, error) { - return _Contract.Contract.Initialize(&_Contract.TransactOpts, portCustomizer) +// Solidity: function initialize(address timelockedAdmin, address portCustomizer) returns() +func (_Contract *ContractSession) Initialize(timelockedAdmin common.Address, portCustomizer common.Address) (*types.Transaction, error) { + return _Contract.Contract.Initialize(&_Contract.TransactOpts, timelockedAdmin, portCustomizer) } -// Initialize is a paid mutator transaction binding the contract method 0xc4d66de8. +// Initialize is a paid mutator transaction binding the contract method 0x485cc955. // -// Solidity: function initialize(address portCustomizer) returns() -func (_Contract *ContractTransactorSession) Initialize(portCustomizer common.Address) (*types.Transaction, error) { - return _Contract.Contract.Initialize(&_Contract.TransactOpts, portCustomizer) +// Solidity: function initialize(address timelockedAdmin, address portCustomizer) returns() +func (_Contract *ContractTransactorSession) Initialize(timelockedAdmin common.Address, portCustomizer common.Address) (*types.Transaction, error) { + return _Contract.Contract.Initialize(&_Contract.TransactOpts, timelockedAdmin, portCustomizer) } // MigrateClient is a paid mutator transaction binding the contract method 0x9ea7ff99. @@ -718,6 +873,48 @@ func (_Contract *ContractTransactorSession) SendPacket(msg_ IICS26RouterMsgsMsgS return _Contract.Contract.SendPacket(&_Contract.TransactOpts, msg_) } +// SetGovAdmin is a paid mutator transaction binding the contract method 0x340cbac4. +// +// Solidity: function setGovAdmin(address newGovAdmin) returns() +func (_Contract *ContractTransactor) SetGovAdmin(opts *bind.TransactOpts, newGovAdmin common.Address) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "setGovAdmin", newGovAdmin) +} + +// SetGovAdmin is a paid mutator transaction binding the contract method 0x340cbac4. +// +// Solidity: function setGovAdmin(address newGovAdmin) returns() +func (_Contract *ContractSession) SetGovAdmin(newGovAdmin common.Address) (*types.Transaction, error) { + return _Contract.Contract.SetGovAdmin(&_Contract.TransactOpts, newGovAdmin) +} + +// SetGovAdmin is a paid mutator transaction binding the contract method 0x340cbac4. +// +// Solidity: function setGovAdmin(address newGovAdmin) returns() +func (_Contract *ContractTransactorSession) SetGovAdmin(newGovAdmin common.Address) (*types.Transaction, error) { + return _Contract.Contract.SetGovAdmin(&_Contract.TransactOpts, newGovAdmin) +} + +// SetTimelockedAdmin is a paid mutator transaction binding the contract method 0x075beb64. +// +// Solidity: function setTimelockedAdmin(address newTimelockedAdmin) returns() +func (_Contract *ContractTransactor) SetTimelockedAdmin(opts *bind.TransactOpts, newTimelockedAdmin common.Address) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "setTimelockedAdmin", newTimelockedAdmin) +} + +// SetTimelockedAdmin is a paid mutator transaction binding the contract method 0x075beb64. +// +// Solidity: function setTimelockedAdmin(address newTimelockedAdmin) returns() +func (_Contract *ContractSession) SetTimelockedAdmin(newTimelockedAdmin common.Address) (*types.Transaction, error) { + return _Contract.Contract.SetTimelockedAdmin(&_Contract.TransactOpts, newTimelockedAdmin) +} + +// SetTimelockedAdmin is a paid mutator transaction binding the contract method 0x075beb64. +// +// Solidity: function setTimelockedAdmin(address newTimelockedAdmin) returns() +func (_Contract *ContractTransactorSession) SetTimelockedAdmin(newTimelockedAdmin common.Address) (*types.Transaction, error) { + return _Contract.Contract.SetTimelockedAdmin(&_Contract.TransactOpts, newTimelockedAdmin) +} + // SubmitMisbehaviour is a paid mutator transaction binding the contract method 0x9e2e5c83. // // Solidity: function submitMisbehaviour(string clientId, bytes misbehaviourMsg) returns() @@ -802,6 +999,27 @@ func (_Contract *ContractTransactorSession) UpgradeClient(clientId string, upgra return _Contract.Contract.UpgradeClient(&_Contract.TransactOpts, clientId, upgradeMsg) } +// UpgradeToAndCall is a paid mutator transaction binding the contract method 0x4f1ef286. +// +// Solidity: function upgradeToAndCall(address newImplementation, bytes data) payable returns() +func (_Contract *ContractTransactor) UpgradeToAndCall(opts *bind.TransactOpts, newImplementation common.Address, data []byte) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "upgradeToAndCall", newImplementation, data) +} + +// UpgradeToAndCall is a paid mutator transaction binding the contract method 0x4f1ef286. +// +// Solidity: function upgradeToAndCall(address newImplementation, bytes data) payable returns() +func (_Contract *ContractSession) UpgradeToAndCall(newImplementation common.Address, data []byte) (*types.Transaction, error) { + return _Contract.Contract.UpgradeToAndCall(&_Contract.TransactOpts, newImplementation, data) +} + +// UpgradeToAndCall is a paid mutator transaction binding the contract method 0x4f1ef286. +// +// Solidity: function upgradeToAndCall(address newImplementation, bytes data) payable returns() +func (_Contract *ContractTransactorSession) UpgradeToAndCall(newImplementation common.Address, data []byte) (*types.Transaction, error) { + return _Contract.Contract.UpgradeToAndCall(&_Contract.TransactOpts, newImplementation, data) +} + // ContractAckPacketIterator is returned from FilterAckPacket and is used to iterate over the raw logs and unpacked data for AckPacket events raised by the Contract contract. type ContractAckPacketIterator struct { Event *ContractAckPacket // Event containing the contract specifics and raw log @@ -2362,6 +2580,150 @@ func (_Contract *ContractFilterer) ParseTimeoutPacket(log types.Log) (*ContractT return event, nil } +// ContractUpgradedIterator is returned from FilterUpgraded and is used to iterate over the raw logs and unpacked data for Upgraded events raised by the Contract contract. +type ContractUpgradedIterator struct { + Event *ContractUpgraded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ContractUpgradedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ContractUpgraded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ContractUpgraded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ContractUpgradedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ContractUpgradedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ContractUpgraded represents a Upgraded event raised by the Contract contract. +type ContractUpgraded struct { + Implementation common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterUpgraded is a free log retrieval operation binding the contract event 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b. +// +// Solidity: event Upgraded(address indexed implementation) +func (_Contract *ContractFilterer) FilterUpgraded(opts *bind.FilterOpts, implementation []common.Address) (*ContractUpgradedIterator, error) { + + var implementationRule []interface{} + for _, implementationItem := range implementation { + implementationRule = append(implementationRule, implementationItem) + } + + logs, sub, err := _Contract.contract.FilterLogs(opts, "Upgraded", implementationRule) + if err != nil { + return nil, err + } + return &ContractUpgradedIterator{contract: _Contract.contract, event: "Upgraded", logs: logs, sub: sub}, nil +} + +// WatchUpgraded is a free log subscription operation binding the contract event 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b. +// +// Solidity: event Upgraded(address indexed implementation) +func (_Contract *ContractFilterer) WatchUpgraded(opts *bind.WatchOpts, sink chan<- *ContractUpgraded, implementation []common.Address) (event.Subscription, error) { + + var implementationRule []interface{} + for _, implementationItem := range implementation { + implementationRule = append(implementationRule, implementationItem) + } + + logs, sub, err := _Contract.contract.WatchLogs(opts, "Upgraded", implementationRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ContractUpgraded) + if err := _Contract.contract.UnpackLog(event, "Upgraded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseUpgraded is a log parse operation binding the contract event 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b. +// +// Solidity: event Upgraded(address indexed implementation) +func (_Contract *ContractFilterer) ParseUpgraded(log types.Log) (*ContractUpgraded, error) { + event := new(ContractUpgraded) + if err := _Contract.contract.UnpackLog(event, "Upgraded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + // ContractWriteAcknowledgementIterator is returned from FilterWriteAcknowledgement and is used to iterate over the raw logs and unpacked data for WriteAcknowledgement events raised by the Contract contract. type ContractWriteAcknowledgementIterator struct { Event *ContractWriteAcknowledgement // Event containing the contract specifics and raw log diff --git a/contracts/ICS20Transfer.sol b/contracts/ICS20Transfer.sol index 2b88ab5b..b7d2e836 100644 --- a/contracts/ICS20Transfer.sol +++ b/contracts/ICS20Transfer.sol @@ -16,6 +16,8 @@ import { IICS26RouterMsgs } from "./msgs/IICS26RouterMsgs.sol"; import { IBCERC20 } from "./utils/IBCERC20.sol"; import { Escrow } from "./utils/Escrow.sol"; import { Bytes } from "@openzeppelin-contracts/utils/Bytes.sol"; +import { UUPSUpgradeable } from "@openzeppelin-contracts/proxy/utils/UUPSUpgradeable.sol"; +import { IIBCUUPSUpgradeable } from "./interfaces/IIBCUUPSUpgradeable.sol"; using SafeERC20 for IERC20; @@ -29,7 +31,8 @@ contract ICS20Transfer is IICS20Transfer, IICS20Errors, ReentrancyGuardTransientUpgradeable, - MulticallUpgradeable + MulticallUpgradeable, + UUPSUpgradeable { /// @notice Storage of the ICS20Transfer contract /// @dev It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions when using with @@ -321,6 +324,12 @@ contract ICS20Transfer is } } + /// @inheritdoc UUPSUpgradeable + function _authorizeUpgrade(address) internal virtual override { + address ics26Router = address(_getICS26Router()); + require(IIBCUUPSUpgradeable(ics26Router).isAdmin(_msgSender()), ICS20Unauthorized(_msgSender())); + } + function _getEscrow() private view returns (IEscrow) { return _getICS20TransferStorage().escrow; } diff --git a/contracts/ICS26Router.sol b/contracts/ICS26Router.sol index f90697f1..0f4ed9fe 100644 --- a/contracts/ICS26Router.sol +++ b/contracts/ICS26Router.sol @@ -14,6 +14,7 @@ import { ILightClientMsgs } from "./msgs/ILightClientMsgs.sol"; import { ReentrancyGuardTransientUpgradeable } from "@openzeppelin-upgradeable/utils/ReentrancyGuardTransientUpgradeable.sol"; import { MulticallUpgradeable } from "@openzeppelin-upgradeable/utils/MulticallUpgradeable.sol"; +import { IBCUUPSUpgradeable } from "./utils/IBCUUPSUpgradeable.sol"; /// @title IBC Eureka Router /// @notice ICS26Router is the router for the IBC Eureka protocol @@ -23,7 +24,8 @@ contract ICS26Router is ICS02ClientUpgradeable, IBCStoreUpgradeable, ReentrancyGuardTransientUpgradeable, - MulticallUpgradeable + MulticallUpgradeable, + IBCUUPSUpgradeable { /// @notice Storage of the ICS26Router contract /// @dev It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions when using with @@ -54,13 +56,15 @@ contract ICS26Router is /// @notice Initializes the contract instead of a constructor /// @dev Meant to be called only once from the proxy + /// @param timelockedAdmin The address of the timelocked admin for IBCUUPSUpgradeable /// @param portCustomizer The address of the port customizer - function initialize(address portCustomizer) public initializer { + function initialize(address timelockedAdmin, address portCustomizer) public initializer { __AccessControl_init(); __ReentrancyGuardTransient_init(); __Multicall_init(); __ICS02Client_init(); __IBCStoreUpgradeable_init(); + __IBCUUPSUpgradeable_init(timelockedAdmin); _grantRole(PORT_CUSTOMIZER_ROLE, portCustomizer); } diff --git a/contracts/errors/IIBCUUPSUpgradeableErrors.sol b/contracts/errors/IIBCUUPSUpgradeableErrors.sol new file mode 100644 index 000000000..a54cbfb2 --- /dev/null +++ b/contracts/errors/IIBCUUPSUpgradeableErrors.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +interface IIBCUUPSUpgradeableErrors { + /// @notice Error code returned when caller is not the timelocked admin nor the governance admin + error Unauthorized(); +} diff --git a/contracts/interfaces/IIBCUUPSUpgradeable.sol b/contracts/interfaces/IIBCUUPSUpgradeable.sol new file mode 100644 index 000000000..ddb68baa --- /dev/null +++ b/contracts/interfaces/IIBCUUPSUpgradeable.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +interface IIBCUUPSUpgradeable { + /// @notice Returns the timelocked admin address + /// @return The timelocked admin address + function getTimelockedAdmin() external view returns (address); + /// @notice Returns the governance admin address + /// @return The governance admin address, 0 if not set + function getGovAdmin() external view returns (address); + /// @notice Sets the timelocked admin address + /// @dev Either admin can set the timelocked admin address. + /// @param newTimelockedAdmin The new timelocked admin address + function setTimelockedAdmin(address newTimelockedAdmin) external; + /// @notice Sets the governance admin address + /// @dev Either admin can set the governance admin address. + /// @dev Since timelocked admin is timelocked, this operation can be stopped by the govAdmin. + /// @param newGovAdmin The new governance admin address + function setGovAdmin(address newGovAdmin) external; + /// @notice Returns true if the account is an admin + /// @dev Used by other IBC contracts to check if upgrades are authorized + /// @param account The account to check + /// @return True if the account is an admin + function isAdmin(address account) external view returns (bool); +} diff --git a/contracts/utils/IBCUUPSUpgradeable.sol b/contracts/utils/IBCUUPSUpgradeable.sol new file mode 100644 index 000000000..b69909a9 --- /dev/null +++ b/contracts/utils/IBCUUPSUpgradeable.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import { IIBCUUPSUpgradeableErrors } from "../errors/IIBCUUPSUpgradeableErrors.sol"; +import { ContextUpgradeable } from "@openzeppelin-upgradeable/utils/ContextUpgradeable.sol"; +import { UUPSUpgradeable } from "@openzeppelin-contracts/proxy/utils/UUPSUpgradeable.sol"; +import { IIBCUUPSUpgradeable } from "../interfaces/IIBCUUPSUpgradeable.sol"; + +/// @title IBC UUPSUpgradeable contract +/// @notice This contract is an abstract contract for managing upgradability of IBC contracts. +/// @dev This contract is developed with OpenZeppelin's UUPS upgradeable proxy pattern. +/// @dev This contract is meant to be inherited by ICS26Router implementation, and it manages its own upgradability. +/// @dev Other IBC contracts can directly query ICS26Router for the admin addresses to authorize UUPS upgrades (see +/// ICS20Transfer). +/// @dev This contract manages two roles: the timelocked admin, and the governance admin. The timelocked admin +/// represents a timelocked security council, and the governance admin represents an interchain account from the +/// governance of a counterparty chain. The timelocked admin must be set during initialization, and the governance admin +/// should be set later by the timelocked admin. +/// @dev We recommend using `openzeppelin-contracts/contracts/governance/TimelockController.sol` for the timelocked +/// admin +abstract contract IBCUUPSUpgradeable is + IIBCUUPSUpgradeableErrors, + IIBCUUPSUpgradeable, + UUPSUpgradeable, + ContextUpgradeable +{ + /// @notice Storage of the IBCUUPSUpgradeable contract + /// @dev It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions when using with + /// upgradeable contracts. + /// @param timelockedAdmin The timelocked admin address, assumed to be timelocked + /// @param govAdmin The governance admin address + struct IBCUUPSUpgradeableStorage { + address timelockedAdmin; + address govAdmin; + } + + /// @notice ERC-7201 slot for the IBCUUPSUpgradeable storage + /// @dev keccak256(abi.encode(uint256(keccak256("ibc.storage.IBCUUPSUpgradeable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant IBCUUPSUPGRADEABLE_STORAGE_SLOT = + 0xba83ed17c16070da0debaa680185af188d82c999a75962a12a40699ca48a2b00; + + /// @dev This contract is meant to be initialized with only the timelockedAdmin, and the govAdmin should be set by + /// the timelockedAdmin later + /// @dev It makes sense to have the timelockedAdmin not be timelocked until the govAdmin is set + function __IBCUUPSUpgradeable_init(address timelockedAdmin) internal onlyInitializing { + _getIBCUUPSUpgradeableStorage().timelockedAdmin = timelockedAdmin; + } + + /// @inheritdoc IIBCUUPSUpgradeable + function getTimelockedAdmin() external view returns (address) { + return _getIBCUUPSUpgradeableStorage().timelockedAdmin; + } + + /// @inheritdoc IIBCUUPSUpgradeable + function getGovAdmin() external view returns (address) { + return _getIBCUUPSUpgradeableStorage().govAdmin; + } + + /// @inheritdoc IIBCUUPSUpgradeable + function setTimelockedAdmin(address newTimelockedAdmin) external onlyAdmin { + _getIBCUUPSUpgradeableStorage().timelockedAdmin = newTimelockedAdmin; + } + + /// @inheritdoc IIBCUUPSUpgradeable + function setGovAdmin(address newGovAdmin) external onlyAdmin { + _getIBCUUPSUpgradeableStorage().govAdmin = newGovAdmin; + } + + /// @inheritdoc IIBCUUPSUpgradeable + function isAdmin(address account) external view override returns (bool) { + IBCUUPSUpgradeableStorage storage $ = _getIBCUUPSUpgradeableStorage(); + return account == $.timelockedAdmin || account == $.govAdmin; + } + + /// @inheritdoc UUPSUpgradeable + function _authorizeUpgrade(address) internal view virtual override onlyAdmin { } + // solhint-disable-previous-line no-empty-blocks + + /// @notice Returns the storage of the IBCUpgradeable contract + function _getIBCUUPSUpgradeableStorage() internal pure returns (IBCUUPSUpgradeableStorage storage $) { + // solhint-disable-next-line no-inline-assembly + assembly { + $.slot := IBCUUPSUPGRADEABLE_STORAGE_SLOT + } + } + + modifier onlyAdmin() { + IBCUUPSUpgradeableStorage storage $ = _getIBCUUPSUpgradeableStorage(); + require(_msgSender() == $.timelockedAdmin || _msgSender() == $.govAdmin, Unauthorized()); + _; + } +} diff --git a/packages/relayer-lib/src/events/eureka.rs b/packages/relayer-lib/src/events/eureka.rs index fca5fc71..a8614c66 100644 --- a/packages/relayer-lib/src/events/eureka.rs +++ b/packages/relayer-lib/src/events/eureka.rs @@ -51,6 +51,7 @@ impl TryFrom for EurekaEvent { routerEvents::IBCAppAdded(_) => Err(anyhow::anyhow!("IBCAppAdded event")), routerEvents::ICS02ClientAdded(_) => Err(anyhow::anyhow!("ICS02ClientAdded event")), routerEvents::Initialized(_) => Err(anyhow::anyhow!("Initialized event")), + routerEvents::Upgraded(_) => Err(anyhow::anyhow!("Upgraded event")), routerEvents::RoleGranted(_) | routerEvents::RoleRevoked(_) | routerEvents::RoleAdminChanged(_) => Err(anyhow::anyhow!("Role events are not used")), diff --git a/scripts/E2ETestDeploy.s.sol b/scripts/E2ETestDeploy.s.sol index 8b854aca..1678affd 100644 --- a/scripts/E2ETestDeploy.s.sol +++ b/scripts/E2ETestDeploy.s.sol @@ -16,7 +16,7 @@ import { ICS20Transfer } from "../contracts/ICS20Transfer.sol"; import { TestERC20 } from "../test/solidity-ibc/mocks/TestERC20.sol"; import { Strings } from "@openzeppelin-contracts/utils/Strings.sol"; import { ICS20Lib } from "../contracts/utils/ICS20Lib.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { ERC1967Proxy } from "@openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { SP1Verifier as SP1VerifierPlonk } from "@sp1-contracts/v4.0.0-rc.3/SP1VerifierPlonk.sol"; import { SP1Verifier as SP1VerifierGroth16 } from "@sp1-contracts/v4.0.0-rc.3/SP1VerifierGroth16.sol"; import { SP1MockVerifier } from "@sp1-contracts/SP1MockVerifier.sol"; @@ -85,18 +85,17 @@ contract E2ETestDeploy is Script, IICS07TendermintMsgs { ICS26Router ics26RouterLogic = new ICS26Router(); ICS20Transfer ics20TransferLogic = new ICS20Transfer(); - TransparentUpgradeableProxy routerProxy = new TransparentUpgradeableProxy( + ERC1967Proxy routerProxy = new ERC1967Proxy( address(ics26RouterLogic), - address(this), abi.encodeWithSelector( ICS26Router.initialize.selector, + msg.sender, msg.sender ) ); - TransparentUpgradeableProxy transferProxy = new TransparentUpgradeableProxy( + ERC1967Proxy transferProxy = new ERC1967Proxy( address(ics20TransferLogic), - address(this), abi.encodeWithSelector( ICS20Transfer.initialize.selector, address(routerProxy) diff --git a/test/solidity-ibc/FixtureTest.t.sol b/test/solidity-ibc/FixtureTest.t.sol index a2bbbcab..2757c3ac 100644 --- a/test/solidity-ibc/FixtureTest.t.sol +++ b/test/solidity-ibc/FixtureTest.t.sol @@ -13,7 +13,7 @@ import { ICS20Transfer } from "../../contracts/ICS20Transfer.sol"; import { IICS07TendermintMsgs } from "../../contracts/light-clients/msgs/IICS07TendermintMsgs.sol"; import { ICS20Lib } from "../../contracts/utils/ICS20Lib.sol"; import { stdJson } from "forge-std/StdJson.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { ERC1967Proxy } from "@openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { SP1Verifier as SP1VerifierPlonk } from "@sp1-contracts/v4.0.0-rc.3/SP1VerifierPlonk.sol"; import { SP1Verifier as SP1VerifierGroth16 } from "@sp1-contracts/v4.0.0-rc.3/SP1VerifierGroth16.sol"; @@ -52,17 +52,14 @@ abstract contract FixtureTest is Test, IICS07TendermintMsgs { ICS26Router ics26RouterLogic = new ICS26Router(); ICS20Transfer ics20TransferLogic = new ICS20Transfer(); - // ============== Step 2: Deploy Transparent Proxies ============== - TransparentUpgradeableProxy routerProxy = new TransparentUpgradeableProxy( + // ============== Step 2: Deploy ERC1967 Proxies ============== + ERC1967Proxy routerProxy = new ERC1967Proxy( address(ics26RouterLogic), - address(this), - abi.encodeWithSelector(ICS26Router.initialize.selector, address(this)) + abi.encodeWithSelector(ICS26Router.initialize.selector, address(this), address(this)) ); - TransparentUpgradeableProxy transferProxy = new TransparentUpgradeableProxy( - address(ics20TransferLogic), - address(this), - abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(routerProxy)) + ERC1967Proxy transferProxy = new ERC1967Proxy( + address(ics20TransferLogic), abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(routerProxy)) ); // ============== Step 3: Wire up the contracts ============== diff --git a/test/solidity-ibc/IBCUUPSUpgradeableTest.t.sol b/test/solidity-ibc/IBCUUPSUpgradeableTest.t.sol new file mode 100644 index 000000000..27560821 --- /dev/null +++ b/test/solidity-ibc/IBCUUPSUpgradeableTest.t.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +// solhint-disable gas-custom-errors + +import { Test } from "forge-std/Test.sol"; +import { ILightClientMsgs } from "../../contracts/msgs/ILightClientMsgs.sol"; +import { IICS02ClientMsgs } from "../../contracts/msgs/IICS02ClientMsgs.sol"; +import { ICS26Router } from "../../contracts/ICS26Router.sol"; +import { ICS20Transfer } from "../../contracts/ICS20Transfer.sol"; +import { ICS20Lib } from "../../contracts/utils/ICS20Lib.sol"; +import { IICS20Errors } from "../../contracts/errors/IICS20Errors.sol"; +import { IIBCUUPSUpgradeableErrors } from "../../contracts/errors/IIBCUUPSUpgradeableErrors.sol"; +import { DummyLightClient } from "./mocks/DummyLightClient.sol"; +import { DummyInitializable, ErroneousInitializable } from "./mocks/DummyInitializable.sol"; +import { ERC1967Proxy } from "@openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +contract IBCUUPSUpgradeableTest is Test { + ICS26Router public ics26Router; + ICS20Transfer public ics20Transfer; + + string public counterpartyId = "42-dummy-01"; + bytes[] public merklePrefix = [bytes("ibc"), bytes("")]; + + function setUp() public { + // ============ Step 1: Deploy the logic contracts ============== + DummyLightClient lightClient = new DummyLightClient(ILightClientMsgs.UpdateResult.Update, 0, false); + ICS26Router ics26RouterLogic = new ICS26Router(); + ICS20Transfer ics20TransferLogic = new ICS20Transfer(); + + // ============== Step 2: Deploy ERC1967 Proxies ============== + ERC1967Proxy routerProxy = new ERC1967Proxy( + address(ics26RouterLogic), + abi.encodeWithSelector(ICS26Router.initialize.selector, address(this), address(this)) + ); + + ERC1967Proxy transferProxy = new ERC1967Proxy( + address(ics20TransferLogic), abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(routerProxy)) + ); + + // ============== Step 3: Wire up the contracts ============== + ics26Router = ICS26Router(address(routerProxy)); + ics20Transfer = ICS20Transfer(address(transferProxy)); + + ics26Router.addClient( + "07-tendermint", IICS02ClientMsgs.CounterpartyInfo(counterpartyId, merklePrefix), address(lightClient) + ); + ics26Router.addIBCApp(ICS20Lib.DEFAULT_PORT_ID, address(ics20Transfer)); + } + + function test_success_ics20_upgrade() public { + // ============== Step 4: Migrate the contracts ============== + DummyInitializable newLogic = new DummyInitializable(); + + ics20Transfer.upgradeToAndCall( + address(newLogic), abi.encodeWithSelector(DummyInitializable.initializeV2.selector) + ); + } + + function test_failure_ics20_upgrade() public { + // Case 1: Revert on failed initialization + ErroneousInitializable erroneousLogic = new ErroneousInitializable(); + + vm.expectRevert(abi.encodeWithSelector(ErroneousInitializable.InitializeFailed.selector)); + ics20Transfer.upgradeToAndCall( + address(erroneousLogic), abi.encodeWithSelector(DummyInitializable.initializeV2.selector) + ); + + // Case 2: Revert on unauthorized upgrade + DummyInitializable newLogic = new DummyInitializable(); + + address unauthorized = makeAddr("unauthorized"); + vm.prank(unauthorized); + vm.expectRevert(abi.encodeWithSelector(IICS20Errors.ICS20Unauthorized.selector, unauthorized)); + ics20Transfer.upgradeToAndCall( + address(newLogic), abi.encodeWithSelector(DummyInitializable.initializeV2.selector) + ); + } + + function test_success_ics26_upgrade() public { + // ============== Step 4: Migrate the contracts ============== + DummyInitializable newLogic = new DummyInitializable(); + + ics26Router.upgradeToAndCall( + address(newLogic), abi.encodeWithSelector(DummyInitializable.initializeV2.selector) + ); + } + + function test_failure_ics26_upgrade() public { + // Case 1: Revert on failed initialization + ErroneousInitializable erroneousLogic = new ErroneousInitializable(); + + vm.expectRevert(abi.encodeWithSelector(ErroneousInitializable.InitializeFailed.selector)); + ics26Router.upgradeToAndCall( + address(erroneousLogic), abi.encodeWithSelector(DummyInitializable.initializeV2.selector) + ); + + // Case 2: Revert on unauthorized upgrade + DummyInitializable newLogic = new DummyInitializable(); + + address unauthorized = makeAddr("unauthorized"); + vm.prank(unauthorized); + vm.expectRevert(abi.encodeWithSelector(IIBCUUPSUpgradeableErrors.Unauthorized.selector)); + ics26Router.upgradeToAndCall( + address(newLogic), abi.encodeWithSelector(DummyInitializable.initializeV2.selector) + ); + } + + function test_success_setGovAdmin() public { + address govAdmin = makeAddr("govAdmin"); + + ics26Router.setGovAdmin(govAdmin); + assertEq(ics26Router.getGovAdmin(), govAdmin); + + // Have the govAdmin change the govAdmin + address newGovAdmin = makeAddr("newGovAdmin"); + ics26Router.setGovAdmin(newGovAdmin); + assertEq(ics26Router.getGovAdmin(), newGovAdmin); + } + + function test_failure_setGovAdmin() public { + address unauthorized = makeAddr("unauthorized"); + address govAdmin = makeAddr("govAdmin"); + + vm.prank(unauthorized); + vm.expectRevert(abi.encodeWithSelector(IIBCUUPSUpgradeableErrors.Unauthorized.selector)); + ics26Router.setGovAdmin(govAdmin); + } + + function test_success_setTimelockedAdmin() public { + address newTimelockedAdmin = makeAddr("timelockedAdmin"); + + ics26Router.setTimelockedAdmin(newTimelockedAdmin); + assertEq(ics26Router.getTimelockedAdmin(), newTimelockedAdmin); + } + + function test_failure_setTimelockedAdmin() public { + address unauthorized = makeAddr("unauthorized"); + address newTimelockedAdmin = makeAddr("timelockedAdmin"); + + vm.prank(unauthorized); + vm.expectRevert(abi.encodeWithSelector(IIBCUUPSUpgradeableErrors.Unauthorized.selector)); + ics26Router.setTimelockedAdmin(newTimelockedAdmin); + } +} diff --git a/test/solidity-ibc/ICS02ClientTest.t.sol b/test/solidity-ibc/ICS02ClientTest.t.sol index 1ba37ae9..d65acd83 100644 --- a/test/solidity-ibc/ICS02ClientTest.t.sol +++ b/test/solidity-ibc/ICS02ClientTest.t.sol @@ -10,7 +10,7 @@ import { IICS02ClientMsgs } from "../../contracts/msgs/IICS02ClientMsgs.sol"; import { ILightClient } from "../../contracts/interfaces/ILightClient.sol"; import { ILightClientMsgs } from "../../contracts/msgs/ILightClientMsgs.sol"; import { DummyLightClient } from "./mocks/DummyLightClient.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { ERC1967Proxy } from "@openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { IAccessControl } from "@openzeppelin-contracts/access/IAccessControl.sol"; import { ICS26Router } from "../../contracts/ICS26Router.sol"; @@ -29,10 +29,9 @@ contract ICS02ClientTest is Test { ICS26Router ics26RouterLogic = new ICS26Router(); lightClient = new DummyLightClient(ILightClientMsgs.UpdateResult.Update, 0, false); - TransparentUpgradeableProxy routerProxy = new TransparentUpgradeableProxy( + ERC1967Proxy routerProxy = new ERC1967Proxy( address(ics26RouterLogic), - address(this), - abi.encodeWithSelector(ICS26Router.initialize.selector, address(this)) + abi.encodeWithSelector(ICS26Router.initialize.selector, address(this), address(this)) ); ics02Client = ICS02ClientUpgradeable(address(routerProxy)); diff --git a/test/solidity-ibc/ICS26RouterTest.t.sol b/test/solidity-ibc/ICS26RouterTest.t.sol index 71137a42..3d97338c 100644 --- a/test/solidity-ibc/ICS26RouterTest.t.sol +++ b/test/solidity-ibc/ICS26RouterTest.t.sol @@ -14,7 +14,7 @@ import { ICS20Lib } from "../../contracts/utils/ICS20Lib.sol"; import { Strings } from "@openzeppelin-contracts/utils/Strings.sol"; import { DummyLightClient } from "./mocks/DummyLightClient.sol"; import { ILightClientMsgs } from "../../contracts/msgs/ILightClientMsgs.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { ERC1967Proxy } from "@openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract ICS26RouterTest is Test { ICS26Router public ics26Router; @@ -24,10 +24,9 @@ contract ICS26RouterTest is Test { function setUp() public { ICS26Router ics26RouterLogic = new ICS26Router(); - TransparentUpgradeableProxy routerProxy = new TransparentUpgradeableProxy( + ERC1967Proxy routerProxy = new ERC1967Proxy( address(ics26RouterLogic), - address(this), - abi.encodeWithSelector(ICS26Router.initialize.selector, address(this)) + abi.encodeWithSelector(ICS26Router.initialize.selector, address(this), address(this)) ); ics26Router = ICS26Router(address(routerProxy)); @@ -62,10 +61,8 @@ contract ICS26RouterTest is Test { ); ICS20Transfer ics20TransferLogic = new ICS20Transfer(); - TransparentUpgradeableProxy transferProxy = new TransparentUpgradeableProxy( - address(ics20TransferLogic), - address(this), - abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(ics26Router)) + ERC1967Proxy transferProxy = new ERC1967Proxy( + address(ics20TransferLogic), abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(ics26Router)) ); ICS20Transfer ics20Transfer = ICS20Transfer(address(transferProxy)); ics26Router.addIBCApp(ICS20Lib.DEFAULT_PORT_ID, address(ics20Transfer)); diff --git a/test/solidity-ibc/IntegrationTest.t.sol b/test/solidity-ibc/IntegrationTest.t.sol index 87fc46e8..84ba1798 100644 --- a/test/solidity-ibc/IntegrationTest.t.sol +++ b/test/solidity-ibc/IntegrationTest.t.sol @@ -18,7 +18,7 @@ import { ILightClientMsgs } from "../../contracts/msgs/ILightClientMsgs.sol"; import { ICS20Lib } from "../../contracts/utils/ICS20Lib.sol"; import { ICS24Host } from "../../contracts/utils/ICS24Host.sol"; import { Strings } from "@openzeppelin-contracts/utils/Strings.sol"; -import { TransparentUpgradeableProxy } from "@openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { ERC1967Proxy } from "@openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract IntegrationTest is Test { ICS26Router public ics26Router; @@ -49,16 +49,13 @@ contract IntegrationTest is Test { ICS20Transfer ics20TransferLogic = new ICS20Transfer(); // ============== Step 2: Deploy Transparent Proxies ============== - TransparentUpgradeableProxy routerProxy = new TransparentUpgradeableProxy( + ERC1967Proxy routerProxy = new ERC1967Proxy( address(ics26RouterLogic), - address(this), - abi.encodeWithSelector(ICS26Router.initialize.selector, address(this)) + abi.encodeWithSelector(ICS26Router.initialize.selector, address(this), address(this)) ); - TransparentUpgradeableProxy transferProxy = new TransparentUpgradeableProxy( - address(ics20TransferLogic), - address(this), - abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(routerProxy)) + ERC1967Proxy transferProxy = new ERC1967Proxy( + address(ics20TransferLogic), abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(routerProxy)) ); // ============== Step 3: Wire up the contracts ============== diff --git a/test/solidity-ibc/MigrationTest.t.sol b/test/solidity-ibc/MigrationTest.t.sol deleted file mode 100644 index e33e7141..000000000 --- a/test/solidity-ibc/MigrationTest.t.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.28; - -// solhint-disable gas-custom-errors - -import { Test } from "forge-std/Test.sol"; -import { ILightClientMsgs } from "../../contracts/msgs/ILightClientMsgs.sol"; -import { IICS02ClientMsgs } from "../../contracts/msgs/IICS02ClientMsgs.sol"; -import { ICS26Router } from "../../contracts/ICS26Router.sol"; -import { ICS20Transfer } from "../../contracts/ICS20Transfer.sol"; -import { ICS20Lib } from "../../contracts/utils/ICS20Lib.sol"; -import { TestERC20 } from "./mocks/TestERC20.sol"; -import { IICS26Router } from "../../contracts/interfaces/IICS26Router.sol"; -import { DummyLightClient } from "./mocks/DummyLightClient.sol"; -import { DummyInitializable, ErroneousInitializable } from "./mocks/DummyInitializable.sol"; -import { - TransparentUpgradeableProxy, - ITransparentUpgradeableProxy -} from "@openzeppelin-contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { ProxyAdmin } from "@openzeppelin-contracts/proxy/transparent/ProxyAdmin.sol"; -import { IERC1967 } from "@openzeppelin-contracts/interfaces/IERC1967.sol"; -import { VmSafe } from "forge-std/Vm.sol"; - -contract MigrationTest is Test { - DummyLightClient public lightClient; - ICS26Router public ics26Router; - ICS20Transfer public ics20Transfer; - TestERC20 public erc20; - string public clientIdentifier; - ProxyAdmin public transferProxyAdmin; - - string public counterpartyId = "42-dummy-01"; - bytes[] public merklePrefix = [bytes("ibc"), bytes("")]; - - function setUp() public { - // ============ Step 1: Deploy the logic contracts ============== - lightClient = new DummyLightClient(ILightClientMsgs.UpdateResult.Update, 0, false); - ICS26Router ics26RouterLogic = new ICS26Router(); - ICS20Transfer ics20TransferLogic = new ICS20Transfer(); - - // ============== Step 2: Deploy Transparent Proxies ============== - vm.recordLogs(); - - TransparentUpgradeableProxy routerProxy = new TransparentUpgradeableProxy( - address(ics26RouterLogic), - address(this), - abi.encodeWithSelector(ICS26Router.initialize.selector, address(this)) - ); - - TransparentUpgradeableProxy transferProxy = new TransparentUpgradeableProxy( - address(ics20TransferLogic), - address(this), - abi.encodeWithSelector(ICS20Transfer.initialize.selector, address(routerProxy)) - ); - - transferProxyAdmin = ProxyAdmin(_getAdminFromLogs(vm.getRecordedLogs(), address(transferProxy))); - - // ============== Step 3: Wire up the contracts ============== - ics26Router = ICS26Router(address(routerProxy)); - ics20Transfer = ICS20Transfer(address(transferProxy)); - erc20 = new TestERC20(); - - clientIdentifier = ics26Router.addClient( - "07-tendermint", IICS02ClientMsgs.CounterpartyInfo(counterpartyId, merklePrefix), address(lightClient) - ); - - vm.expectEmit(); - emit IICS26Router.IBCAppAdded(ICS20Lib.DEFAULT_PORT_ID, address(ics20Transfer)); - ics26Router.addIBCApp(ICS20Lib.DEFAULT_PORT_ID, address(ics20Transfer)); - - assertEq(address(ics20Transfer), address(ics26Router.getIBCApp(ICS20Lib.DEFAULT_PORT_ID))); - } - - function test_success_upgrade() public { - // ============== Step 4: Migrate the contracts ============== - DummyInitializable newLogic = new DummyInitializable(); - - transferProxyAdmin.upgradeAndCall( - ITransparentUpgradeableProxy(address(ics20Transfer)), - address(newLogic), - abi.encodeWithSelector(DummyInitializable.initializeV2.selector) - ); - } - - function test_failure_upgrade() public { - // ============== Step 4: Migrate the contracts ============== - ErroneousInitializable newLogic = new ErroneousInitializable(); - - vm.expectRevert(abi.encodeWithSelector(ErroneousInitializable.InitializeFailed.selector)); - transferProxyAdmin.upgradeAndCall( - ITransparentUpgradeableProxy(address(ics20Transfer)), - address(newLogic), - abi.encodeWithSelector(DummyInitializable.initializeV2.selector) - ); - } - - function _getAdminFromLogs(VmSafe.Log[] memory logs, address emitter) internal pure returns (address) { - for (uint256 i = 0; i < logs.length; i++) { - if (logs[i].emitter == emitter && logs[i].topics[0] == IERC1967.AdminChanged.selector) { - (, address newAdmin) = abi.decode(logs[i].data, (address, address)); - return newAdmin; - } - } - revert("Admin not found"); - } -} diff --git a/test/solidity-ibc/mocks/DummyInitializable.sol b/test/solidity-ibc/mocks/DummyInitializable.sol index 414ba921..240d841b 100644 --- a/test/solidity-ibc/mocks/DummyInitializable.sol +++ b/test/solidity-ibc/mocks/DummyInitializable.sol @@ -4,15 +4,20 @@ pragma solidity ^0.8.28; // solhint-disable no-empty-blocks import { Initializable } from "@openzeppelin-contracts/proxy/utils/Initializable.sol"; +import { UUPSUpgradeable } from "@openzeppelin-contracts/proxy/utils/UUPSUpgradeable.sol"; -contract DummyInitializable is Initializable { +contract DummyInitializable is Initializable, UUPSUpgradeable { function initializeV2() public reinitializer(2) { } + + function _authorizeUpgrade(address) internal override { } } -contract ErroneousInitializable is Initializable { +contract ErroneousInitializable is Initializable, UUPSUpgradeable { error InitializeFailed(); function initializeV2() public reinitializer(2) { revert InitializeFailed(); } + + function _authorizeUpgrade(address) internal override { } }