diff --git a/test/Dispatcher/Dispatcher.multiclient.sol b/test/Dispatcher/Dispatcher.multiclient.sol index d8c90006..0ed301ee 100644 --- a/test/Dispatcher/Dispatcher.multiclient.sol +++ b/test/Dispatcher/Dispatcher.multiclient.sol @@ -4,16 +4,15 @@ pragma solidity ^0.8.15; import "../../contracts/libs/Ibc.sol"; import {IbcUtils} from "../../contracts/libs/IbcUtils.sol"; import {Mars} from "../../contracts/examples/Mars.sol"; -import {DispatcherProofTestUtils} from "./Dispatcher.proof.t.sol"; +import {Base} from "../utils/Dispatcher.base.t.sol"; import {DummyLightClient} from "../../contracts/utils/DummyLightClient.sol"; import {OptimisticLightClient} from "../../contracts/core/OptimisticLightClient.sol"; import {ILightClient} from "../../contracts/interfaces/ILightClient.sol"; import "../../contracts/interfaces/IProofVerifier.sol"; -contract DispatcherRealProofMultiClient is DispatcherProofTestUtils { +contract DispatcherRealProofMultiClient is Base { string[] connectionHops0 = ["dummy-connection-1", "dummy-connection-2"]; string[] connectionHops1 = ["connection-2", "connection-1"]; - // string[] connectionHops1 = ["op-connection-1", "op-connection-2"]; Mars mars; address notOwner = vm.addr(1); ChannelEnd ch0 = diff --git a/test/Dispatcher/Dispatcher.proof.t.sol b/test/Dispatcher/Dispatcher.proof.t.sol index a93d11ea..4158556d 100644 --- a/test/Dispatcher/Dispatcher.proof.t.sol +++ b/test/Dispatcher/Dispatcher.proof.t.sol @@ -15,26 +15,7 @@ import {ChannelHandshakeSetting} from "../utils/Dispatcher.base.t.sol"; import {DummyLightClient} from "../../contracts/utils/DummyLightClient.sol"; import {DispatcherSendPacketTestSuite, ChannelOpenTestBaseSetup} from "./Dispatcher.t.sol"; -contract DispatcherProofTestUtils is Base { - using stdStorage for StdStorage; - - function load_proof(string memory filepath) internal returns (Ics23Proof memory) { - (bytes32 apphash, Ics23Proof memory proof) = - abi.decode(vm.parseBytes(vm.readFile(string.concat(rootDir, filepath))), (bytes32, Ics23Proof)); - - // this loads the app hash we got from the testing data into the consensus state manager internals - // at the height it's supposed to go. That is, a block less than where the proof was generated from. - stdstore.target(address(opLightClient)).sig("consensusStates(uint256)").with_key(proof.height - 1).checked_write( - apphash - ); - // trick the fraud time window check - vm.warp(block.timestamp + 1); - - return proof; - } -} - -abstract contract DispatcherIbcWithRealProofsSuite is IbcEventsEmitter, DispatcherProofTestUtils { +abstract contract DispatcherIbcWithRealProofsSuite is IbcEventsEmitter, Base { Mars mars; ChannelEnd ch0; @@ -60,7 +41,7 @@ abstract contract DispatcherIbcWithRealProofsSuite is IbcEventsEmitter, Dispatch dispatcherProxy.channelOpenTry(ch1, ChannelOrder.NONE, false, connectionHops1, ch0, proof); } - function test_ibc_channel_ack_123_a() public { + function test_ibc_channel_ack() public { Ics23Proof memory proof = load_proof("/test/payload/channel_ack_pending_proof.hex"); vm.expectEmit(true, true, true, true); diff --git a/test/Dispatcher/Dispatcher.t.sol b/test/Dispatcher/Dispatcher.t.sol index c4812dbc..17e68c7d 100644 --- a/test/Dispatcher/Dispatcher.t.sol +++ b/test/Dispatcher/Dispatcher.t.sol @@ -9,7 +9,7 @@ import {IbcReceiver} from "../../contracts/interfaces/IbcReceiver.sol"; import {DummyLightClient} from "../../contracts/utils/DummyLightClient.sol"; import "../../contracts/examples/Mars.sol"; import "../../contracts/core/OptimisticLightClient.sol"; -import "../utils/Dispatcher.base.t.sol"; +import {LocalEnd, ChannelHandshakeSetting, Base} from "../utils/Dispatcher.base.t.sol"; import {Earth} from "../../contracts/examples/Earth.sol"; abstract contract ChannelHandshakeUtils is Base { @@ -293,11 +293,6 @@ contract PacketSenderTestBase is ChannelOpenTestBaseSetup { function genPacket(uint64 packetSeq) internal view returns (IbcPacket memory) { return IbcPacket(src, dest, packetSeq, payload, ZERO_HEIGHT, maxTimeout); } - - // genAckPacket generates an ack packet for the given packet sequence - function genAckPacket(string memory packetSeq) internal pure returns (bytes memory) { - return ackToBytes(AckPacket(true, bytes(packetSeq))); - } } // Test Chains B receives a packet from Chain A diff --git a/test/upgradeableProxy/Dispatcher.upgrade.t.sol b/test/upgradeableProxy/Dispatcher.upgrade.t.sol index 30577517..8ef41781 100644 --- a/test/upgradeableProxy/Dispatcher.upgrade.t.sol +++ b/test/upgradeableProxy/Dispatcher.upgrade.t.sol @@ -9,19 +9,35 @@ import "../../contracts/core/OptimisticLightClient.sol"; import {ChannelHandshakeTestSuite, ChannelHandshakeTest, ChannelHandshakeUtils} from "../Dispatcher/Dispatcher.t.sol"; import {LocalEnd} from "../utils/Dispatcher.base.t.sol"; import {Base, ChannelHandshakeSetting} from "../utils/Dispatcher.base.t.sol"; -import {ChannelEnd, ChannelOrder, IbcEndpoint, IbcPacket, AckPacket, Ibc, Height} from "../../contracts/libs/Ibc.sol"; +import { + ChannelEnd, + ChannelOrder, + ChannelState, + IbcEndpoint, + IbcPacket, + AckPacket, + Ibc, + Height +} from "../../contracts/libs/Ibc.sol"; import {IbcUtils} from "../../contracts/libs/IbcUtils.sol"; -import {IbcReceiver} from "../../contracts/interfaces/IbcReceiver.sol"; +import {IbcReceiver, IbcChannelReceiver} from "../../contracts/interfaces/IbcReceiver.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import {OptimisticLightClient} from "../../contracts/core/OptimisticLightClient.sol"; import {IProofVerifier} from "../../contracts/core/OptimisticProofVerifier.sol"; import {DummyLightClient} from "../../contracts/utils/DummyLightClient.sol"; import {IDispatcher} from "../../contracts/interfaces/IDispatcher.sol"; +import {DispatcherRc4} from "./upgrades/DispatcherRc4.sol"; import {DispatcherV2Initializable} from "./upgrades/DispatcherV2Initializable.sol"; import {DispatcherV2} from "./upgrades/DispatcherV2.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; abstract contract UpgradeTestUtils { + string[] connectionHops0 = ["dummy-connection-1", "dummy-connection-2"]; + string[] connectionHops1 = ["connection-1", "connection-2"]; + LocalEnd _localDummy; + ChannelEnd _remoteDummy; + function upgradeDispatcher(string memory portPrefix, address dispatcherProxy) public returns (DispatcherV2Initializable newDispatcherImplementation) @@ -31,11 +47,22 @@ abstract contract UpgradeTestUtils { bytes memory initData = abi.encodeWithSignature("initialize(string)", portPrefix); UUPSUpgradeable(dispatcherProxy).upgradeToAndCall(address(newDispatcherImplementation), initData); } + + function deployDispatcherRC4ProxyAndImpl(string memory initPortPrefix, ILightClient initLightClient) + public + returns (IDispatcher proxy) + { + DispatcherRc4 dispatcherImplementation = new DispatcherRc4(); + bytes memory initData = + abi.encodeWithSelector(DispatcherRc4.initialize.selector, initPortPrefix, initLightClient); + proxy = IDispatcher(address(new ERC1967Proxy(address(dispatcherImplementation), initData))); + } } contract ChannelHandShakeUpgradeUtil is ChannelHandshakeUtils { uint32 nextSequenceSendSlot = 153; uint32 sendPacketCommitmentSlot = 156; + uint32 ackPacketCommitmentSlot = 158; uint32 nextSequenceAckSlot = 155; uint32 nextSequenceRecvSlot = 154; IbcPacket[3] packets; @@ -43,36 +70,45 @@ contract ChannelHandShakeUpgradeUtil is ChannelHandshakeUtils { bytes packet = abi.encodePacked(payload); uint64 timeoutTimestamp = 1000; - function doChannelHandshake() public { + // Conduct 4-step channel handshake between localChannelEnd and remoteChannelEnd end + // Have to pass in receivingDapp because it's hard to parse out the addresss from the portId + function doChannelHandshake(LocalEnd memory localEnd, ChannelEnd memory remoteEnd) public { // same setup as that run in test_connectChannel_ok ChannelHandshakeSetting[8] memory settings = createSettings2(true); string[2] memory versions = ["1.0", "2.0"]; for (uint256 i = 0; i < settings.length; i++) { for (uint256 j = 0; j < versions.length; j++) { - LocalEnd memory le = _local; - ChannelEnd memory re = _remote; - le.versionCall = versions[j]; - le.versionExpected = versions[j]; - re.version = versions[j]; - channelOpenInit(le, re, settings[i], true); - channelOpenTry(le, re, settings[i], true); - channelOpenAck(le, re, settings[i], true); - channelOpenConfirm(le, re, settings[i], true); + localEnd.versionCall = versions[j]; + localEnd.versionExpected = versions[j]; + remoteEnd.version = versions[j]; + channelOpenInit(localEnd, remoteEnd, settings[i], true); + channelOpenTry(localEnd, remoteEnd, settings[i], true); + channelOpenAck(localEnd, remoteEnd, settings[i], true); + channelOpenConfirm(localEnd, remoteEnd, settings[i], true); } } } - function sendOnePacket(bytes32 channelId, uint64 packetSeq) public { + function doProofChannelHandshake(LocalEnd memory localEnd, ChannelEnd memory remoteEnd) public { + ChannelHandshakeSetting memory setting = ChannelHandshakeSetting(ChannelOrder.ORDERED, false, true, validProof); + + channelOpenInit(localEnd, remoteEnd, setting, true); + channelOpenTry(localEnd, remoteEnd, setting, true); + channelOpenAck(localEnd, remoteEnd, setting, true); + channelOpenConfirm(localEnd, remoteEnd, setting, true); + } + + function sendOnePacket(bytes32 channelId, uint64 packetSeq, Mars sender) public { vm.expectEmit(true, true, true, true); - emit SendPacket(address(mars), channelId, packet, packetSeq, timeoutTimestamp); - mars.greet(payload, channelId, timeoutTimestamp); + emit SendPacket(address(sender), channelId, packet, packetSeq, timeoutTimestamp); + sender.greet(payload, channelId, timeoutTimestamp); } function sendPacket(bytes32 channelId) public { for (uint64 index = 0; index < 3; index++) { uint64 packetSeq = index + 1; - sendOnePacket(channelId, packetSeq); + sendOnePacket(channelId, packetSeq, mars); IbcEndpoint memory dest = IbcEndpoint("polyibc.bsc.9876543210", "channel-99"); string memory marsPort = string(abi.encodePacked(portPrefix, getHexBytes(address(mars)))); IbcEndpoint memory src = IbcEndpoint(marsPort, channelId); @@ -87,7 +123,7 @@ contract ChannelHandShakeUpgradeUtil is ChannelHandshakeUtils { slot = keccak256(abi.encode(channelId, slot1)); } - function findPacketCommitmentSlot(address portAddress, bytes32 channelId, uint64 sequence) + function findSendPacketCommitmentSlot(address portAddress, bytes32 channelId, uint64 sequence) public view returns (bytes32 slot) @@ -97,6 +133,16 @@ contract ChannelHandShakeUpgradeUtil is ChannelHandshakeUtils { slot = keccak256(abi.encode(sequence, slot2)); } + function findAckPacketCommitmentSlot(address portAddress, bytes32 channelId, uint64 sequence) + public + view + returns (bytes32 slot) + { + bytes32 slot1 = keccak256(abi.encode(portAddress, ackPacketCommitmentSlot)); + bytes32 slot2 = keccak256(abi.encode(channelId, slot1)); + slot = keccak256(abi.encode(sequence, slot2)); + } + function findNextSequenceAck(address portAddress, bytes32 channelId) public view returns (bytes32 slot) { bytes32 slot1 = keccak256(abi.encode(portAddress, nextSequenceAckSlot)); slot = keccak256(abi.encode(channelId, slot1)); @@ -110,15 +156,18 @@ contract ChannelHandShakeUpgradeUtil is ChannelHandshakeUtils { contract DispatcherUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils { function setUp() public override { + address targetMarsAddress = 0x71C95911E9a5D330f4D621842EC243EE1343292e; (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix); + deployCodeTo("contracts/examples/Mars.sol:Mars", abi.encode(address(dispatcherProxy)), targetMarsAddress); dispatcherProxy.setClientForConnection(connectionHops[0], dummyLightClient); mars = new Mars(dispatcherProxy); - portId = IbcUtils.addressToPortId(portPrefix, address(mars)); - _local = LocalEnd(mars, portId, "channel-1", connectionHops, "1.0", "1.0"); - _remote = ChannelEnd("eth2.7E5F4552091A69125d5DfCb7b8C2659029395Bdf", "channel-2", "1.0"); + string memory sendingPortId = IbcUtils.addressToPortId(portPrefix, address(mars)); + string memory receivingPortId = IbcUtils.addressToPortId(portPrefix, targetMarsAddress); + _local = LocalEnd(mars, sendingPortId, "channel-1", connectionHops, "1.0", "1.0"); + _remote = ChannelEnd(receivingPortId, "channel-2", "1.0"); // Add state to test if impacted by upgrade - doChannelHandshake(); + doChannelHandshake(_local, _remote); sendPacket(_local.channelId); // Upgrade dispatcherProxy for tests @@ -126,7 +175,6 @@ contract DispatcherUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils } function test_SentPacketState_Conserved() public { - // Check packet state in sendPacketCommitment()[] uint64 nextSequenceSendValue = uint64( uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _local.channelId))) ); @@ -134,13 +182,13 @@ contract DispatcherUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils assertEq(4, nextSequenceSendValue); // packets - assert(vm.load(address(dispatcherProxy), findPacketCommitmentSlot(address(mars), _local.channelId, 1)) > 0); - assert(vm.load(address(dispatcherProxy), findPacketCommitmentSlot(address(mars), _local.channelId, 2)) > 0); - assert(vm.load(address(dispatcherProxy), findPacketCommitmentSlot(address(mars), _local.channelId, 3)) > 0); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 1)) > 0); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 2)) > 0); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 3)) > 0); // Test sending packet with the updated contract - sendOnePacket(_local.channelId, 4); - assert(vm.load(address(dispatcherProxy), findPacketCommitmentSlot(address(mars), _local.channelId, 4)) > 0); + sendOnePacket(_local.channelId, 4, mars); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 4)) > 0); uint64 nextSequenceSendAfterSending = uint64( uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _local.channelId))) ); diff --git a/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol b/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol new file mode 100644 index 00000000..ff854e20 --- /dev/null +++ b/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/console2.sol"; +import {DispatcherUpdateClientTestSuite} from "../Dispatcher/Dispatcher.client.t.sol"; +import {DispatcherIbcWithRealProofsSuite} from "../Dispatcher/Dispatcher.proof.t.sol"; +import {Mars} from "../../contracts/examples/Mars.sol"; +import "../../contracts/core/OptimisticLightClient.sol"; +import {ChannelHandshakeTestSuite, ChannelHandshakeTest, ChannelHandshakeUtils} from "../Dispatcher/Dispatcher.t.sol"; +import {LocalEnd} from "../utils/Dispatcher.base.t.sol"; +import {Base, ChannelHandshakeSetting} from "../utils/Dispatcher.base.t.sol"; +import { + ChannelEnd, + ChannelOrder, + ChannelState, + IbcEndpoint, + IbcPacket, + AckPacket, + Ibc, + Height +} from "../../contracts/libs/Ibc.sol"; +import {IbcUtils} from "../../contracts/libs/IbcUtils.sol"; +import {IbcReceiver} from "../../contracts/interfaces/IbcReceiver.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; +import {OptimisticLightClient} from "../../contracts/core/OptimisticLightClient.sol"; +import {IProofVerifier} from "../../contracts/core/OptimisticProofVerifier.sol"; +import {DummyLightClient} from "../../contracts/utils/DummyLightClient.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {IDispatcher} from "../../contracts/interfaces/IDispatcher.sol"; + +import {ChannelHandShakeUpgradeUtil, UpgradeTestUtils} from "./Dispatcher.upgrade.t.sol"; +import {IDispatcherRc4, DispatcherRc4} from "./upgrades/DispatcherRc4.sol"; + +// Tests to ensure that the upgrade between rc4 -> preaudit fixes doesn't break the state of the contract +contract DispatcherRC4UpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils { + Mars receivingMars; + Mars dummyMars; + IDispatcher oldDummyDispatcherProxy; + + function setUp() public override { + // In Rc4 version, there can only be one dispatcher per light client so we deploy multiple clients + // Deploy dummy old dispathcer + oldDummyDispatcherProxy = deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient); + + // Deploy op old dispatcher + DummyLightClient dummyLightClient2 = new DummyLightClient(); // dummyLightClient2 models the op light client in + // prod - it will be the light client that is chosen for the upgrade (and the oldDummyDispatcherProxy will + // be deprecated) + dispatcherProxy = deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient2); + + // Set up dispatcher with non-trivial state + mars = new Mars(dispatcherProxy); + receivingMars = new Mars(dispatcherProxy); + string memory sendingPortId = IbcUtils.addressToPortId(portPrefix, address(mars)); + string memory receivingPortId = IbcUtils.addressToPortId(portPrefix, address(receivingMars)); + _local = LocalEnd(mars, sendingPortId, "channel-1", connectionHops1, "1.0", "1.0"); + _remote = ChannelEnd(receivingPortId, "channel-2", "1.0"); + + // Should now be able to able to open a connection without proofs on the upgraded dispatcherproxy now + _localDummy = LocalEnd(mars, sendingPortId, "dummy-channel-1", connectionHops0, "1.0", "1.0"); + _remoteDummy = ChannelEnd(receivingPortId, "dummy-channel-2", "1.0"); + + // Add state to test if impacted by upgrade + doProofChannelHandshake(_local, _remote); + sendPacket(_local.channelId); + + // Upgrade dispatcherProxy for tests + upgradeDispatcher(portPrefix, address(dispatcherProxy)); + dispatcherProxy.setClientForConnection(connectionHops0[0], dummyLightClient2); + dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient2); + } + + function test_SentPacketState_Conserved_RC4_Upgrade() public { + // Check packet state in sendPacketCommitment()[] + uint64 nextSequenceSendValue = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _local.channelId))) + ); + + assertEq(4, nextSequenceSendValue); + + // Packets + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 1)) > 0); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 2)) > 0); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 3)) > 0); + + // Test sending packet with the updated contract + sendOnePacket(_local.channelId, 4, mars); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 4)) > 0); + uint64 nextSequenceSendAfterSending = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _local.channelId))) + ); + assertEq(5, nextSequenceSendAfterSending); + } + + function test_OpenChannelState_Conserved_RC4Upgrade() public { + // State should be conserved after upgrade + uint64 nextSequenceRecvValue = + uint64(uint256(vm.load(address(dispatcherProxy), findNextSequenceRecv(address(mars), _local.channelId)))); + uint64 nextSequenceAckValue = + uint64(uint256(vm.load(address(dispatcherProxy), findNextSequenceAck(address(mars), _local.channelId)))); + + assertEq(1, nextSequenceRecvValue); + assertEq(1, nextSequenceAckValue); + + // Should be able to do the channel handshake and send a packet from the dummy client + doChannelHandshake(_localDummy, _remoteDummy); + sendOnePacket(_localDummy.channelId, 1, mars); + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 1)) > 0); + uint64 nextSequenceSendAfterSendingDummy = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _localDummy.channelId))) + ); + assertEq(2, nextSequenceSendAfterSendingDummy); + + // Should be able to open a channel with another contract after upgrade through optimistic light client + Mars mars2 = new Mars(dispatcherProxy); + + string memory portId2 = IbcUtils.addressToPortId(portPrefix, address(mars2)); + LocalEnd memory _local2 = LocalEnd(mars2, portId2, "channel-1", connectionHops1, "1.0", "1.0"); + ChannelHandshakeSetting memory setting = ChannelHandshakeSetting(ChannelOrder.ORDERED, false, false, validProof); + + channelOpenTry(_local2, _remote, setting, false); + + // Another dapp should be able to initialize another channel and send a packet from the new channel + doProofChannelHandshake(_local2, _remote); + sendOnePacket(_local2.channelId, 1, mars2); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars2), _local2.channelId, 1)) > 0 + ); + uint64 nextSequenceSendAfterSending = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars2), _local2.channelId))) + ); + assertEq(2, nextSequenceSendAfterSending); + } +} + +// Contract to test that state upgrades within mappings are preserved . +contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils { + Mars receivingMars; + LocalEnd _re; + ChannelEnd _le; + string sendingPortId; + string receivingPortId; + DummyLightClient dummyLightClient2; + + function setUp() public override { + ChannelHandshakeSetting memory setting = ChannelHandshakeSetting(ChannelOrder.ORDERED, false, true, validProof); + + DispatcherRc4 oldOpDispatcherImplementation = new DispatcherRc4(); + bytes memory initData = abi.encodeWithSelector(DispatcherRc4.initialize.selector, portPrefix, dummyLightClient); + dispatcherProxy = IDispatcher(address(new ERC1967Proxy(address(oldOpDispatcherImplementation), initData))); + + dummyLightClient2 = new DummyLightClient(); + + mars = new Mars(dispatcherProxy); + receivingMars = new Mars(dispatcherProxy); + + sendingPortId = IbcUtils.addressToPortId(portPrefix, address(mars)); + receivingPortId = IbcUtils.addressToPortId(portPrefix, address(receivingMars)); + // LocalEnd version of _remote + _re = LocalEnd(receivingMars, receivingPortId, "channel-2", connectionHops1, "1.0", "1.0"); + // ChannelEnd version of _local + _le = ChannelEnd(sendingPortId, "channel-1", "1.0"); + _local = LocalEnd(mars, sendingPortId, "channel-1", connectionHops1, "1.0", "1.0"); + _remote = ChannelEnd(receivingPortId, "channel-2", "1.0"); + + // Do only half a handshake to test upgrading between handshakes + channelOpenInit(_local, _remote, setting, true); + + channelOpenTry(_re, _le, setting, true); + } + + // Test that channel handshake can be finished even if done during an upgrade + function test_UpgradeBetween_ChannelOpen() public { + upgradeDispatcher(portPrefix, address(dispatcherProxy)); + dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient2); + ChannelHandshakeSetting memory setting = ChannelHandshakeSetting(ChannelOrder.ORDERED, false, true, validProof); + channelOpenAck(_local, _remote, setting, true); + channelOpenConfirm(_re, _le, setting, true); + } + + // Test that packet sending can be finished even if done during an upgade + function test_UpgradeBetween_SentPacketState() public { + // Finish up channel handshake so that we can send packet + ChannelHandshakeSetting memory setting = ChannelHandshakeSetting(ChannelOrder.ORDERED, false, true, validProof); + channelOpenAck(_local, _remote, setting, true); + channelOpenConfirm(_re, _le, setting, true); + // Send packet before upgrade + + sendOnePacket(_local.channelId, 1, mars); + + // Ensure packet is sent correctly + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 1)) > 0); + + // Do upgrade before finishing packet handshake + upgradeDispatcher(portPrefix, address(dispatcherProxy)); + dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient2); + + // Now recv and ack packet + IbcEndpoint memory src = IbcEndpoint(sendingPortId, _local.channelId); + IbcEndpoint memory dest = IbcEndpoint(receivingPortId, _remote.channelId); + IbcPacket memory pkt = IbcPacket(src, dest, 1, bytes("payload"), ZERO_HEIGHT, maxTimeout); + dispatcherProxy.recvPacket(pkt, validProof); + assert( + vm.load(address(dispatcherProxy), findAckPacketCommitmentSlot(address(receivingMars), _remote.channelId, 1)) + > 0 + ); + + dispatcherProxy.acknowledgement(pkt, genAckPacket("1"), validProof); + // Send packet commitment should be deleted after sending + assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 1)) == 0); + + uint64 nextSequenceAckValue = + uint64(uint256(vm.load(address(dispatcherProxy), findNextSequenceAck(address(mars), _local.channelId)))); + + uint64 nextSequenceSendValue = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _local.channelId))) + ); + + assertEq(2, nextSequenceAckValue); + assertEq(2, nextSequenceSendValue); + } +} diff --git a/test/upgradeableProxy/upgrades/DispatcherRc3.sol b/test/upgradeableProxy/upgrades/DispatcherRc3.sol new file mode 100644 index 00000000..26949d04 --- /dev/null +++ b/test/upgradeableProxy/upgrades/DispatcherRc3.sol @@ -0,0 +1,6351 @@ +pragma solidity >=0.6.0 ^0.8.0 ^0.8.1 ^0.8.15 ^0.8.2 ^0.8.9; + +import "forge-std/Test.sol"; +// contracts/interfaces/ProofVerifier.sol + +struct OpIcs23ProofPath { + bytes prefix; + bytes suffix; +} + +struct OpIcs23Proof { + OpIcs23ProofPath[] path; + bytes key; + bytes value; + bytes prefix; +} + +// the Ics23 proof related structs are used to do membership verification. These are not the actual Ics23 +// format but a "solidity friendly" version of it - data is the same just packaged differently +struct Ics23Proof { + OpIcs23Proof[] proof; + uint256 height; +} + +// This is the proof we use to verify the apphash (state) updates. +struct OpL2StateProof { + bytes[] accountProof; + bytes[] outputRootProof; + bytes32 l2OutputProposalKey; + bytes32 l2BlockHash; +} + +// The `header` field is a list of RLP encoded L1 header fields. Both stateRoot and number are not +// encoded for easy usage. They must match with their RLP encoded counterparty versions. +struct L1Header { + bytes[] header; + bytes32 stateRoot; + uint64 number; +} + +interface ProofVerifier { + error InvalidL1BlockNumber(); + error InvalidL1BlockHash(); + error InvalidRLPEncodedL1BlockNumber(); + error InvalidRLPEncodedL1StateRoot(); + error InvalidAppHash(); + error InvalidProofKey(); + error InvalidProofValue(); + error InvalidPacketProof(); + error InvalidIbcStateProof(); + error MethodNotImplemented(); + + /** + * @dev verifies if a state update (apphash) is valid, given the provided proofs. + * Reverts in case of failure. + * + * @param l1header RLP "encoded" version of the L1 header that matches with the trusted hash and number + * @param proof l2 state proof. It includes the keys, hashes and storage proofs required to verify the app hash + * @param appHash l2 app hash (state root) to be verified + * @param trustedL1BlockHash trusted L1 block hash. Provided L1 header must match with it. + * @param trustedL1BlockNumber trusted L1 block number. Provided L1 header must match with it. + */ + function verifyStateUpdate( + L1Header calldata l1header, + OpL2StateProof calldata proof, + bytes32 appHash, + bytes32 trustedL1BlockHash, + uint64 trustedL1BlockNumber + ) external view; + + /** + * @dev verifies the provided ICS23 proof given the trusted app hash. Reverts in case of failure. + * + * @param appHash trusted l2 app hash (state root) + * @param key key to be proven + * @param value value to be proven + * @param proof ICS23 membership proof + */ + function verifyMembership(bytes32 appHash, bytes calldata key, bytes calldata value, Ics23Proof calldata proof) + external + pure; + + /** + * @dev verifies the provided ICS23 proof given the trusted app hash. Reverts in case of failure. + * + * @param appHash trusted l2 app hash (state root) + * @param key key to be proven non-existing + * @param proof ICS23 non-membership proof + */ + function verifyNonMembership(bytes32 appHash, bytes calldata key, Ics23Proof calldata proof) external pure; +} + +// lib/base64/base64.sol + +/// @title Base64 +/// @author Brecht Devos - <brecht@loopring.org> +/// @notice Provides functions for encoding/decoding base64 +library Base64 { + string internal constant TABLE_ENCODE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000" + hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000" + hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000" + hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000"; + + function encode(bytes memory data) internal pure returns (string memory) { + if (data.length == 0) return ""; + + // load the table into memory + string memory table = TABLE_ENCODE; + + // multiply by 4/3 rounded up + uint256 encodedLen = 4 * ((data.length + 2) / 3); + + // add some extra buffer at the end required for the writing + string memory result = new string(encodedLen + 32); + + assembly { + // set the actual output length + mstore(result, encodedLen) + + // prepare the lookup table + let tablePtr := add(table, 1) + + // input ptr + let dataPtr := data + let endPtr := add(dataPtr, mload(data)) + + // result ptr, jump over length + let resultPtr := add(result, 32) + + // run over the input, 3 bytes at a time + for {} lt(dataPtr, endPtr) {} { + // read 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // write 4 characters + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) + } + + // padding with '=' + switch mod(mload(data), 3) + case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } + case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } + } + + return result; + } + + function decode(string memory _data) internal pure returns (bytes memory) { + bytes memory data = bytes(_data); + + if (data.length == 0) return new bytes(0); + require(data.length % 4 == 0, "invalid base64 decoder input"); + + // load the table into memory + bytes memory table = TABLE_DECODE; + + // every 4 characters represent 3 bytes + uint256 decodedLen = (data.length / 4) * 3; + + // add some extra buffer at the end required for the writing + bytes memory result = new bytes(decodedLen + 32); + + assembly { + // padding with '=' + let lastBytes := mload(add(data, mload(data))) + if eq(and(lastBytes, 0xFF), 0x3d) { + decodedLen := sub(decodedLen, 1) + if eq(and(lastBytes, 0xFFFF), 0x3d3d) { decodedLen := sub(decodedLen, 1) } + } + + // set the actual output length + mstore(result, decodedLen) + + // prepare the lookup table + let tablePtr := add(table, 1) + + // input ptr + let dataPtr := data + let endPtr := add(dataPtr, mload(data)) + + // result ptr, jump over length + let resultPtr := add(result, 32) + + // run over the input, 4 characters at a time + for {} lt(dataPtr, endPtr) {} { + // read 4 characters + dataPtr := add(dataPtr, 4) + let input := mload(dataPtr) + + // write 3 bytes + let output := + add( + add( + shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)), + shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF)) + ), + add( + shl(6, and(mload(add(tablePtr, and(shr(8, input), 0xFF))), 0xFF)), + and(mload(add(tablePtr, and(input, 0xFF))), 0xFF) + ) + ) + mstore(resultPtr, shl(232, output)) + resultPtr := add(resultPtr, 3) + } + } + + return result; + } +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) + +/** + * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. + * + * _Available since v4.8.3._ + */ +interface IERC1967 { + /** + * @dev Emitted when the implementation is upgraded. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Emitted when the admin account has changed. + */ + event AdminChanged(address previousAdmin, address newAdmin); + + /** + * @dev Emitted when the beacon is changed. + */ + event BeaconUpgraded(address indexed beacon); +} + +// lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol + +// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) + +/** + * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified + * proxy whose upgrades are fully controlled by the current implementation. + */ +interface IERC1822Proxiable { + /** + * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation + * address. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. + */ + function proxiableUUID() external view returns (bytes32); +} + +// lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol + +// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) + +/** + * @dev This is the interface that {BeaconProxy} expects of its beacon. + */ +interface IBeacon { + /** + * @dev Must return an address that can be used as a delegate call target. + * + * {BeaconProxy} will check that this address is a contract. + */ + function implementation() external view returns (address); +} + +// lib/openzeppelin-contracts/contracts/utils/Address.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * + * Furthermore, `isContract` will also return true if the target contract within + * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, + * which only has an effect at the end of a transaction. + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions + * pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success,) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use + * https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) + internal + returns (bytes memory) + { + require(address(this).balance >= value, "Address: insufficient balance for call"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) + internal + view + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) + internal + pure + returns (bytes memory) + { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/Context.sol + +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) +// This file was procedurally generated from scripts/generate/templates/StorageSlot.js. + +/** + * @dev Library for reading and writing primitive types to specific storage slots. + * + * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. + * This library helps with reading and writing to such slots without the need for inline assembly. + * + * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. + * + * Example usage to set ERC1967 implementation slot: + * ```solidity + * contract ERC1967 { + * bytes32 internal constant _IMPLEMENTATION_SLOT = + * 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + * + * function _getImplementation() internal view returns (address) { + * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + * } + * + * function _setImplementation(address newImplementation) internal { + * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * ``` + * + * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ + * _Available since v4.9 for `string`, `bytes`._ + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `StringSlot` with member `value` located at `slot`. + */ + function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `StringSlot` representation of the string storage pointer `store`. + */ + function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := store.slot + } + } + + /** + * @dev Returns an `BytesSlot` with member `value` located at `slot`. + */ + function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. + */ + function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := store.slot + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Down, // Toward negative infinity + Up, // Toward infinity + Zero // Toward zero + + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds up instead + * of rounding down. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0 + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) + * with further edits by Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always + // >= 1. + // See https://cs.stackexchange.com/q/138556/92363. + + // Does not overflow because the denominator cannot be zero at this stage in the function. + uint256 twos = denominator & (~denominator + 1); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works + // in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) + +/** + * @dev Collection of functions related to the address type + */ +library AddressUpgradeable { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * + * Furthermore, `isContract` will also return true if the target contract within + * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, + * which only has an effect at the end of a transaction. + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions + * pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success,) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use + * https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) + internal + returns (bytes memory) + { + require(address(this).balance >= value, "Address: insufficient balance for call"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) + internal + view + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) + internal + pure + returns (bytes memory) + { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} + +// lib/proto/ProtoBufRuntime.sol + +/** + * @title Runtime library for ProtoBuf serialization and/or deserialization. + * All ProtoBuf generated code will use this library. + */ +library ProtoBufRuntime { + // Types defined in ProtoBuf + enum WireType { + Varint, + Fixed64, + LengthDelim, + StartGroup, + EndGroup, + Fixed32 + } + // Constants for bytes calculation + + uint256 constant WORD_LENGTH = 32; + uint256 constant HEADER_SIZE_LENGTH_IN_BYTES = 4; + uint256 constant BYTE_SIZE = 8; + uint256 constant REMAINING_LENGTH = WORD_LENGTH - HEADER_SIZE_LENGTH_IN_BYTES; + string constant OVERFLOW_MESSAGE = "length overflow"; + + //Storages + /** + * @dev Encode to storage location using assembly to save storage space. + * @param location The location of storage + * @param encoded The encoded ProtoBuf bytes + */ + function encodeStorage(bytes storage location, bytes memory encoded) internal { + /** + * This code use the first four bytes as size, + * and then put the rest of `encoded` bytes. + */ + uint256 length = encoded.length; + uint256 firstWord; + uint256 wordLength = WORD_LENGTH; + uint256 remainingLength = REMAINING_LENGTH; + + assembly { + firstWord := mload(add(encoded, wordLength)) + } + firstWord = + (firstWord >> (BYTE_SIZE * HEADER_SIZE_LENGTH_IN_BYTES)) | (length << (BYTE_SIZE * REMAINING_LENGTH)); + + assembly { + sstore(location.slot, firstWord) + } + + if (length > REMAINING_LENGTH) { + length -= REMAINING_LENGTH; + for (uint256 i = 0; i < ceil(length, WORD_LENGTH); i++) { + assembly { + let offset := add(mul(i, wordLength), remainingLength) + let slotIndex := add(i, 1) + sstore(add(location.slot, slotIndex), mload(add(add(encoded, wordLength), offset))) + } + } + } + } + + /** + * @dev Decode storage location using assembly using the format in `encodeStorage`. + * @param location The location of storage + * @return The encoded bytes + */ + function decodeStorage(bytes storage location) internal view returns (bytes memory) { + /** + * This code is to decode the first four bytes as size, + * and then decode the rest using the decoded size. + */ + uint256 firstWord; + uint256 remainingLength = REMAINING_LENGTH; + uint256 wordLength = WORD_LENGTH; + + assembly { + firstWord := sload(location.slot) + } + + uint256 length = firstWord >> (BYTE_SIZE * REMAINING_LENGTH); + bytes memory encoded = new bytes(length); + + assembly { + mstore(add(encoded, remainingLength), firstWord) + } + + if (length > REMAINING_LENGTH) { + length -= REMAINING_LENGTH; + for (uint256 i = 0; i < ceil(length, WORD_LENGTH); i++) { + assembly { + let offset := add(mul(i, wordLength), remainingLength) + let slotIndex := add(i, 1) + mstore(add(add(encoded, wordLength), offset), sload(add(location.slot, slotIndex))) + } + } + } + return encoded; + } + + /** + * @dev Fast memory copy of bytes using assembly. + * @param src The source memory address + * @param dest The destination memory address + * @param len The length of bytes to copy + */ + function copyBytes(uint256 src, uint256 dest, uint256 len) internal pure { + if (len == 0) { + return; + } + + // Copy word-length chunks while possible + for (; len > WORD_LENGTH; len -= WORD_LENGTH) { + assembly { + mstore(dest, mload(src)) + } + dest += WORD_LENGTH; + src += WORD_LENGTH; + } + + // Copy remaining bytes + uint256 mask = 256 ** (WORD_LENGTH - len) - 1; + assembly { + let srcpart := and(mload(src), not(mask)) + let destpart := and(mload(dest), mask) + mstore(dest, or(destpart, srcpart)) + } + } + + /** + * @dev Use assembly to get memory address. + * @param r The in-memory bytes array + * @return The memory address of `r` + */ + function getMemoryAddress(bytes memory r) internal pure returns (uint256) { + uint256 addr; + assembly { + addr := r + } + return addr; + } + + /** + * @dev Implement Math function of ceil + * @param a The denominator + * @param m The numerator + * @return r The result of ceil(a/m) + */ + function ceil(uint256 a, uint256 m) internal pure returns (uint256 r) { + return (a + m - 1) / m; + } + + // Decoders + /** + * This section of code `_decode_(u)int(32|64)`, `_decode_enum` and `_decode_bool` + * is to decode ProtoBuf native integers, + * using the `varint` encoding. + */ + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_uint32(uint256 p, bytes memory bs) internal pure returns (uint32, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + return (uint32(varint), sz); + } + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_uint64(uint256 p, bytes memory bs) internal pure returns (uint64, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + return (uint64(varint), sz); + } + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_int32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + int32 r; + assembly { + r := varint + } + return (r, sz); + } + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_int64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + int64 r; + assembly { + r := varint + } + return (r, sz); + } + + /** + * @dev Decode enum + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded enum's integer + * @return The length of `bs` used to get decoded + */ + function _decode_enum(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + return _decode_int64(p, bs); + } + + /** + * @dev Decode enum + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded boolean + * @return The length of `bs` used to get decoded + */ + function _decode_bool(uint256 p, bytes memory bs) internal pure returns (bool, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + if (varint == 0) { + return (false, sz); + } + return (true, sz); + } + + /** + * This section of code `_decode_sint(32|64)` + * is to decode ProtoBuf native signed integers, + * using the `zig-zag` encoding. + */ + + /** + * @dev Decode signed integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_sint32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (int256 varint, uint256 sz) = _decode_varints(p, bs); + return (int32(varint), sz); + } + + /** + * @dev Decode signed integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_sint64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (int256 varint, uint256 sz) = _decode_varints(p, bs); + return (int64(varint), sz); + } + + /** + * @dev Decode string + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded string + * @return The length of `bs` used to get decoded + */ + function _decode_string(uint256 p, bytes memory bs) internal pure returns (string memory, uint256) { + (bytes memory x, uint256 sz) = _decode_lendelim(p, bs); + return (string(x), sz); + } + + /** + * @dev Decode bytes array + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded bytes array + * @return The length of `bs` used to get decoded + */ + function _decode_bytes(uint256 p, bytes memory bs) internal pure returns (bytes memory, uint256) { + return _decode_lendelim(p, bs); + } + + /** + * @dev Decode ProtoBuf key + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded field ID + * @return The decoded WireType specified in ProtoBuf + * @return The length of `bs` used to get decoded + */ + function _decode_key(uint256 p, bytes memory bs) internal pure returns (uint256, WireType, uint256) { + (uint256 x, uint256 n) = _decode_varint(p, bs); + WireType typeId = WireType(x & 7); + uint256 fieldId = x / 8; + return (fieldId, typeId, n); + } + + /** + * @dev Decode ProtoBuf varint + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded unsigned integer + * @return The length of `bs` used to get decoded + */ + function _decode_varint(uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + /** + * Read a byte. + * Use the lower 7 bits and shift it to the left, + * until the most significant bit is 0. + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 x = 0; + uint256 sz = 0; + uint256 length = bs.length + WORD_LENGTH; + assembly { + let b := 0x80 + p := add(bs, p) + for {} eq(0x80, and(b, 0x80)) {} { + if eq(lt(sub(p, bs), length), 0) { + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) //error function + // selector + mstore(4, 32) + mstore(36, 15) + mstore(68, 0x6c656e677468206f766572666c6f770000000000000000000000000000000000) // length overflow in + // hex + revert(0, 83) + } + let tmp := mload(p) + let pos := 0 + for {} and(eq(0x80, and(b, 0x80)), lt(pos, 32)) {} { + if eq(lt(sub(p, bs), length), 0) { + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) //error function + // selector + mstore(4, 32) + mstore(36, 15) + mstore(68, 0x6c656e677468206f766572666c6f770000000000000000000000000000000000) // length + // overflow in hex + revert(0, 83) + } + b := byte(pos, tmp) + x := or(x, shl(mul(7, sz), and(0x7f, b))) + sz := add(sz, 1) + pos := add(pos, 1) + p := add(p, 0x01) + } + } + } + return (x, sz); + } + + /** + * @dev Decode ProtoBuf zig-zag encoding + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded signed integer + * @return The length of `bs` used to get decoded + */ + function _decode_varints(uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + (uint256 u, uint256 sz) = _decode_varint(p, bs); + int256 s; + assembly { + s := xor(shr(1, u), add(not(and(u, 1)), 1)) + } + return (s, sz); + } + + /** + * @dev Decode ProtoBuf fixed-length encoding + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded unsigned integer + * @return The length of `bs` used to get decoded + */ + function _decode_uintf(uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256, uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 x = 0; + uint256 length = bs.length + WORD_LENGTH; + assert(p + sz <= length); + assembly { + let i := 0 + p := add(bs, p) + let tmp := mload(p) + for {} lt(i, sz) {} { + x := or(x, shl(mul(8, i), byte(i, tmp))) + p := add(p, 0x01) + i := add(i, 1) + } + } + return (x, sz); + } + + /** + * `_decode_(s)fixed(32|64)` is the concrete implementation of `_decode_uintf` + */ + function _decode_fixed32(uint256 p, bytes memory bs) internal pure returns (uint32, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 4); + return (uint32(x), sz); + } + + function _decode_fixed64(uint256 p, bytes memory bs) internal pure returns (uint64, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 8); + return (uint64(x), sz); + } + + function _decode_sfixed32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 4); + int256 r; + assembly { + r := x + } + return (int32(r), sz); + } + + function _decode_sfixed64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 8); + int256 r; + assembly { + r := x + } + return (int64(r), sz); + } + + /** + * @dev Decode bytes array + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded bytes array + * @return The length of `bs` used to get decoded + */ + function _decode_lendelim(uint256 p, bytes memory bs) internal pure returns (bytes memory, uint256) { + /** + * First read the size encoded in `varint`, then use the size to read bytes. + */ + (uint256 len, uint256 sz) = _decode_varint(p, bs); + bytes memory b = new bytes(len); + uint256 length = bs.length + WORD_LENGTH; + assert(p + sz + len <= length); + uint256 sourcePtr; + uint256 destPtr; + assembly { + destPtr := add(b, 32) + sourcePtr := add(add(bs, p), sz) + } + copyBytes(sourcePtr, destPtr, len); + return (b, sz + len); + } + + /** + * @dev Skip the decoding of a single field + * @param wt The WireType of the field + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The length of `bs` to skipped + */ + function _skip_field_decode(WireType wt, uint256 p, bytes memory bs) internal pure returns (uint256) { + if (wt == ProtoBufRuntime.WireType.Fixed64) { + return 8; + } else if (wt == ProtoBufRuntime.WireType.Fixed32) { + return 4; + } else if (wt == ProtoBufRuntime.WireType.Varint) { + (, uint256 size) = ProtoBufRuntime._decode_varint(p, bs); + return size; + } else { + require(wt == ProtoBufRuntime.WireType.LengthDelim); + (uint256 len, uint256 size) = ProtoBufRuntime._decode_varint(p, bs); + return size + len; + } + } + + // Encoders + /** + * @dev Encode ProtoBuf key + * @param x The field ID + * @param wt The WireType specified in ProtoBuf + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_key(uint256 x, WireType wt, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 i; + assembly { + i := or(mul(x, 8), mod(wt, 8)) + } + return _encode_varint(i, p, bs); + } + + /** + * @dev Encode ProtoBuf varint + * @param x The unsigned integer to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_varint(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 sz = 0; + assembly { + let bsptr := add(bs, p) + let byt := and(x, 0x7f) + for {} gt(shr(7, x), 0) {} { + mstore8(bsptr, or(0x80, byt)) + bsptr := add(bsptr, 1) + sz := add(sz, 1) + x := shr(7, x) + byt := and(x, 0x7f) + } + mstore8(bsptr, byt) + sz := add(sz, 1) + } + return sz; + } + + /** + * @dev Encode ProtoBuf zig-zag encoding + * @param x The signed integer to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_varints(int256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 encodedInt = _encode_zigzag(x); + return _encode_varint(encodedInt, p, bs); + } + + /** + * @dev Encode ProtoBuf bytes + * @param xs The bytes array to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_bytes(bytes memory xs, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 xsLength = xs.length; + uint256 sz = _encode_varint(xsLength, p, bs); + uint256 count = 0; + assembly { + let bsptr := add(bs, add(p, sz)) + let xsptr := add(xs, 32) + for {} lt(count, xsLength) {} { + mstore8(bsptr, byte(0, mload(xsptr))) + bsptr := add(bsptr, 1) + xsptr := add(xsptr, 1) + count := add(count, 1) + } + } + return sz + count; + } + + /** + * @dev Encode ProtoBuf string + * @param xs The string to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_string(string memory xs, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_bytes(bytes(xs), p, bs); + } + + /** + * `_encode_(u)int(32|64)`, `_encode_enum` and `_encode_bool` + * are concrete implementation of `_encode_varint` + */ + function _encode_uint32(uint32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varint(x, p, bs); + } + + function _encode_uint64(uint64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varint(x, p, bs); + } + + function _encode_int32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint64 twosComplement; + assembly { + twosComplement := x + } + return _encode_varint(twosComplement, p, bs); + } + + function _encode_int64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint64 twosComplement; + assembly { + twosComplement := x + } + return _encode_varint(twosComplement, p, bs); + } + + function _encode_enum(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_int32(x, p, bs); + } + + function _encode_bool(bool x, uint256 p, bytes memory bs) internal pure returns (uint256) { + if (x) { + return _encode_varint(1, p, bs); + } else { + return _encode_varint(0, p, bs); + } + } + + /** + * `_encode_sint(32|64)`, `_encode_enum` and `_encode_bool` + * are the concrete implementation of `_encode_varints` + */ + function _encode_sint32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varints(x, p, bs); + } + + function _encode_sint64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varints(x, p, bs); + } + + /** + * `_encode_(s)fixed(32|64)` is the concrete implementation of `_encode_uintf` + */ + function _encode_fixed32(uint32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_uintf(x, p, bs, 4); + } + + function _encode_fixed64(uint64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_uintf(x, p, bs, 8); + } + + function _encode_sfixed32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint32 twosComplement; + assembly { + twosComplement := x + } + return _encode_uintf(twosComplement, p, bs, 4); + } + + function _encode_sfixed64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint64 twosComplement; + assembly { + twosComplement := x + } + return _encode_uintf(twosComplement, p, bs, 8); + } + + /** + * @dev Encode ProtoBuf fixed-length integer + * @param x The unsigned integer to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_uintf(uint256 x, uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256) { + assembly { + let bsptr := add(sz, add(bs, p)) + let count := sz + for {} gt(count, 0) {} { + bsptr := sub(bsptr, 1) + mstore8(bsptr, byte(sub(32, count), x)) + count := sub(count, 1) + } + } + return sz; + } + + /** + * @dev Encode ProtoBuf zig-zag signed integer + * @param i The unsigned integer to be encoded + * @return The encoded unsigned integer + */ + function _encode_zigzag(int256 i) internal pure returns (uint256) { + if (i >= 0) { + return uint256(i) * 2; + } else { + return uint256(i * -2) - 1; + } + } + + // Estimators + /** + * @dev Estimate the length of encoded LengthDelim + * @param i The length of LengthDelim + * @return The estimated encoded length + */ + function _sz_lendelim(uint256 i) internal pure returns (uint256) { + return i + _sz_varint(i); + } + + /** + * @dev Estimate the length of encoded ProtoBuf field ID + * @param i The field ID + * @return The estimated encoded length + */ + function _sz_key(uint256 i) internal pure returns (uint256) { + if (i < 16) { + return 1; + } else if (i < 2048) { + return 2; + } else if (i < 262_144) { + return 3; + } else { + revert("not supported"); + } + } + + /** + * @dev Estimate the length of encoded ProtoBuf varint + * @param i The unsigned integer + * @return The estimated encoded length + */ + function _sz_varint(uint256 i) internal pure returns (uint256) { + uint256 count = 1; + assembly { + i := shr(7, i) + for {} gt(i, 0) {} { + i := shr(7, i) + count := add(count, 1) + } + } + return count; + } + + /** + * `_sz_(u)int(32|64)` and `_sz_enum` are the concrete implementation of `_sz_varint` + */ + function _sz_uint32(uint32 i) internal pure returns (uint256) { + return _sz_varint(i); + } + + function _sz_uint64(uint64 i) internal pure returns (uint256) { + return _sz_varint(i); + } + + function _sz_int32(int32 i) internal pure returns (uint256) { + if (i < 0) { + return 10; + } else { + return _sz_varint(uint32(i)); + } + } + + function _sz_int64(int64 i) internal pure returns (uint256) { + if (i < 0) { + return 10; + } else { + return _sz_varint(uint64(i)); + } + } + + function _sz_enum(int64 i) internal pure returns (uint256) { + if (i < 0) { + return 10; + } else { + return _sz_varint(uint64(i)); + } + } + + /** + * `_sz_sint(32|64)` and `_sz_enum` are the concrete implementation of zig-zag encoding + */ + function _sz_sint32(int32 i) internal pure returns (uint256) { + return _sz_varint(_encode_zigzag(i)); + } + + function _sz_sint64(int64 i) internal pure returns (uint256) { + return _sz_varint(_encode_zigzag(i)); + } + + /** + * `_estimate_packed_repeated_(uint32|uint64|int32|int64|sint32|sint64)` + */ + function _estimate_packed_repeated_uint32(uint32[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_uint32(a[i]); + } + return e; + } + + function _estimate_packed_repeated_uint64(uint64[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_uint64(a[i]); + } + return e; + } + + function _estimate_packed_repeated_int32(int32[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_int32(a[i]); + } + return e; + } + + function _estimate_packed_repeated_int64(int64[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_int64(a[i]); + } + return e; + } + + function _estimate_packed_repeated_sint32(int32[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_sint32(a[i]); + } + return e; + } + + function _estimate_packed_repeated_sint64(int64[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_sint64(a[i]); + } + return e; + } + + // Element counters for packed repeated fields + function _count_packed_repeated_varint(uint256 p, uint256 len, bytes memory bs) internal pure returns (uint256) { + uint256 count = 0; + uint256 end = p + len; + while (p < end) { + uint256 sz; + (, sz) = _decode_varint(p, bs); + p += sz; + count += 1; + } + return count; + } + + // Soltype extensions + /** + * @dev Decode Solidity integer and/or fixed-size bytes array, filling from lowest bit. + * @param n The maximum number of bytes to read + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The bytes32 representation + * @return The number of bytes used to decode + */ + function _decode_sol_bytesN_lower(uint8 n, uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + uint256 r; + (uint256 len, uint256 sz) = _decode_varint(p, bs); + if (len + sz > n + 3) { + revert(OVERFLOW_MESSAGE); + } + p += 3; + assert(p < bs.length + WORD_LENGTH); + assembly { + r := mload(add(p, bs)) + } + for (uint256 i = len - 2; i < WORD_LENGTH; i++) { + r /= 256; + } + return (bytes32(r), len + sz); + } + + /** + * @dev Decode Solidity integer and/or fixed-size bytes array, filling from highest bit. + * @param n The maximum number of bytes to read + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The bytes32 representation + * @return The number of bytes used to decode + */ + function _decode_sol_bytesN(uint8 n, uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + (uint256 len, uint256 sz) = _decode_varint(p, bs); + uint256 wordLength = WORD_LENGTH; + uint256 byteSize = BYTE_SIZE; + if (len + sz > n + 3) { + revert(OVERFLOW_MESSAGE); + } + p += 3; + bytes32 acc; + assert(p < bs.length + WORD_LENGTH); + assembly { + acc := mload(add(p, bs)) + let difference := sub(wordLength, sub(len, 2)) + let bits := mul(byteSize, difference) + acc := shl(bits, shr(bits, acc)) + } + return (acc, len + sz); + } + + /* + * `_decode_sol*` are the concrete implementation of decoding Solidity types + */ + function _decode_sol_address(uint256 p, bytes memory bs) internal pure returns (address, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytesN(20, p, bs); + return (address(bytes20(r)), sz); + } + + function _decode_sol_bool(uint256 p, bytes memory bs) internal pure returns (bool, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(1, p, bs); + if (r == 0) { + return (false, sz); + } + return (true, sz); + } + + function _decode_sol_uint(uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + return _decode_sol_uint256(p, bs); + } + + function _decode_sol_uintN(uint8 n, uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + (bytes32 u, uint256 sz) = _decode_sol_bytesN_lower(n, p, bs); + uint256 r; + assembly { + r := u + } + return (r, sz); + } + + function _decode_sol_uint8(uint256 p, bytes memory bs) internal pure returns (uint8, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(1, p, bs); + return (uint8(r), sz); + } + + function _decode_sol_uint16(uint256 p, bytes memory bs) internal pure returns (uint16, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(2, p, bs); + return (uint16(r), sz); + } + + function _decode_sol_uint24(uint256 p, bytes memory bs) internal pure returns (uint24, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(3, p, bs); + return (uint24(r), sz); + } + + function _decode_sol_uint32(uint256 p, bytes memory bs) internal pure returns (uint32, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(4, p, bs); + return (uint32(r), sz); + } + + function _decode_sol_uint40(uint256 p, bytes memory bs) internal pure returns (uint40, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(5, p, bs); + return (uint40(r), sz); + } + + function _decode_sol_uint48(uint256 p, bytes memory bs) internal pure returns (uint48, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(6, p, bs); + return (uint48(r), sz); + } + + function _decode_sol_uint56(uint256 p, bytes memory bs) internal pure returns (uint56, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(7, p, bs); + return (uint56(r), sz); + } + + function _decode_sol_uint64(uint256 p, bytes memory bs) internal pure returns (uint64, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(8, p, bs); + return (uint64(r), sz); + } + + function _decode_sol_uint72(uint256 p, bytes memory bs) internal pure returns (uint72, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(9, p, bs); + return (uint72(r), sz); + } + + function _decode_sol_uint80(uint256 p, bytes memory bs) internal pure returns (uint80, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(10, p, bs); + return (uint80(r), sz); + } + + function _decode_sol_uint88(uint256 p, bytes memory bs) internal pure returns (uint88, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(11, p, bs); + return (uint88(r), sz); + } + + function _decode_sol_uint96(uint256 p, bytes memory bs) internal pure returns (uint96, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(12, p, bs); + return (uint96(r), sz); + } + + function _decode_sol_uint104(uint256 p, bytes memory bs) internal pure returns (uint104, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(13, p, bs); + return (uint104(r), sz); + } + + function _decode_sol_uint112(uint256 p, bytes memory bs) internal pure returns (uint112, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(14, p, bs); + return (uint112(r), sz); + } + + function _decode_sol_uint120(uint256 p, bytes memory bs) internal pure returns (uint120, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(15, p, bs); + return (uint120(r), sz); + } + + function _decode_sol_uint128(uint256 p, bytes memory bs) internal pure returns (uint128, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(16, p, bs); + return (uint128(r), sz); + } + + function _decode_sol_uint136(uint256 p, bytes memory bs) internal pure returns (uint136, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(17, p, bs); + return (uint136(r), sz); + } + + function _decode_sol_uint144(uint256 p, bytes memory bs) internal pure returns (uint144, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(18, p, bs); + return (uint144(r), sz); + } + + function _decode_sol_uint152(uint256 p, bytes memory bs) internal pure returns (uint152, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(19, p, bs); + return (uint152(r), sz); + } + + function _decode_sol_uint160(uint256 p, bytes memory bs) internal pure returns (uint160, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(20, p, bs); + return (uint160(r), sz); + } + + function _decode_sol_uint168(uint256 p, bytes memory bs) internal pure returns (uint168, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(21, p, bs); + return (uint168(r), sz); + } + + function _decode_sol_uint176(uint256 p, bytes memory bs) internal pure returns (uint176, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(22, p, bs); + return (uint176(r), sz); + } + + function _decode_sol_uint184(uint256 p, bytes memory bs) internal pure returns (uint184, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(23, p, bs); + return (uint184(r), sz); + } + + function _decode_sol_uint192(uint256 p, bytes memory bs) internal pure returns (uint192, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(24, p, bs); + return (uint192(r), sz); + } + + function _decode_sol_uint200(uint256 p, bytes memory bs) internal pure returns (uint200, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(25, p, bs); + return (uint200(r), sz); + } + + function _decode_sol_uint208(uint256 p, bytes memory bs) internal pure returns (uint208, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(26, p, bs); + return (uint208(r), sz); + } + + function _decode_sol_uint216(uint256 p, bytes memory bs) internal pure returns (uint216, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(27, p, bs); + return (uint216(r), sz); + } + + function _decode_sol_uint224(uint256 p, bytes memory bs) internal pure returns (uint224, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(28, p, bs); + return (uint224(r), sz); + } + + function _decode_sol_uint232(uint256 p, bytes memory bs) internal pure returns (uint232, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(29, p, bs); + return (uint232(r), sz); + } + + function _decode_sol_uint240(uint256 p, bytes memory bs) internal pure returns (uint240, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(30, p, bs); + return (uint240(r), sz); + } + + function _decode_sol_uint248(uint256 p, bytes memory bs) internal pure returns (uint248, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(31, p, bs); + return (uint248(r), sz); + } + + function _decode_sol_uint256(uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(32, p, bs); + return (uint256(r), sz); + } + + function _decode_sol_int(uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + return _decode_sol_int256(p, bs); + } + + function _decode_sol_intN(uint8 n, uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + (bytes32 u, uint256 sz) = _decode_sol_bytesN_lower(n, p, bs); + int256 r; + assembly { + r := u + r := signextend(sub(sz, 4), r) + } + return (r, sz); + } + + function _decode_sol_bytes(uint8 n, uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + (bytes32 u, uint256 sz) = _decode_sol_bytesN(n, p, bs); + return (u, sz); + } + + function _decode_sol_int8(uint256 p, bytes memory bs) internal pure returns (int8, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(1, p, bs); + return (int8(r), sz); + } + + function _decode_sol_int16(uint256 p, bytes memory bs) internal pure returns (int16, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(2, p, bs); + return (int16(r), sz); + } + + function _decode_sol_int24(uint256 p, bytes memory bs) internal pure returns (int24, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(3, p, bs); + return (int24(r), sz); + } + + function _decode_sol_int32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(4, p, bs); + return (int32(r), sz); + } + + function _decode_sol_int40(uint256 p, bytes memory bs) internal pure returns (int40, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(5, p, bs); + return (int40(r), sz); + } + + function _decode_sol_int48(uint256 p, bytes memory bs) internal pure returns (int48, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(6, p, bs); + return (int48(r), sz); + } + + function _decode_sol_int56(uint256 p, bytes memory bs) internal pure returns (int56, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(7, p, bs); + return (int56(r), sz); + } + + function _decode_sol_int64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(8, p, bs); + return (int64(r), sz); + } + + function _decode_sol_int72(uint256 p, bytes memory bs) internal pure returns (int72, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(9, p, bs); + return (int72(r), sz); + } + + function _decode_sol_int80(uint256 p, bytes memory bs) internal pure returns (int80, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(10, p, bs); + return (int80(r), sz); + } + + function _decode_sol_int88(uint256 p, bytes memory bs) internal pure returns (int88, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(11, p, bs); + return (int88(r), sz); + } + + function _decode_sol_int96(uint256 p, bytes memory bs) internal pure returns (int96, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(12, p, bs); + return (int96(r), sz); + } + + function _decode_sol_int104(uint256 p, bytes memory bs) internal pure returns (int104, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(13, p, bs); + return (int104(r), sz); + } + + function _decode_sol_int112(uint256 p, bytes memory bs) internal pure returns (int112, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(14, p, bs); + return (int112(r), sz); + } + + function _decode_sol_int120(uint256 p, bytes memory bs) internal pure returns (int120, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(15, p, bs); + return (int120(r), sz); + } + + function _decode_sol_int128(uint256 p, bytes memory bs) internal pure returns (int128, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(16, p, bs); + return (int128(r), sz); + } + + function _decode_sol_int136(uint256 p, bytes memory bs) internal pure returns (int136, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(17, p, bs); + return (int136(r), sz); + } + + function _decode_sol_int144(uint256 p, bytes memory bs) internal pure returns (int144, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(18, p, bs); + return (int144(r), sz); + } + + function _decode_sol_int152(uint256 p, bytes memory bs) internal pure returns (int152, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(19, p, bs); + return (int152(r), sz); + } + + function _decode_sol_int160(uint256 p, bytes memory bs) internal pure returns (int160, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(20, p, bs); + return (int160(r), sz); + } + + function _decode_sol_int168(uint256 p, bytes memory bs) internal pure returns (int168, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(21, p, bs); + return (int168(r), sz); + } + + function _decode_sol_int176(uint256 p, bytes memory bs) internal pure returns (int176, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(22, p, bs); + return (int176(r), sz); + } + + function _decode_sol_int184(uint256 p, bytes memory bs) internal pure returns (int184, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(23, p, bs); + return (int184(r), sz); + } + + function _decode_sol_int192(uint256 p, bytes memory bs) internal pure returns (int192, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(24, p, bs); + return (int192(r), sz); + } + + function _decode_sol_int200(uint256 p, bytes memory bs) internal pure returns (int200, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(25, p, bs); + return (int200(r), sz); + } + + function _decode_sol_int208(uint256 p, bytes memory bs) internal pure returns (int208, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(26, p, bs); + return (int208(r), sz); + } + + function _decode_sol_int216(uint256 p, bytes memory bs) internal pure returns (int216, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(27, p, bs); + return (int216(r), sz); + } + + function _decode_sol_int224(uint256 p, bytes memory bs) internal pure returns (int224, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(28, p, bs); + return (int224(r), sz); + } + + function _decode_sol_int232(uint256 p, bytes memory bs) internal pure returns (int232, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(29, p, bs); + return (int232(r), sz); + } + + function _decode_sol_int240(uint256 p, bytes memory bs) internal pure returns (int240, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(30, p, bs); + return (int240(r), sz); + } + + function _decode_sol_int248(uint256 p, bytes memory bs) internal pure returns (int248, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(31, p, bs); + return (int248(r), sz); + } + + function _decode_sol_int256(uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(32, p, bs); + return (int256(r), sz); + } + + function _decode_sol_bytes1(uint256 p, bytes memory bs) internal pure returns (bytes1, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(1, p, bs); + return (bytes1(r), sz); + } + + function _decode_sol_bytes2(uint256 p, bytes memory bs) internal pure returns (bytes2, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(2, p, bs); + return (bytes2(r), sz); + } + + function _decode_sol_bytes3(uint256 p, bytes memory bs) internal pure returns (bytes3, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(3, p, bs); + return (bytes3(r), sz); + } + + function _decode_sol_bytes4(uint256 p, bytes memory bs) internal pure returns (bytes4, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(4, p, bs); + return (bytes4(r), sz); + } + + function _decode_sol_bytes5(uint256 p, bytes memory bs) internal pure returns (bytes5, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(5, p, bs); + return (bytes5(r), sz); + } + + function _decode_sol_bytes6(uint256 p, bytes memory bs) internal pure returns (bytes6, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(6, p, bs); + return (bytes6(r), sz); + } + + function _decode_sol_bytes7(uint256 p, bytes memory bs) internal pure returns (bytes7, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(7, p, bs); + return (bytes7(r), sz); + } + + function _decode_sol_bytes8(uint256 p, bytes memory bs) internal pure returns (bytes8, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(8, p, bs); + return (bytes8(r), sz); + } + + function _decode_sol_bytes9(uint256 p, bytes memory bs) internal pure returns (bytes9, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(9, p, bs); + return (bytes9(r), sz); + } + + function _decode_sol_bytes10(uint256 p, bytes memory bs) internal pure returns (bytes10, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(10, p, bs); + return (bytes10(r), sz); + } + + function _decode_sol_bytes11(uint256 p, bytes memory bs) internal pure returns (bytes11, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(11, p, bs); + return (bytes11(r), sz); + } + + function _decode_sol_bytes12(uint256 p, bytes memory bs) internal pure returns (bytes12, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(12, p, bs); + return (bytes12(r), sz); + } + + function _decode_sol_bytes13(uint256 p, bytes memory bs) internal pure returns (bytes13, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(13, p, bs); + return (bytes13(r), sz); + } + + function _decode_sol_bytes14(uint256 p, bytes memory bs) internal pure returns (bytes14, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(14, p, bs); + return (bytes14(r), sz); + } + + function _decode_sol_bytes15(uint256 p, bytes memory bs) internal pure returns (bytes15, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(15, p, bs); + return (bytes15(r), sz); + } + + function _decode_sol_bytes16(uint256 p, bytes memory bs) internal pure returns (bytes16, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(16, p, bs); + return (bytes16(r), sz); + } + + function _decode_sol_bytes17(uint256 p, bytes memory bs) internal pure returns (bytes17, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(17, p, bs); + return (bytes17(r), sz); + } + + function _decode_sol_bytes18(uint256 p, bytes memory bs) internal pure returns (bytes18, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(18, p, bs); + return (bytes18(r), sz); + } + + function _decode_sol_bytes19(uint256 p, bytes memory bs) internal pure returns (bytes19, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(19, p, bs); + return (bytes19(r), sz); + } + + function _decode_sol_bytes20(uint256 p, bytes memory bs) internal pure returns (bytes20, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(20, p, bs); + return (bytes20(r), sz); + } + + function _decode_sol_bytes21(uint256 p, bytes memory bs) internal pure returns (bytes21, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(21, p, bs); + return (bytes21(r), sz); + } + + function _decode_sol_bytes22(uint256 p, bytes memory bs) internal pure returns (bytes22, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(22, p, bs); + return (bytes22(r), sz); + } + + function _decode_sol_bytes23(uint256 p, bytes memory bs) internal pure returns (bytes23, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(23, p, bs); + return (bytes23(r), sz); + } + + function _decode_sol_bytes24(uint256 p, bytes memory bs) internal pure returns (bytes24, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(24, p, bs); + return (bytes24(r), sz); + } + + function _decode_sol_bytes25(uint256 p, bytes memory bs) internal pure returns (bytes25, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(25, p, bs); + return (bytes25(r), sz); + } + + function _decode_sol_bytes26(uint256 p, bytes memory bs) internal pure returns (bytes26, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(26, p, bs); + return (bytes26(r), sz); + } + + function _decode_sol_bytes27(uint256 p, bytes memory bs) internal pure returns (bytes27, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(27, p, bs); + return (bytes27(r), sz); + } + + function _decode_sol_bytes28(uint256 p, bytes memory bs) internal pure returns (bytes28, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(28, p, bs); + return (bytes28(r), sz); + } + + function _decode_sol_bytes29(uint256 p, bytes memory bs) internal pure returns (bytes29, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(29, p, bs); + return (bytes29(r), sz); + } + + function _decode_sol_bytes30(uint256 p, bytes memory bs) internal pure returns (bytes30, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(30, p, bs); + return (bytes30(r), sz); + } + + function _decode_sol_bytes31(uint256 p, bytes memory bs) internal pure returns (bytes31, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(31, p, bs); + return (bytes31(r), sz); + } + + function _decode_sol_bytes32(uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + return _decode_sol_bytes(32, p, bs); + } + + /* + * `_encode_sol*` are the concrete implementation of encoding Solidity types + */ + function _encode_sol_address(address x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(uint160(x)), 20, p, bs); + } + + function _encode_sol_uint(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 32, p, bs); + } + + function _encode_sol_uint8(uint8 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 1, p, bs); + } + + function _encode_sol_uint16(uint16 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 2, p, bs); + } + + function _encode_sol_uint24(uint24 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 3, p, bs); + } + + function _encode_sol_uint32(uint32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 4, p, bs); + } + + function _encode_sol_uint40(uint40 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 5, p, bs); + } + + function _encode_sol_uint48(uint48 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 6, p, bs); + } + + function _encode_sol_uint56(uint56 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 7, p, bs); + } + + function _encode_sol_uint64(uint64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 8, p, bs); + } + + function _encode_sol_uint72(uint72 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 9, p, bs); + } + + function _encode_sol_uint80(uint80 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 10, p, bs); + } + + function _encode_sol_uint88(uint88 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 11, p, bs); + } + + function _encode_sol_uint96(uint96 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 12, p, bs); + } + + function _encode_sol_uint104(uint104 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 13, p, bs); + } + + function _encode_sol_uint112(uint112 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 14, p, bs); + } + + function _encode_sol_uint120(uint120 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 15, p, bs); + } + + function _encode_sol_uint128(uint128 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 16, p, bs); + } + + function _encode_sol_uint136(uint136 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 17, p, bs); + } + + function _encode_sol_uint144(uint144 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 18, p, bs); + } + + function _encode_sol_uint152(uint152 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 19, p, bs); + } + + function _encode_sol_uint160(uint160 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 20, p, bs); + } + + function _encode_sol_uint168(uint168 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 21, p, bs); + } + + function _encode_sol_uint176(uint176 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 22, p, bs); + } + + function _encode_sol_uint184(uint184 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 23, p, bs); + } + + function _encode_sol_uint192(uint192 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 24, p, bs); + } + + function _encode_sol_uint200(uint200 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 25, p, bs); + } + + function _encode_sol_uint208(uint208 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 26, p, bs); + } + + function _encode_sol_uint216(uint216 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 27, p, bs); + } + + function _encode_sol_uint224(uint224 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 28, p, bs); + } + + function _encode_sol_uint232(uint232 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 29, p, bs); + } + + function _encode_sol_uint240(uint240 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 30, p, bs); + } + + function _encode_sol_uint248(uint248 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 31, p, bs); + } + + function _encode_sol_uint256(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 32, p, bs); + } + + function _encode_sol_int(int256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(x, 32, p, bs); + } + + function _encode_sol_int8(int8 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 1, p, bs); + } + + function _encode_sol_int16(int16 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 2, p, bs); + } + + function _encode_sol_int24(int24 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 3, p, bs); + } + + function _encode_sol_int32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 4, p, bs); + } + + function _encode_sol_int40(int40 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 5, p, bs); + } + + function _encode_sol_int48(int48 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 6, p, bs); + } + + function _encode_sol_int56(int56 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 7, p, bs); + } + + function _encode_sol_int64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 8, p, bs); + } + + function _encode_sol_int72(int72 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 9, p, bs); + } + + function _encode_sol_int80(int80 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 10, p, bs); + } + + function _encode_sol_int88(int88 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 11, p, bs); + } + + function _encode_sol_int96(int96 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 12, p, bs); + } + + function _encode_sol_int104(int104 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 13, p, bs); + } + + function _encode_sol_int112(int112 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 14, p, bs); + } + + function _encode_sol_int120(int120 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 15, p, bs); + } + + function _encode_sol_int128(int128 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 16, p, bs); + } + + function _encode_sol_int136(int136 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 17, p, bs); + } + + function _encode_sol_int144(int144 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 18, p, bs); + } + + function _encode_sol_int152(int152 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 19, p, bs); + } + + function _encode_sol_int160(int160 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 20, p, bs); + } + + function _encode_sol_int168(int168 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 21, p, bs); + } + + function _encode_sol_int176(int176 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 22, p, bs); + } + + function _encode_sol_int184(int184 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 23, p, bs); + } + + function _encode_sol_int192(int192 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 24, p, bs); + } + + function _encode_sol_int200(int200 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 25, p, bs); + } + + function _encode_sol_int208(int208 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 26, p, bs); + } + + function _encode_sol_int216(int216 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 27, p, bs); + } + + function _encode_sol_int224(int224 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 28, p, bs); + } + + function _encode_sol_int232(int232 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 29, p, bs); + } + + function _encode_sol_int240(int240 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 30, p, bs); + } + + function _encode_sol_int248(int248 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 31, p, bs); + } + + function _encode_sol_int256(int256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(x, 32, p, bs); + } + + function _encode_sol_bytes1(bytes1 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 1, p, bs); + } + + function _encode_sol_bytes2(bytes2 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 2, p, bs); + } + + function _encode_sol_bytes3(bytes3 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 3, p, bs); + } + + function _encode_sol_bytes4(bytes4 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 4, p, bs); + } + + function _encode_sol_bytes5(bytes5 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 5, p, bs); + } + + function _encode_sol_bytes6(bytes6 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 6, p, bs); + } + + function _encode_sol_bytes7(bytes7 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 7, p, bs); + } + + function _encode_sol_bytes8(bytes8 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 8, p, bs); + } + + function _encode_sol_bytes9(bytes9 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 9, p, bs); + } + + function _encode_sol_bytes10(bytes10 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 10, p, bs); + } + + function _encode_sol_bytes11(bytes11 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 11, p, bs); + } + + function _encode_sol_bytes12(bytes12 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 12, p, bs); + } + + function _encode_sol_bytes13(bytes13 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 13, p, bs); + } + + function _encode_sol_bytes14(bytes14 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 14, p, bs); + } + + function _encode_sol_bytes15(bytes15 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 15, p, bs); + } + + function _encode_sol_bytes16(bytes16 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 16, p, bs); + } + + function _encode_sol_bytes17(bytes17 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 17, p, bs); + } + + function _encode_sol_bytes18(bytes18 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 18, p, bs); + } + + function _encode_sol_bytes19(bytes19 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 19, p, bs); + } + + function _encode_sol_bytes20(bytes20 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 20, p, bs); + } + + function _encode_sol_bytes21(bytes21 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 21, p, bs); + } + + function _encode_sol_bytes22(bytes22 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 22, p, bs); + } + + function _encode_sol_bytes23(bytes23 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 23, p, bs); + } + + function _encode_sol_bytes24(bytes24 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 24, p, bs); + } + + function _encode_sol_bytes25(bytes25 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 25, p, bs); + } + + function _encode_sol_bytes26(bytes26 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 26, p, bs); + } + + function _encode_sol_bytes27(bytes27 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 27, p, bs); + } + + function _encode_sol_bytes28(bytes28 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 28, p, bs); + } + + function _encode_sol_bytes29(bytes29 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 29, p, bs); + } + + function _encode_sol_bytes30(bytes30 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 30, p, bs); + } + + function _encode_sol_bytes31(bytes31 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 31, p, bs); + } + + function _encode_sol_bytes32(bytes32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(x, 32, p, bs); + } + + /** + * @dev Encode the key of Solidity integer and/or fixed-size bytes array. + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol_header(uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + p += _encode_varint(sz + 2, p, bs); + p += _encode_key(1, WireType.LengthDelim, p, bs); + p += _encode_varint(sz, p, bs); + return p - offset; + } + + /** + * @dev Encode Solidity type + * @param x The unsinged integer to be encoded + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol(uint256 x, uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 size; + p += 3; + size = _encode_sol_raw_other(x, p, bs, sz); + p += size; + _encode_sol_header(size, offset, bs); + return p - offset; + } + + /** + * @dev Encode Solidity type + * @param x The signed integer to be encoded + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol(int256 x, uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 size; + p += 3; + size = _encode_sol_raw_other(x, p, bs, sz); + p += size; + _encode_sol_header(size, offset, bs); + return p - offset; + } + + /** + * @dev Encode Solidity type + * @param x The fixed-size byte array to be encoded + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol_bytes(bytes32 x, uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 size; + p += 3; + size = _encode_sol_raw_bytes_array(x, p, bs, sz); + p += size; + _encode_sol_header(size, offset, bs); + return p - offset; + } + + /** + * @dev Get the actual size needed to encoding an unsigned integer + * @param x The unsigned integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @return The number of bytes needed for encoding `x` + */ + function _get_real_size(uint256 x, uint256 sz) internal pure returns (uint256) { + uint256 base = 0xff; + uint256 realSize = sz; + while (x & (base << (realSize * BYTE_SIZE - BYTE_SIZE)) == 0 && realSize > 0) { + realSize -= 1; + } + if (realSize == 0) { + realSize = 1; + } + return realSize; + } + + /** + * @dev Get the actual size needed to encoding an signed integer + * @param x The signed integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @return The number of bytes needed for encoding `x` + */ + function _get_real_size(int256 x, uint256 sz) internal pure returns (uint256) { + int256 base = 0xff; + if (x >= 0) { + uint256 tmp = _get_real_size(uint256(x), sz); + int256 remainder = (x & (base << (tmp * BYTE_SIZE - BYTE_SIZE))) >> (tmp * BYTE_SIZE - BYTE_SIZE); + if (remainder >= 128) { + tmp += 1; + } + return tmp; + } + + uint256 realSize = sz; + while ( + x & (base << (realSize * BYTE_SIZE - BYTE_SIZE)) == (base << (realSize * BYTE_SIZE - BYTE_SIZE)) + && realSize > 0 + ) { + realSize -= 1; + } + { + int256 remainder = (x & (base << (realSize * BYTE_SIZE - BYTE_SIZE))) >> (realSize * BYTE_SIZE - BYTE_SIZE); + if (remainder < 128) { + realSize += 1; + } + } + return realSize; + } + + /** + * @dev Encode the fixed-bytes array + * @param x The fixed-size byte array to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes needed for encoding `x` + */ + function _encode_sol_raw_bytes_array(bytes32 x, uint256 p, bytes memory bs, uint256 sz) + internal + pure + returns (uint256) + { + /** + * The idea is to not encode the leading bytes of zero. + */ + uint256 actualSize = sz; + for (uint256 i = 0; i < sz; i++) { + uint8 current = uint8(x[sz - 1 - i]); + if (current == 0 && actualSize > 1) { + actualSize--; + } else { + break; + } + } + assembly { + let bsptr := add(bs, p) + let count := actualSize + for {} gt(count, 0) {} { + mstore8(bsptr, byte(sub(actualSize, count), x)) + bsptr := add(bsptr, 1) + count := sub(count, 1) + } + } + return actualSize; + } + + /** + * @dev Encode the signed integer + * @param x The signed integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes needed for encoding `x` + */ + function _encode_sol_raw_other(int256 x, uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256) { + /** + * The idea is to not encode the leading bytes of zero.or one, + * depending on whether it is positive. + */ + uint256 realSize = _get_real_size(x, sz); + assembly { + let bsptr := add(bs, p) + let count := realSize + for {} gt(count, 0) {} { + mstore8(bsptr, byte(sub(32, count), x)) + bsptr := add(bsptr, 1) + count := sub(count, 1) + } + } + return realSize; + } + + /** + * @dev Encode the unsigned integer + * @param x The unsigned integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes needed for encoding `x` + */ + function _encode_sol_raw_other(uint256 x, uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256) { + uint256 realSize = _get_real_size(x, sz); + assembly { + let bsptr := add(bs, p) + let count := realSize + for {} gt(count, 0) {} { + mstore8(bsptr, byte(sub(32, count), x)) + bsptr := add(bsptr, 1) + count := sub(count, 1) + } + } + return realSize; + } +} + +// contracts/interfaces/LightClient.sol + +interface LightClient { + /** + * addOpConsensusState adds an appHash to internal store and + * returns the fraud proof end time, and a bool flag indicating if + * the fraud proof window has passed according to the block's time stamp. + */ + function addOpConsensusState( + L1Header calldata l1header, + OpL2StateProof calldata proof, + uint256 height, + uint256 appHash + ) external returns (uint256 endTime, bool ended); + + /** + * + */ + function getFraudProofEndtime(uint256 height) external returns (uint256 endTime); + + /** + * verifyMembership checks if the current state + * can be used to perform the membership test and if so, it uses + * the verifier to perform membership check. + */ + function verifyMembership(Ics23Proof calldata proof, bytes memory key, bytes memory expectedValue) external; + + /** + * + */ + function verifyNonMembership(Ics23Proof calldata proof, bytes memory key) external; + + /** + * + */ + function getState(uint256 height) external view returns (uint256 appHash, uint256 fraudProofEndTime, bool ended); +} + +// lib/openzeppelin-contracts/contracts/access/Ownable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + +// lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ```solidity + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable_0 { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a + * constructor. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: setting the version to 255 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ```solidity + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable_1 { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a + * constructor. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: setting the version to 255 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} + +// lib/proto/GoogleProtobufAny.sol + +library GoogleProtobufAny { + //struct definition + struct Data { + string type_url; + bytes value; + } + + // Decoder section + + /** + * @dev The main decoder for memory + * @param bs The bytes array to be decoded + * @return The decoded struct + */ + function decode(bytes memory bs) internal pure returns (Data memory) { + (Data memory x,) = _decode(32, bs, bs.length); + return x; + } + + /** + * @dev The main decoder for storage + * @param self The in-storage struct + * @param bs The bytes array to be decoded + */ + function decode(Data storage self, bytes memory bs) internal { + (Data memory x,) = _decode(32, bs, bs.length); + store(x, self); + } + // inner decoder + + /** + * @dev The decoder for internal usage + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param sz The number of bytes expected + * @return The decoded struct + * @return The number of bytes decoded + */ + function _decode(uint256 p, bytes memory bs, uint256 sz) internal pure returns (Data memory, uint256) { + Data memory r; + uint256[3] memory counters; + uint256 fieldId; + ProtoBufRuntime.WireType wireType; + uint256 bytesRead; + uint256 offset = p; + uint256 pointer = p; + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 1) { + pointer += _read_type_url(pointer, bs, r, counters); + } else if (fieldId == 2) { + pointer += _read_value(pointer, bs, r, counters); + } else { + if (wireType == ProtoBufRuntime.WireType.Fixed64) { + uint256 size; + (, size) = ProtoBufRuntime._decode_fixed64(pointer, bs); + pointer += size; + } + if (wireType == ProtoBufRuntime.WireType.Fixed32) { + uint256 size; + (, size) = ProtoBufRuntime._decode_fixed32(pointer, bs); + pointer += size; + } + if (wireType == ProtoBufRuntime.WireType.Varint) { + uint256 size; + (, size) = ProtoBufRuntime._decode_varint(pointer, bs); + pointer += size; + } + if (wireType == ProtoBufRuntime.WireType.LengthDelim) { + uint256 size; + (, size) = ProtoBufRuntime._decode_lendelim(pointer, bs); + pointer += size; + } + } + } + return (r, sz); + } + + // field readers + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @param counters The counters for repeated fields + * @return The number of bytes decoded + */ + function _read_type_url(uint256 p, bytes memory bs, Data memory r, uint256[3] memory counters) + internal + pure + returns (uint256) + { + /** + * if `r` is NULL, then only counting the number of fields. + */ + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + if (isNil(r)) { + counters[1] += 1; + } else { + r.type_url = x; + if (counters[1] > 0) counters[1] -= 1; + } + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @param counters The counters for repeated fields + * @return The number of bytes decoded + */ + function _read_value(uint256 p, bytes memory bs, Data memory r, uint256[3] memory counters) + internal + pure + returns (uint256) + { + /** + * if `r` is NULL, then only counting the number of fields. + */ + (bytes memory x, uint256 sz) = ProtoBufRuntime._decode_bytes(p, bs); + if (isNil(r)) { + counters[2] += 1; + } else { + r.value = x; + if (counters[2] > 0) counters[2] -= 1; + } + return sz; + } + + // Encoder section + + /** + * @dev The main encoder for memory + * @param r The struct to be encoded + * @return The encoded byte array + */ + function encode(Data memory r) internal pure returns (bytes memory) { + bytes memory bs = new bytes(_estimate(r)); + uint256 sz = _encode(r, 32, bs); + assembly { + mstore(bs, sz) + } + return bs; + } + // inner encoder + + /** + * @dev The encoder for internal usage + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 pointer = p; + + pointer += ProtoBufRuntime._encode_key(1, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.type_url, pointer, bs); + pointer += ProtoBufRuntime._encode_key(2, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_bytes(r.value, pointer, bs); + return pointer - offset; + } + // nested encoder + + /** + * @dev The encoder for inner struct + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode_nested(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * First encoded `r` into a temporary array, and encode the actual size used. + * Then copy the temporary array into `bs`. + */ + uint256 offset = p; + uint256 pointer = p; + bytes memory tmp = new bytes(_estimate(r)); + uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp); + uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs); + uint256 size = _encode(r, 32, tmp); + pointer += ProtoBufRuntime._encode_varint(size, pointer, bs); + ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size); + pointer += size; + delete tmp; + return pointer - offset; + } + // estimator + + /** + * @dev The estimator for a struct + * @param r The struct to be encoded + * @return The number of bytes encoded in estimation + */ + function _estimate(Data memory r) internal pure returns (uint256) { + uint256 e; + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.type_url).length); + e += 1 + ProtoBufRuntime._sz_lendelim(r.value.length); + return e; + } + + //store function + /** + * @dev Store in-memory struct to storage + * @param input The in-memory struct + * @param output The in-storage struct + */ + function store(Data memory input, Data storage output) internal { + output.type_url = input.type_url; + output.value = input.value; + } + + //utility functions + /** + * @dev Return an empty struct + * @return r The empty struct + */ + function nil() internal pure returns (Data memory r) { + assembly { + r := 0 + } + } + + /** + * @dev Test whether a struct is empty + * @param x The struct to be tested + * @return r True if it is empty + */ + function isNil(Data memory x) internal pure returns (bool r) { + assembly { + r := iszero(x) + } + } +} +//library Any + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal + * representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract ContextUpgradeable is Initializable_1 { + function __Context_init() internal onlyInitializing {} + + function __Context_init_unchained() internal onlyInitializing {} + + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +// lib/proto/channel.sol + +library ProtoChannel { + //struct definition + struct Data { + int32 state; + int32 ordering; + ProtoCounterparty.Data counterparty; + string[] connection_hops; + string version; + } + + // Decoder section + + /** + * @dev The main decoder for memory + * @param bs The bytes array to be decoded + * @return The decoded struct + */ + function decode(bytes memory bs) internal pure returns (Data memory) { + (Data memory x,) = _decode(32, bs, bs.length); + return x; + } + + /** + * @dev The main decoder for storage + * @param self The in-storage struct + * @param bs The bytes array to be decoded + */ + function decode(Data storage self, bytes memory bs) internal { + (Data memory x,) = _decode(32, bs, bs.length); + store(x, self); + } + // inner decoder + + /** + * @dev The decoder for internal usage + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param sz The number of bytes expected + * @return The decoded struct + * @return The number of bytes decoded + */ + function _decode(uint256 p, bytes memory bs, uint256 sz) internal pure returns (Data memory, uint256) { + Data memory r; + uint256[6] memory counters; + uint256 fieldId; + ProtoBufRuntime.WireType wireType; + uint256 bytesRead; + uint256 offset = p; + uint256 pointer = p; + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 1) { + pointer += _read_state(pointer, bs, r); + } else if (fieldId == 2) { + pointer += _read_ordering(pointer, bs, r); + } else if (fieldId == 3) { + pointer += _read_counterparty(pointer, bs, r); + } else if (fieldId == 4) { + pointer += _read_unpacked_repeated_connection_hops(pointer, bs, nil(), counters); + } else if (fieldId == 5) { + pointer += _read_version(pointer, bs, r); + } else { + pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); + } + } + pointer = offset; + if (counters[4] > 0) { + require(r.connection_hops.length == 0); + r.connection_hops = new string[](counters[4]); + } + + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 4) { + pointer += _read_unpacked_repeated_connection_hops(pointer, bs, r, counters); + } else { + pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); + } + } + return (r, sz); + } + + // field readers + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_state(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (int32 x, uint256 sz) = ProtoBufRuntime._decode_int32(p, bs); + r.state = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_ordering(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (int32 x, uint256 sz) = ProtoBufRuntime._decode_int32(p, bs); + r.ordering = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_counterparty(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (ProtoCounterparty.Data memory x, uint256 sz) = _decode_ProtoCounterparty(p, bs); + r.counterparty = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @param counters The counters for repeated fields + * @return The number of bytes decoded + */ + function _read_unpacked_repeated_connection_hops( + uint256 p, + bytes memory bs, + Data memory r, + uint256[6] memory counters + ) internal pure returns (uint256) { + /** + * if `r` is NULL, then only counting the number of fields. + */ + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + if (isNil(r)) { + counters[4] += 1; + } else { + r.connection_hops[r.connection_hops.length - counters[4]] = x; + counters[4] -= 1; + } + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_version(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + r.version = x; + return sz; + } + + // struct decoder + /** + * @dev The decoder for reading a inner struct field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The decoded inner-struct + * @return The number of bytes used to decode + */ + function _decode_ProtoCounterparty(uint256 p, bytes memory bs) + internal + pure + returns (ProtoCounterparty.Data memory, uint256) + { + uint256 pointer = p; + (uint256 sz, uint256 bytesRead) = ProtoBufRuntime._decode_varint(pointer, bs); + pointer += bytesRead; + (ProtoCounterparty.Data memory r,) = ProtoCounterparty._decode(pointer, bs, sz); + return (r, sz + bytesRead); + } + + // Encoder section + + /** + * @dev The main encoder for memory + * @param r The struct to be encoded + * @return The encoded byte array + */ + function encode(Data memory r) internal pure returns (bytes memory) { + bytes memory bs = new bytes(_estimate(r)); + uint256 sz = _encode(r, 32, bs); + assembly { + mstore(bs, sz) + } + return bs; + } + // inner encoder + + /** + * @dev The encoder for internal usage + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 pointer = p; + uint256 i; + if (r.state != 0) { + pointer += ProtoBufRuntime._encode_key(1, ProtoBufRuntime.WireType.Varint, pointer, bs); + pointer += ProtoBufRuntime._encode_int32(r.state, pointer, bs); + } + if (r.ordering != 0) { + pointer += ProtoBufRuntime._encode_key(2, ProtoBufRuntime.WireType.Varint, pointer, bs); + pointer += ProtoBufRuntime._encode_int32(r.ordering, pointer, bs); + } + + pointer += ProtoBufRuntime._encode_key(3, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoCounterparty._encode_nested(r.counterparty, pointer, bs); + + if (r.connection_hops.length != 0) { + for (i = 0; i < r.connection_hops.length; i++) { + pointer += ProtoBufRuntime._encode_key(4, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.connection_hops[i], pointer, bs); + } + } + if (bytes(r.version).length != 0) { + pointer += ProtoBufRuntime._encode_key(5, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.version, pointer, bs); + } + return pointer - offset; + } + // nested encoder + + /** + * @dev The encoder for inner struct + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode_nested(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * First encoded `r` into a temporary array, and encode the actual size used. + * Then copy the temporary array into `bs`. + */ + uint256 offset = p; + uint256 pointer = p; + bytes memory tmp = new bytes(_estimate(r)); + uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp); + uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs); + uint256 size = _encode(r, 32, tmp); + pointer += ProtoBufRuntime._encode_varint(size, pointer, bs); + ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size); + pointer += size; + delete tmp; + return pointer - offset; + } + // estimator + + /** + * @dev The estimator for a struct + * @param r The struct to be encoded + * @return The number of bytes encoded in estimation + */ + function _estimate(Data memory r) internal pure returns (uint256) { + uint256 e; + uint256 i; + e += 1 + ProtoBufRuntime._sz_int32(r.state); + e += 1 + ProtoBufRuntime._sz_int32(r.ordering); + e += 1 + ProtoBufRuntime._sz_lendelim(ProtoCounterparty._estimate(r.counterparty)); + for (i = 0; i < r.connection_hops.length; i++) { + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.connection_hops[i]).length); + } + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.version).length); + return e; + } + // empty checker + + function _empty(Data memory r) internal pure returns (bool) { + if (r.state != 0) { + return false; + } + + if (r.ordering != 0) { + return false; + } + + if (r.connection_hops.length != 0) { + return false; + } + + if (bytes(r.version).length != 0) { + return false; + } + + return true; + } + + //store function + /** + * @dev Store in-memory struct to storage + * @param input The in-memory struct + * @param output The in-storage struct + */ + function store(Data memory input, Data storage output) internal { + output.state = input.state; + output.ordering = input.ordering; + ProtoCounterparty.store(input.counterparty, output.counterparty); + output.connection_hops = input.connection_hops; + output.version = input.version; + } + + //array helpers for ConnectionHops + /** + * @dev Add value to an array + * @param self The in-memory struct + * @param value The value to add + */ + function addConnectionHops(Data memory self, string memory value) internal pure { + /** + * First resize the array. Then add the new element to the end. + */ + string[] memory tmp = new string[](self.connection_hops.length + 1); + for (uint256 i = 0; i < self.connection_hops.length; i++) { + tmp[i] = self.connection_hops[i]; + } + tmp[self.connection_hops.length] = value; + self.connection_hops = tmp; + } + + //utility functions + /** + * @dev Return an empty struct + * @return r The empty struct + */ + function nil() internal pure returns (Data memory r) { + assembly { + r := 0 + } + } + + /** + * @dev Test whether a struct is empty + * @param x The struct to be tested + * @return r True if it is empty + */ + function isNil(Data memory x) internal pure returns (bool r) { + assembly { + r := iszero(x) + } + } +} +//library ProtoChannel + +library ProtoCounterparty { + //struct definition + struct Data { + string port_id; + string channel_id; + } + + // Decoder section + + /** + * @dev The main decoder for memory + * @param bs The bytes array to be decoded + * @return The decoded struct + */ + function decode(bytes memory bs) internal pure returns (Data memory) { + (Data memory x,) = _decode(32, bs, bs.length); + return x; + } + + /** + * @dev The main decoder for storage + * @param self The in-storage struct + * @param bs The bytes array to be decoded + */ + function decode(Data storage self, bytes memory bs) internal { + (Data memory x,) = _decode(32, bs, bs.length); + store(x, self); + } + // inner decoder + + /** + * @dev The decoder for internal usage + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param sz The number of bytes expected + * @return The decoded struct + * @return The number of bytes decoded + */ + function _decode(uint256 p, bytes memory bs, uint256 sz) internal pure returns (Data memory, uint256) { + Data memory r; + uint256 fieldId; + ProtoBufRuntime.WireType wireType; + uint256 bytesRead; + uint256 offset = p; + uint256 pointer = p; + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 1) { + pointer += _read_port_id(pointer, bs, r); + } else if (fieldId == 2) { + pointer += _read_channel_id(pointer, bs, r); + } else { + pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); + } + } + return (r, sz); + } + + // field readers + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_port_id(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + r.port_id = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_channel_id(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + r.channel_id = x; + return sz; + } + + // Encoder section + + /** + * @dev The main encoder for memory + * @param r The struct to be encoded + * @return The encoded byte array + */ + function encode(Data memory r) internal pure returns (bytes memory) { + bytes memory bs = new bytes(_estimate(r)); + uint256 sz = _encode(r, 32, bs); + assembly { + mstore(bs, sz) + } + return bs; + } + // inner encoder + + /** + * @dev The encoder for internal usage + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 pointer = p; + + if (bytes(r.port_id).length != 0) { + pointer += ProtoBufRuntime._encode_key(1, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.port_id, pointer, bs); + } + if (bytes(r.channel_id).length != 0) { + pointer += ProtoBufRuntime._encode_key(2, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.channel_id, pointer, bs); + } + return pointer - offset; + } + // nested encoder + + /** + * @dev The encoder for inner struct + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode_nested(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * First encoded `r` into a temporary array, and encode the actual size used. + * Then copy the temporary array into `bs`. + */ + uint256 offset = p; + uint256 pointer = p; + bytes memory tmp = new bytes(_estimate(r)); + uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp); + uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs); + uint256 size = _encode(r, 32, tmp); + pointer += ProtoBufRuntime._encode_varint(size, pointer, bs); + ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size); + pointer += size; + delete tmp; + return pointer - offset; + } + // estimator + + /** + * @dev The estimator for a struct + * @param r The struct to be encoded + * @return The number of bytes encoded in estimation + */ + function _estimate(Data memory r) internal pure returns (uint256) { + uint256 e; + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.port_id).length); + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.channel_id).length); + return e; + } + // empty checker + + function _empty(Data memory r) internal pure returns (bool) { + if (bytes(r.port_id).length != 0) { + return false; + } + + if (bytes(r.channel_id).length != 0) { + return false; + } + + return true; + } + + //store function + /** + * @dev Store in-memory struct to storage + * @param input The in-memory struct + * @param output The in-storage struct + */ + function store(Data memory input, Data storage output) internal { + output.port_id = input.port_id; + output.channel_id = input.channel_id; + } + + //utility functions + /** + * @dev Return an empty struct + * @return r The empty struct + */ + function nil() internal pure returns (Data memory r) { + assembly { + r := 0 + } + } + + /** + * @dev Test whether a struct is empty + * @param x The struct to be tested + * @return r True if it is empty + */ + function isNil(Data memory x) internal pure returns (bool r) { + assembly { + r := iszero(x) + } + } +} +//library ProtoCounterparty + +// lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract OwnableUpgradeable is Initializable_1, ContextUpgradeable { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + function __Ownable_init() internal onlyInitializing { + __Ownable_init_unchained(); + } + + function __Ownable_init_unchained() internal onlyInitializing { + _transferOwnership(_msgSender()); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[49] private __gap; +} + +// lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) + +/** + * @dev This abstract contract provides getters and event emitting update functions for + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. + * + * _Available since v4.1._ + */ +abstract contract ERC1967Upgrade is IERC1967 { + // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 + bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @dev Returns the current implementation address. + */ + function _getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 implementation slot. + */ + function _setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + } + + /** + * @dev Perform implementation upgrade + * + * Emits an {Upgraded} event. + */ + function _upgradeTo(address newImplementation) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + /** + * @dev Perform implementation upgrade with additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { + _upgradeTo(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + } + + /** + * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { + // Upgrades from old implementations will perform a rollback test. This test requires the new + // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing + // this special case will break upgrade paths from old UUPS implementation to new ones. + if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { + _setImplementation(newImplementation); + } else { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { + require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); + } catch { + revert("ERC1967Upgrade: new implementation is not UUPS"); + } + _upgradeToAndCall(newImplementation, data, forceCall); + } + } + + /** + * @dev Storage slot with the admin of the contract. + * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + /** + * @dev Returns the current admin. + */ + function _getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 admin slot. + */ + function _setAdmin(address newAdmin) private { + require(newAdmin != address(0), "ERC1967: new admin is the zero address"); + StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {AdminChanged} event. + */ + function _changeAdmin(address newAdmin) internal { + emit AdminChanged(_getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + /** + * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. + * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. + */ + bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + /** + * @dev Returns the current beacon. + */ + function _getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(_BEACON_SLOT).value; + } + + /** + * @dev Stores a new beacon in the EIP1967 beacon slot. + */ + function _setBeacon(address newBeacon) private { + require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); + require( + Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" + ); + StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; + } + + /** + * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does + * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). + * + * Emits a {BeaconUpgraded} event. + */ + function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); + } + } +} + +// lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol) + +/** + * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an + * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. + * + * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is + * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing + * `UUPSUpgradeable` with a custom implementation of upgrades. + * + * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. + * + * _Available since v4.1._ + */ +abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address private immutable __self = address(this); + + /** + * @dev Check that the execution is being performed through a delegatecall call and that the execution context is + * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case + * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a + * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to + * fail. + */ + modifier onlyProxy() { + require(address(this) != __self, "Function must be called through delegatecall"); + require(_getImplementation() == __self, "Function must be called through active proxy"); + _; + } + + /** + * @dev Check that the execution is not being performed through a delegate call. This allows a function to be + * callable on the implementing contract but not through proxies. + */ + modifier notDelegated() { + require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); + _; + } + + /** + * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the + * implementation. It is used to validate the implementation's compatibility when performing an upgrade. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. + */ + function proxiableUUID() external view virtual override notDelegated returns (bytes32) { + return _IMPLEMENTATION_SLOT; + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeTo(address newImplementation) public virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call + * encoded in `data`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, data, true); + } + + /** + * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by + * {upgradeTo} and {upgradeToAndCall}. + * + * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. + * + * ```solidity + * function _authorizeUpgrade(address) internal override onlyOwner {} + * ``` + */ + function _authorizeUpgrade(address newImplementation) internal virtual; +} + +// contracts/libs/Ibc.sol + +/** + * Ibc.sol + * Basic IBC data structures and utilities. + */ + +/// IbcPacket represents the packet data structure received from a remote chain +/// over an IBC channel. +struct IbcPacket { + /// identifies the channel and port on the sending chain. + IbcEndpoint src; + /// identifies the channel and port on the receiving chain. + IbcEndpoint dest; + /// The sequence number of the packet on the given channel + uint64 sequence; + bytes data; + /// block height after which the packet times out + Height timeoutHeight; + /// block timestamp (in nanoseconds) after which the packet times out + uint64 timeoutTimestamp; +} + +// UniversalPacke represents the data field of an IbcPacket +struct UniversalPacket { + bytes32 srcPortAddr; + // source middleware ids bitmap, ie. logic OR of all MW IDs in the MW stack. + uint256 mwBitmap; + bytes32 destPortAddr; + bytes appData; +} + +/// Height is a monotonically increasing data type +/// that can be compared against another Height for the purposes of updating and +/// freezing clients +/// +/// Normally the RevisionHeight is incremented at each height while keeping +/// RevisionNumber the same. However some consensus algorithms may choose to +/// reset the height in certain conditions e.g. hard forks, state-machine +/// breaking changes In these cases, the RevisionNumber is incremented so that +/// height continues to be monitonically increasing even as the RevisionHeight +/// gets reset +struct Height { + uint64 revision_number; + uint64 revision_height; +} + +struct AckPacket { + // success indicates the dApp-level logic. Even when a dApp fails to process a packet per its dApp logic, the + // delivery of packet and ack packet are still considered successful. + bool success; + bytes data; +} + +struct IncentivizedAckPacket { + bool success; + // Forward relayer's payee address, an EMV address registered on Polymer chain with `RegisterCounterpartyPayee` + // endpoint. + // In case of missing payee, zero address is used on Polymer. + // The relayer payee address is set when incentivized ack is created on Polymer. + bytes relayer; + bytes data; +} + +enum ChannelOrder { + NONE, + UNORDERED, + ORDERED +} + +enum ChannelState { + // Default State + UNINITIALIZED, + // A channel has just started the opening handshake. + INIT, + // A channel has acknowledged the handshake step on the counterparty chain. + TRYOPEN, + // A channel has completed the handshake. Open channels are + // ready to send and receive packets. + OPEN, + // A channel has been closed and can no longer be used to send or receive + // packets. + CLOSED, + // A channel has been forced closed due to a frozen client in the connection + // path. + FROZEN, + // A channel has acknowledged the handshake step on the counterparty chain, but not yet confirmed with a virtual + // chain. Virtual channel end ONLY. + TRY_PENDING, + // A channel has finished the ChanOpenAck handshake step on chain A, but not yet confirmed with the corresponding + // virtual chain. Virtual channel end ONLY. + ACK_PENDING, + // A channel has finished the ChanOpenConfirm handshake step on chain B, but not yet confirmed with the + // corresponding + // virtual chain. Virtual channel end ONLY. + CONFIRM_PENDING, + // A channel has finished the ChanCloseConfirm step on chainB, but not yet confirmed with the corresponding + // virtual chain. Virtual channel end ONLY. + CLOSE_CONFIRM_PENDING +} + +struct Channel { + string version; + ChannelOrder ordering; + bool feeEnabled; + string[] connectionHops; + string counterpartyPortId; + bytes32 counterpartyChannelId; +} + +struct ChannelEnd { + string portId; + bytes32 channelId; + string version; +} + +struct IbcEndpoint { + string portId; + bytes32 channelId; +} + +struct Proof { + // block height at which the proof is valid for a membership or non-membership at the given keyPath + Height proofHeight; + // ics23 merkle proof + bytes proof; +} + +// misc errors. +library IBCErrors { + error invalidCounterParty(); + error invalidCounterPartyPortId(); + error invalidHexStringLength(); + error invalidRelayerAddress(); + error consensusStateVerificationFailed(); + error packetNotTimedOut(); + error invalidAddress(); + + // packet sequence related errors. + error invalidPacketSequence(); + error unexpectedPacketSequence(); + + // channel related errors. + error channelNotOwnedBySender(); + error channelNotOwnedByPortAddress(); + + // client related errors. + error clientAlreadyCreated(); + error clientNotCreated(); + + // packet commitment related errors. + error packetCommitmentNotFound(); + error ackPacketCommitmentAlreadyExists(); + error packetReceiptAlreadyExists(); + + // receiver related errors. + error receiverNotIntendedPacketDestination(); + error receiverNotOriginPacketSender(); + + error invalidChannelType(string channelType); +} + +// define a library of Ibc utility functions +library IbcUtils { + error StringTooLong(); + + // fromUniversalPacketBytes converts UniversalPacketDataBytes to UniversalPacketData, per how its packed into bytes + function fromUniversalPacketBytes(bytes calldata data) + external + pure + returns (UniversalPacket memory universalPacketData) + { + bytes32 srcPortAddr; + uint256 mwBitmap; + bytes32 destPortAddr; + assembly { + // Keep reusing 0x0 to move from calldata to return vars + calldatacopy(0x0, data.offset, 32) + srcPortAddr := mload(0x0) + calldatacopy(0x0, add(data.offset, 32), 32) + mwBitmap := mload(0x0) + calldatacopy(0x0, add(data.offset, 64), 32) + destPortAddr := mload(0x0) + } + universalPacketData = UniversalPacket(srcPortAddr, uint256(mwBitmap), destPortAddr, data[96:data.length]); + } + + /** + * Convert a non-0x-prefixed hex string to an address + * @param hexStr hex string to convert to address. Note that the hex string must not include a 0x prefix. + * hexStr is case-insensitive. + */ + function hexStrToAddress(string memory hexStr) public pure returns (address addr) { + if (bytes(hexStr).length != 40) { + revert IBCErrors.invalidHexStringLength(); + } + + bytes memory strBytes = bytes(hexStr); + bytes memory addrBytes = new bytes(20); + + for (uint256 i = 0; i < 20; i++) { + uint8 high = uint8(strBytes[i * 2]); + uint8 low = uint8(strBytes[1 + i * 2]); + // Convert to lowercase if the character is in uppercase + if (high >= 65 && high <= 90) { + high += 32; + } + if (low >= 65 && low <= 90) { + low += 32; + } + uint8 digit = (high - (high >= 97 ? 87 : 48)) * 16 + (low - (low >= 97 ? 87 : 48)); + addrBytes[i] = bytes1(digit); + } + + assembly { + addr := mload(add(addrBytes, 20)) + } + + return addr; + } + + // For XXXX => vIBC direction, SC needs to verify the proof of membership of TRY_PENDING + // For vIBC initiated channel, SC doesn't need to verify any proof, and these should be all empty + function isChannelOpenTry(ChannelEnd calldata counterparty) public pure returns (bool open) { + if (counterparty.channelId == bytes32(0) && bytes(counterparty.version).length == 0) { + return false; + // ChanOpenInit with unknow conterparty + } else if (counterparty.channelId != bytes32(0) && bytes(counterparty.version).length != 0) { + // this is the ChanOpenTry; counterparty must not be zero-value + return true; + } else { + revert IBCErrors.invalidCounterParty(); + } + } + + function toUniversalPacketBytes(UniversalPacket memory data) internal pure returns (bytes memory packetBytes) { + packetBytes = bytes.concat(data.srcPortAddr, bytes32(data.mwBitmap), data.destPortAddr, data.appData); + } + + // addressToPortId converts an address to a port ID + function addressToPortId(string memory portPrefix, address addr) internal pure returns (string memory portId) { + portId = string(abi.encodePacked(portPrefix, toHexStr(addr))); + } + + // convert an address to its hex string, but without 0x prefix + function toHexStr(address addr) internal pure returns (bytes memory hexStr) { + bytes memory addrWithPrefix = abi.encodePacked(Strings.toHexString(addr)); + bytes memory addrWithoutPrefix = new bytes(addrWithPrefix.length - 2); + for (uint256 i = 0; i < addrWithoutPrefix.length; i++) { + addrWithoutPrefix[i] = addrWithPrefix[i + 2]; + } + hexStr = addrWithoutPrefix; + } + + // toAddress converts a bytes32 to an address + function toAddress(bytes32 b) internal pure returns (address out) { + out = address(uint160(uint256(b))); + } + + // toBytes32 converts an address to a bytes32 + function toBytes32(address a) internal pure returns (bytes32 out) { + out = bytes32(uint256(uint160(a))); + } + + function toBytes32(string memory s) internal pure returns (bytes32 result) { + bytes memory b = bytes(s); + if (b.length > 32) revert StringTooLong(); + + assembly { + result := mload(add(b, 32)) + } + } +} + +library Ibc { + /** + * Convert a non-0x-prefixed hex string to an address + * @param hexStr hex string to convert to address. Note that the hex string must not include a 0x prefix. + * hexStr is case-insensitive. + */ + function _hexStrToAddress(string memory hexStr) external pure returns (address addr) { + if (bytes(hexStr).length != 40) { + revert IBCErrors.invalidHexStringLength(); + } + + bytes memory strBytes = bytes(hexStr); + bytes memory addrBytes = new bytes(20); + + for (uint256 i = 0; i < 20; i++) { + uint8 high = uint8(strBytes[i * 2]); + uint8 low = uint8(strBytes[1 + i * 2]); + // Convert to lowercase if the character is in uppercase + if (high >= 65 && high <= 90) { + high += 32; + } + if (low >= 65 && low <= 90) { + low += 32; + } + uint8 digit = (high - (high >= 97 ? 87 : 48)) * 16 + (low - (low >= 97 ? 87 : 48)); + addrBytes[i] = bytes1(digit); + } + + assembly { + addr := mload(add(addrBytes, 20)) + } + } + + // For XXXX => vIBC direction, SC needs to verify the proof of membership of TRY_PENDING + // For vIBC initiated channel, SC doesn't need to verify any proof, and these should be all empty + function _isChannelOpenTry(ChannelEnd calldata counterparty) external pure returns (bool open) { + if (counterparty.channelId == bytes32(0) && bytes(counterparty.version).length == 0) { + open = false; + // ChanOpenInit with unknow conterparty + } else if (counterparty.channelId != bytes32(0) && bytes(counterparty.version).length != 0) { + // this is the ChanOpenTry; counterparty must not be zero-value + open = true; + } else { + revert IBCErrors.invalidCounterParty(); + } + } + + function toStr(bytes32 b) public pure returns (string memory outStr) { + uint8 i = 0; + while (i < 32 && b[i] != 0) { + i++; + } + bytes memory bytesArray = new bytes(i); + for (uint8 j = 0; j < i; j++) { + bytesArray[j] = b[j]; + } + outStr = string(bytesArray); + } + + function toStr(uint256 _number) public pure returns (string memory outStr) { + if (_number == 0) { + return "0"; + } + + uint256 length; + uint256 number = _number; + + // Determine the length of the string + while (number != 0) { + length++; + number /= 10; + } + + bytes memory buffer = new bytes(length); + + // Convert each digit to its ASCII representation + for (uint256 i = length; i > 0; i--) { + buffer[i - 1] = bytes1(uint8(48 + (_number % 10))); + _number /= 10; + } + + outStr = string(buffer); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/24-host/keys.go#L135 + function channelProofKey(string calldata portId, bytes32 channelId) public pure returns (bytes memory proofKey) { + proofKey = abi.encodePacked("channelEnds/ports/", portId, "/channels/", toStr(channelId)); + } + + // protobuf encoding of a channel object + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/04-channel/keeper/keeper.go#L92 + function channelProofValue( + ChannelState state, + ChannelOrder ordering, + string calldata version, + string[] calldata connectionHops, + ChannelEnd calldata counterparty + ) public pure returns (bytes memory proofValue) { + proofValue = ProtoChannel.encode( + ProtoChannel.Data( + int32(uint32(state)), + int32(uint32(ordering)), + ProtoCounterparty.Data(counterparty.portId, toStr(counterparty.channelId)), + connectionHops, + version + ) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/24-host/keys.go#L185 + function packetCommitmentProofKey(IbcPacket calldata packet) public pure returns (bytes memory proofKey) { + proofKey = abi.encodePacked( + "commitments/ports/", + packet.src.portId, + "/channels/", + toStr(packet.src.channelId), + "/sequences/", + toStr(packet.sequence) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/04-channel/types/packet.go#L19 + function packetCommitmentProofValue(IbcPacket calldata packet) public pure returns (bytes32 proofValue) { + proofValue = sha256( + abi.encodePacked( + packet.timeoutTimestamp, + packet.timeoutHeight.revision_number, + packet.timeoutHeight.revision_height, + sha256(packet.data) + ) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/24-host/keys.go#L201 + function ackProofKey(IbcPacket calldata packet) public pure returns (bytes memory proofKey) { + proofKey = abi.encodePacked( + "acks/ports/", + packet.dest.portId, + "/channels/", + toStr(packet.dest.channelId), + "/sequences/", + toStr(packet.sequence) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/04-channel/types/packet.go#L38 + function ackProofValue(bytes calldata ack) public pure returns (bytes32 proofValue) { + proofValue = sha256(ack); + } + + function parseAckData(bytes calldata ack) public pure returns (AckPacket memory ackData) { + // this hex value is '"result"' + ackData = (keccak256(ack[1:9]) == keccak256(hex"22726573756c7422")) + ? AckPacket(true, Base64.decode(string(ack[11:ack.length - 2]))) // result success + : AckPacket(false, ack[10:ack.length - 2]); // this is an error + } +} + +// contracts/interfaces/IbcDispatcher.sol + +/** + * @title IbcPacketSender + * @author Polymer Labs + * @dev IBC packet sender interface. + */ +interface IbcPacketSender { + function sendPacket(bytes32 channelId, bytes calldata payload, uint64 timeoutTimestamp) external; +} + +/** + * @title IbcDispatcher + * @author Polymer Labs + * @notice IBC dispatcher interface is the Polymer Core Smart Contract that implements the core IBC protocol. + * @dev IBC-compatible contracts depend on this interface to actively participate in the IBC protocol. + * Other features are implemented as callback methods in the IbcReceiver interface. + */ +interface IbcDispatcher is IbcPacketSender { + function channelOpenInit( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external; + + function closeIbcChannel(bytes32 channelId) external; + + function portPrefix() external view returns (string memory portPrefix); +} + +/** + * @title IbcEventsEmitter + * @notice IBC CoreSC events interface. + */ +interface IbcEventsEmitter { + // + // channel events + // + event ChannelOpenInit( + address indexed recevier, + string version, + ChannelOrder ordering, + bool feeEnabled, + string[] connectionHops, + string counterpartyPortId + ); + event ChannelOpenInitError(address indexed receiver, bytes error); + + event ChannelOpenTry( + address indexed receiver, + string version, + ChannelOrder ordering, + bool feeEnabled, + string[] connectionHops, + string counterpartyPortId, + bytes32 counterpartyChannelId + ); + event ChannelOpenTryError(address indexed receiver, bytes error); + + event ChannelOpenAck(address indexed receiver, bytes32 channelId); + event ChannelOpenAckError(address indexed receiver, bytes error); + + event ChannelOpenConfirm(address indexed receiver, bytes32 channelId); + event ChannelOpenConfirmError(address indexed receiver, bytes error); + + event CloseIbcChannel(address indexed portAddress, bytes32 indexed channelId); + + event CloseIbcChannelError(address indexed receiver, bytes error); + event AcknowledgementError(address indexed receiver, bytes error); + event TimeoutError(address indexed receiver, bytes error); + + // + // packet events + // + event SendPacket( + address indexed sourcePortAddress, + bytes32 indexed sourceChannelId, + bytes packet, + uint64 sequence, + // timeoutTimestamp is in UNIX nano seconds; packet will be rejected if + // delivered after this timestamp on the receiving chain. + // Timeout semantics is compliant to IBC spec and ibc-go implementation + uint64 timeoutTimestamp + ); + + event Acknowledgement(address indexed sourcePortAddress, bytes32 indexed sourceChannelId, uint64 sequence); + + event Timeout(address indexed sourcePortAddress, bytes32 indexed sourceChannelId, uint64 indexed sequence); + + event RecvPacket(address indexed destPortAddress, bytes32 indexed destChannelId, uint64 sequence); + + event WriteAckPacket( + address indexed writerPortAddress, bytes32 indexed writerChannelId, uint64 sequence, AckPacket ackPacket + ); + + event WriteTimeoutPacket( + address indexed writerPortAddress, + bytes32 indexed writerChannelId, + uint64 sequence, + Height timeoutHeight, + uint64 timeoutTimestamp + ); +} + +// contracts/interfaces/IbcReceiver.sol + +/** + * @title IbcChannelReceiver + * @dev This interface must be implemented by IBC-enabled contracts that act as channel owners and process channel + * handshake callbacks. + */ +interface IbcChannelReceiver { + function onChanOpenInit(string calldata version) external returns (string memory selectedVersion); + + function onChanOpenTry(string calldata counterpartyVersion) external returns (string memory selectedVersion); + + function onChanOpenAck(bytes32 channelId, string calldata counterpartyVersion) external; + + function onChanOpenConfirm(bytes32 channelId, string calldata counterpartyVersion) external; + + function onCloseIbcChannel(bytes32 channelId, string calldata counterpartyPortId, bytes32 counterpartyChannelId) + external; +} + +/** + * @title IbcPacketReceiver + * @notice Packet handler interface must be implemented by a IBC-enabled contract. + * @dev Packet handling callback methods are invoked by the IBC dispatcher. + */ +interface IbcPacketReceiver { + function onRecvPacket(IbcPacket calldata packet) external returns (AckPacket memory ackPacket); + + function onAcknowledgementPacket(IbcPacket calldata packet, AckPacket calldata ack) external; + + function onTimeoutPacket(IbcPacket calldata packet) external; +} + +/** + * @title IbcReceiver + * @author Polymer Labs + * @notice IBC receiver interface must be implemented by a IBC-enabled contract. + * The implementer, aka. dApp devs, should implement channel handshake and packet handling methods. + */ +interface IbcReceiver is IbcChannelReceiver, IbcPacketReceiver {} + +contract IbcReceiverBase is Ownable { + IbcDispatcher public dispatcher; + + error notIbcDispatcher(); + error UnsupportedVersion(); + error ChannelNotFound(); + + /** + * @dev Modifier to restrict access to only the IBC dispatcher. + * Only the address with the IBC_ROLE can execute the function. + * Should add this modifier to all IBC-related callback functions. + */ + modifier onlyIbcDispatcher() { + if (msg.sender != address(dispatcher)) { + revert notIbcDispatcher(); + } + _; + } + + /** + * @dev Constructor function that takes an IbcDispatcher address and grants the IBC_ROLE to the Polymer IBC + * Dispatcher. + * @param _dispatcher The address of the IbcDispatcher contract. + */ + constructor(IbcDispatcher _dispatcher) Ownable() { + dispatcher = _dispatcher; + } + + /// This function is called for plain Ether transfers, i.e. for every call with empty calldata. + // An empty function body is sufficient to receive packet fee refunds. + receive() external payable {} +} + +// contracts/interfaces/IDispatcher.sol + +interface IDispatcherRc3 is IbcDispatcher, IbcEventsEmitter { + function setPortPrefix(string calldata _portPrefix) external; + + function updateClientWithOptimisticConsensusState( + L1Header calldata l1header, + OpL2StateProof calldata proof, + uint256 height, + uint256 appHash + ) external returns (uint256 fraudProofEndTime, bool ended); + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenInit. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenInit( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external; + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenTry. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenTry( + ChannelEnd calldata local, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external; + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the third channel handshake method: ChanOpenAck + */ + function channelOpenAck( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external; + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the last channel handshake method: + * ChannelOpenConfirm + */ + function channelOpenConfirm( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external; + + function closeIbcChannel(bytes32 channelId) external; + + function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) external; + + function acknowledgement(IbcPacket calldata packet, bytes calldata ack, Ics23Proof calldata proof) external; + + function timeout(IbcPacket calldata packet, Ics23Proof calldata proof) external; + + function recvPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external; + + function getOptimisticConsensusState(uint256 height) + external + view + returns (uint256 appHash, uint256 fraudProofEndTime, bool ended); + + function getChannel(address portAddress, bytes32 channelId) external view returns (Channel memory channel); +} + +// contracts/core/Dispatcher.sol + +/** + * @title Dispatcher; tagged as v2.0.0-rc3 + * @author Polymer Labs + * @notice + * Contract callers call this contract to send IBC-like msg, + * which can be relayed to a rollup module on the Polymerase chain + */ +contract DispatcherRc3 is OwnableUpgradeable, UUPSUpgradeable, IDispatcherRc3 { + uint256[49] private __gap; + + // + // fields + // + // IBC_PortID = portPrefix + address (hex string without 0x prefix, case insensitive) + string public portPrefix; + uint32 public portPrefixLen; + + mapping(address => mapping(bytes32 => Channel)) private _portChannelMap; + mapping(address => mapping(bytes32 => uint64)) private _nextSequenceSend; + // keep track of received packets' sequences to ensure channel ordering is enforced for ordered channels + mapping(address => mapping(bytes32 => uint64)) private _nextSequenceRecv; + mapping(address => mapping(bytes32 => uint64)) private _nextSequenceAck; + // only stores a bit to mark packet has not been ack'ed or timed out yet; actual IBC packet verification is done on + // Polymer chain. + // Keep track of sent packets + mapping(address => mapping(bytes32 => mapping(uint64 => bool))) private _sendPacketCommitment; + // keep track of received packets to prevent replay attack + mapping(address => mapping(bytes32 => mapping(uint64 => bool))) private _recvPacketReceipt; + // keep track of outbound ack packets to prevent replay attack + mapping(address => mapping(bytes32 => mapping(uint64 => bool))) private _ackPacketCommitment; + + LightClient _lightClient; // Can't be set to immutable since it needs to be called in the initializer; not the + + //////// NEW storage + mapping(bytes32 => string) private _channelIdToConnection; + + // constructor + + // + // methods + // + constructor() { + _disableInitializers(); + } + + function initialize(string memory initPortPrefix, LightClient lightClient) public initializer { + __Ownable_init(); + portPrefix = initPortPrefix; + portPrefixLen = uint32(bytes(initPortPrefix).length); + _lightClient = lightClient; + } + + // + // CoreSC maaintainer methods, only invoked by the owner + // + function setPortPrefix(string calldata _portPrefix) external onlyOwner { + portPrefix = _portPrefix; + portPrefixLen = uint32(bytes(_portPrefix).length); + } + + // updateClientWithOptimisticConsensusState updates the client + // with the optimistic consensus state. The optimistic consensus + // is accepted and will be open for verify in the fraud proof + // window. + function updateClientWithOptimisticConsensusState( + L1Header calldata l1header, + OpL2StateProof calldata proof, + uint256 height, + uint256 appHash + ) external returns (uint256 fraudProofEndTime, bool ended) { + return _lightClient.addOpConsensusState(l1header, proof, height, appHash); + } + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenInit. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenInit( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external { + if (bytes(counterpartyPortId).length == 0) { + revert IBCErrors.invalidCounterPartyPortId(); + } + + (bool success, bytes memory data) = + _callIfContract(msg.sender, abi.encodeWithSelector(IbcChannelReceiver.onChanOpenInit.selector, version)); + + if (success) { + emit ChannelOpenInit( + msg.sender, abi.decode(data, (string)), ordering, feeEnabled, connectionHops, counterpartyPortId + ); + } else { + emit ChannelOpenInitError(msg.sender, data); + } + } + + // */ + // function channelOpenInit( + // string calldata version, + // ChannelOrder ordering, + // bool feeEnabled, + // string[] calldata connectionHops, + // string calldata counterpartyPortId + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenTry. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenTry( + ChannelEnd calldata local, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external { + if (bytes(counterparty.portId).length == 0) { + revert IBCErrors.invalidCounterPartyPortId(); + } + + _lightClient.verifyMembership( + proof, + Ibc.channelProofKey(local.portId, local.channelId), + Ibc.channelProofValue(ChannelState.TRY_PENDING, ordering, local.version, connectionHops, counterparty) + ); + + address receiver = _getAddressFromPort(local.portId); + (bool success, bytes memory data) = _callIfContract( + receiver, abi.encodeWithSelector(IbcChannelReceiver.onChanOpenTry.selector, counterparty.version) + ); + + if (success) { + emit ChannelOpenTry( + receiver, + abi.decode(data, (string)), + ordering, + feeEnabled, + connectionHops, + counterparty.portId, + counterparty.channelId + ); + } else { + emit ChannelOpenTryError(receiver, data); + } + } + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the third channel handshake method: ChanOpenAck + */ + function channelOpenAck( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external { + _lightClient.verifyMembership( + proof, + Ibc.channelProofKey(local.portId, local.channelId), + Ibc.channelProofValue(ChannelState.ACK_PENDING, ordering, local.version, connectionHops, counterparty) + ); + + address receiver = _getAddressFromPort(local.portId); + (bool success, bytes memory data) = _callIfContract( + receiver, + abi.encodeWithSelector(IbcChannelReceiver.onChanOpenAck.selector, local.channelId, counterparty.version) + ); + + if (success) { + _connectChannel(IbcChannelReceiver(receiver), local, connectionHops, ordering, feeEnabled, counterparty); + emit ChannelOpenAck(receiver, local.channelId); + } else { + emit ChannelOpenAckError(receiver, data); + } + } + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the last channel handshake method: + * ChannelOpenConfirm + */ + function channelOpenConfirm( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external { + _lightClient.verifyMembership( + proof, + Ibc.channelProofKey(local.portId, local.channelId), + Ibc.channelProofValue(ChannelState.CONFIRM_PENDING, ordering, local.version, connectionHops, counterparty) + ); + + address receiver = _getAddressFromPort(local.portId); + (bool success, bytes memory data) = _callIfContract( + receiver, + abi.encodeWithSelector(IbcChannelReceiver.onChanOpenConfirm.selector, local.channelId, counterparty.version) + ); + + if (success) { + _connectChannel(IbcChannelReceiver(receiver), local, connectionHops, ordering, feeEnabled, counterparty); + emit ChannelOpenConfirm(receiver, local.channelId); + } else { + emit ChannelOpenConfirmError(receiver, data); + } + } + + /** + * @dev Emits a `CloseIbcChannel` event with the given `channelId` and the address of the message sender + * @notice Close the specified IBC channel by channel ID + * Must be called by the channel owner, ie. _portChannelMap[msg.sender][channelId] must exist + */ + function closeIbcChannel(bytes32 channelId) external { + Channel memory channel = _portChannelMap[msg.sender][channelId]; + if (channel.counterpartyChannelId == bytes32(0)) { + revert IBCErrors.channelNotOwnedBySender(); + } + + (bool success, bytes memory data) = _callIfContract( + msg.sender, + abi.encodeWithSelector( + IbcChannelReceiver.onCloseIbcChannel.selector, + channelId, + channel.counterpartyPortId, + channel.counterpartyChannelId + ) + ); + if (success) { + emit CloseIbcChannel(msg.sender, channelId); + } else { + emit CloseIbcChannelError(address(msg.sender), data); + } + } + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed ChanCloseConfirm event. + * The dApp's onCloseIbcChannel callback is invoked. + * dApp should throw an error if the channel should not be closed. + */ + // FIXME this is commented out to make the contract size smaller. We need to optimise for size + // function onCloseIbcChannel(address portAddress, bytes32 channelId, Ics23Proof calldata proof) external { + // // verify VIBC/IBC hub chain has processed ChanCloseConfirm event + // _lightClient.verifyMembership( + // proof, + // bytes('channel/path/to/be/added/here'), + // bytes('expected channel bytes constructed from params. Channel.State = {Closed(_Pending?)}') + // ); + // + // // ensure port owns channel + // Channel memory channel = _portChannelMap[portAddress][channelId]; + // if (channel.counterpartyChannelId == bytes32(0)) { + // revert channelNotOwnedByPortAddress(); + // } + // + // // confirm with dApp by calling its callback + // IbcChannelReceiver reciever = IbcChannelReceiver(portAddress); + // reciever.onCloseIbcChannel(channelId, channel.counterpartyPortId, channel.counterpartyChannelId); + // delete _portChannelMap[portAddress][channelId]; + // emit CloseIbcChannel(portAddress, channelId); + // } + + // + // IBC Packet methods + // + + /** + * @notice Sends an IBC packet on a existing channel with the specified packet data and timeout block timestamp. + * @notice Data should be encoded in a format defined by the channel version, and the module on the other side + * should know how to parse this. + * @dev Emits an `IbcPacketEvent` event containing the sender address, channel ID, packet data, and timeout block + * timestamp. + * @param channelId The ID of the channel on which to send the packet. + * @param packet The packet data to send. + * @param timeoutTimestamp The timestamp in nanoseconds after which the packet times out if it has not been + * received. + */ + function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) external { + // ensure port owns channel + Channel memory channel = _portChannelMap[msg.sender][channelId]; + if (channel.counterpartyChannelId == bytes32(0)) { + revert IBCErrors.channelNotOwnedBySender(); + } + + _sendPacket(msg.sender, channelId, packet, timeoutTimestamp); + } + /** + * @notice Handle the acknowledgement of an IBC packet by the counterparty + * @dev Verifies the given proof and calls the `onAcknowledgementPacket` function on the given `receiver` contract, + * ie. the IBC dApp. + * Prerequisite: the original packet is committed and not ack'ed or timed out yet. + * Note: If the receiving dapp doesn't satisfy the interface, the transaction will be reverted. + * @param packet The IbcPacket data for the acknowledged packet + * @param ack The acknowledgement receipt for the packet + * @param proof The membership proof to verify the packet acknowledgement committed on Polymer chain + */ + + function acknowledgement(IbcPacket calldata packet, bytes calldata ack, Ics23Proof calldata proof) external { + address receiver = _getAddressFromPort(packet.src.portId); + // prove ack packet is on Polymer chain + _lightClient.verifyMembership(proof, Ibc.ackProofKey(packet), abi.encode(Ibc.ackProofValue(ack))); + // verify packet has been committed and not yet ack'ed or timed out + bool hasCommitment = _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + if (!hasCommitment) { + revert IBCErrors.packetCommitmentNotFound(); + } + + // enforce ack'ed packet sequences always increment by 1 for ordered channels + Channel memory channel = _portChannelMap[receiver][packet.src.channelId]; + (bool success, bytes memory data) = _callIfContract( + receiver, + abi.encodeWithSelector(IbcPacketReceiver.onAcknowledgementPacket.selector, packet, Ibc.parseAckData(ack)) + ); + + if (success) { + if (channel.ordering == ChannelOrder.ORDERED) { + if (packet.sequence != _nextSequenceAck[receiver][packet.src.channelId]) { + revert IBCErrors.unexpectedPacketSequence(); + } + + _nextSequenceAck[receiver][packet.src.channelId] = packet.sequence + 1; + } + + // delete packet commitment to avoid double ack + delete _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + emit Acknowledgement(receiver, packet.src.channelId, packet.sequence); + } else { + emit AcknowledgementError(receiver, data); + } + } + + /** + * @notice Timeout of an IBC packet + * @dev Verifies the given proof and calls the `onTimeoutPacket` function on the given `receiver` contract, ie. the + * IBC-dApp. + * Prerequisite: the original packet is committed and not ack'ed or timed out yet. + * If the receiving dapp doesn't satisfy the interface, the transaction will be reverted. + * @param packet The IbcPacket data for the timed-out packet + * @param proof The non-membership proof data needed to verify the packet timeout + */ + function timeout(IbcPacket calldata packet, Ics23Proof calldata proof) external { + // prove absence of packet receipt on Polymer chain + // TODO: add non membership support + _lightClient.verifyNonMembership(proof, "packet/receipt/path"); + + address receiver = _getAddressFromPort(packet.src.portId); + // verify packet has been committed and not yet ack'ed or timed out + bool hasCommitment = _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + if (!hasCommitment) { + revert IBCErrors.packetCommitmentNotFound(); + } + + (bool success, bytes memory data) = + _callIfContract(receiver, abi.encodeWithSelector(IbcPacketReceiver.onTimeoutPacket.selector, packet)); + if (success) { + // delete packet commitment to avoid double timeout + delete _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + emit Timeout(receiver, packet.src.channelId, packet.sequence); + } else { + emit TimeoutError(receiver, data); + } + } + + /** + * @notice Receive an IBC packet and then pass it to the IBC-dApp for processing if verification succeeds. + * @dev Verifies the given proof and calls the `onRecvPacket` function on the given `receiver` contract + * If the address doesn't satisfy the interface, the transaction will be reverted. + * The receiver must be the intended packet destination, which is the same as packet.dest.portId. + * @param packet The IbcPacket data for the received packet + * @param proof The proof data needed to verify the packet receipt + * @dev Emit an `RecvPacket` event with the details of the received packet; + * Also emit a WriteAckPacket event, which can be relayed to Polymer chain by relayers + */ + function recvPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external { + address receiver = _getAddressFromPort(packet.dest.portId); + _lightClient.verifyMembership( + proof, Ibc.packetCommitmentProofKey(packet), abi.encode(Ibc.packetCommitmentProofValue(packet)) + ); + + // verify packet has not been received yet + bool hasReceipt = _recvPacketReceipt[receiver][packet.dest.channelId][packet.sequence]; + if (hasReceipt) { + revert IBCErrors.packetReceiptAlreadyExists(); + } + + _recvPacketReceipt[receiver][packet.dest.channelId][packet.sequence] = true; + + // enforce recv'ed packet sequences always increment by 1 for ordered channels + Channel memory channel = _portChannelMap[receiver][packet.dest.channelId]; + if (channel.ordering == ChannelOrder.ORDERED) { + if (packet.sequence != _nextSequenceRecv[receiver][packet.dest.channelId]) { + revert IBCErrors.unexpectedPacketSequence(); + } + + _nextSequenceRecv[receiver][packet.dest.channelId] = packet.sequence + 1; + } + + // Emit recv packet event to prove the relayer did the correct job, and pkt is received. + emit RecvPacket(receiver, packet.dest.channelId, packet.sequence); + + // If pkt is already timed out, then return early so dApps won't receive it. + if (_isPacketTimeout(packet)) { + emit WriteTimeoutPacket( + receiver, packet.dest.channelId, packet.sequence, packet.timeoutHeight, packet.timeoutTimestamp + ); + return; + } + + // Not timeout yet, then do normal handling + IbcPacket memory pkt = packet; + AckPacket memory ack; + (bool success, bytes memory data) = + _callIfContract(receiver, abi.encodeWithSelector(IbcPacketReceiver.onRecvPacket.selector, pkt)); + if (success) { + (ack) = abi.decode(data, (AckPacket)); + } else { + ack = AckPacket(false, data); + } + bool hasAckPacketCommitment = _ackPacketCommitment[receiver][packet.dest.channelId][packet.sequence]; + // check is not necessary for sync-acks + if (hasAckPacketCommitment) { + revert IBCErrors.ackPacketCommitmentAlreadyExists(); + } + + _ackPacketCommitment[receiver][packet.dest.channelId][packet.sequence] = true; + + emit WriteAckPacket(receiver, packet.dest.channelId, packet.sequence, ack); + } + + // TODO: add async writeAckPacket + // // this can be invoked sync or async by the IBC-dApp + // function writeAckPacket(IbcPacket calldata packet, AckPacket calldata ackPacket) external { + // // verify `receiver` is the original packet sender + // require( + // portIdAddressMatch(address(msg.sender), packet.src.portId), + // 'Receiver is not the original packet sender' + // ); + // } + + // TODO: remove below writeTimeoutPacket() function + // 1. core SC is responsible to generate timeout packet + // 2. user contract are not free to generate timeout with different criteria + // 3. [optional]: we may wish relayer to trigger timeout process, but in this case, belowunction won't do + // the job, as it doesn't have proofs. + // There is no strong reason to do this, as relayer can always do the regular `recvPacket` flow, which will + // do proper timeout generation. + /** + * Generate a timeout packet for the given packet + */ + function writeTimeoutPacket(IbcPacket calldata packet) external { + address receiver = _getAddressFromPort(packet.src.portId); + // verify packet does not have a receipt + bool hasReceipt = _recvPacketReceipt[receiver][packet.dest.channelId][packet.sequence]; + if (hasReceipt) { + revert IBCErrors.packetReceiptAlreadyExists(); + } + + // verify packet has timed out; zero-value in packet.timeout means no timeout set + if (!_isPacketTimeout(packet)) { + revert IBCErrors.packetNotTimedOut(); + } + + emit WriteTimeoutPacket( + receiver, packet.dest.channelId, packet.sequence, packet.timeoutHeight, packet.timeoutTimestamp + ); + } + + /** + * @notice Get the IBC channel with the specified port and channel ID + * @param portAddress EVM address of the IBC port + * @param channelId IBC channel ID from the port perspective + * @return channel A channel struct is always returned. If it doesn't exists, the channel struct is populated with + * default + * values per EVM. + */ + function getChannel(address portAddress, bytes32 channelId) external view returns (Channel memory channel) { + channel = _portChannelMap[portAddress][channelId]; + } + + // getOptimisticConsensusState + function getOptimisticConsensusState(uint256 height) + external + view + returns (uint256 appHash, uint256 fraudProofEndTime, bool ended) + { + return _lightClient.getState(height); + } + + // verify an EVM address matches an IBC portId. + // IBC_PortID = portPrefix + address (hex string without 0x prefix, case-insensitive) + // function portIdAddressMatch(address addr, string calldata portId) public view returns (bool isMatch) { + // if (keccak256(abi.encodePacked(portPrefix)) != keccak256(abi.encodePacked(portId[0:portPrefixLen]))) { + // return false; + // } + // string memory portSuffix = portId[portPrefixLen:]; + // isMatch = Ibc._hexStrToAddress(portSuffix) == addr; + // } + + // Prerequisite: must verify sender is authorized to send packet on the channel + function _sendPacket(address sender, bytes32 channelId, bytes memory packet, uint64 timeoutTimestamp) internal { + // current packet sequence + uint64 sequence = _nextSequenceSend[sender][channelId]; + if (sequence == 0) { + revert IBCErrors.invalidPacketSequence(); + } + + // packet commitment + _sendPacketCommitment[sender][channelId][sequence] = true; + // increment nextSendPacketSequence + _nextSequenceSend[sender][channelId] = sequence + 1; + + emit SendPacket(sender, channelId, packet, sequence, timeoutTimestamp); + } + + function _connectChannel( + IbcChannelReceiver portAddress, + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty + ) internal { + // Register port and channel mapping + // TODO: check duplicated channel registration? + // TODO: The call to `Channel` constructor MUST be move to `openIbcChannel` phase + // Then `connectIbcChannel` phase can use the `version` as part of `require` condition. + _portChannelMap[address(portAddress)][local.channelId] = Channel( + counterparty.version, // TODO: this should be self version instead of counterparty version + ordering, + feeEnabled, + connectionHops, + counterparty.portId, + counterparty.channelId + ); + + // initialize channel sequences + _nextSequenceSend[address(portAddress)][local.channelId] = 1; + _nextSequenceRecv[address(portAddress)][local.channelId] = 1; + _nextSequenceAck[address(portAddress)][local.channelId] = 1; + _channelIdToConnection[local.channelId] = connectionHops[0]; // Set channel to connection mapping for finding + } + + // Returns the result of the call if no revert, otherwise returns the error if thrown. + function _callIfContract(address receiver, bytes memory args) + internal + returns (bool success, bytes memory message) + { + if (!Address.isContract(receiver)) { + return (false, bytes("call to non-contract")); + } + // Only call if we are sure receiver is a contract + // Note: This tx won't revert if the low-level call fails, see + // https://docs.soliditylang.org/en/latest/cheatsheet.html#members-of-address + (success, message) = receiver.call(args); + } + + function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} + + // _isPacketTimeout returns true if the given packet has timed out acoording to host chain's block height and + // timestamp + function _isPacketTimeout(IbcPacket calldata packet) internal view returns (bool isTimeOut) { + return ( + isTimeOut = (packet.timeoutTimestamp != 0 && block.timestamp >= packet.timeoutTimestamp) + // TODO: check timeoutHeight.revision_number? + || (packet.timeoutHeight.revision_height != 0 && block.number >= packet.timeoutHeight.revision_height) + ); + } + + function _getAddressFromPort(string calldata port) internal view returns (address addr) { + addr = Ibc._hexStrToAddress(port[portPrefixLen:]); + } +} diff --git a/test/upgradeableProxy/upgrades/DispatcherRc4.sol b/test/upgradeableProxy/upgrades/DispatcherRc4.sol new file mode 100644 index 00000000..c933e8e0 --- /dev/null +++ b/test/upgradeableProxy/upgrades/DispatcherRc4.sol @@ -0,0 +1,6352 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.0 ^0.8.0 ^0.8.1 ^0.8.15 ^0.8.2 ^0.8.9; + +// contracts/interfaces/ProofVerifier.sol + +struct OpIcs23ProofPath { + bytes prefix; + bytes suffix; +} + +struct OpIcs23Proof { + OpIcs23ProofPath[] path; + bytes key; + bytes value; + bytes prefix; +} + +// the Ics23 proof related structs are used to do membership verification. These are not the actual Ics23 +// format but a "solidity friendly" version of it - data is the same just packaged differently +struct Ics23Proof { + OpIcs23Proof[] proof; + uint256 height; +} + +// This is the proof we use to verify the apphash (state) updates. +struct OpL2StateProof { + bytes[] accountProof; + bytes[] outputRootProof; + bytes32 l2OutputProposalKey; + bytes32 l2BlockHash; +} + +// The `header` field is a list of RLP encoded L1 header fields. Both stateRoot and number are not +// encoded for easy usage. They must match with their RLP encoded counterparty versions. +struct L1Header { + bytes[] header; + bytes32 stateRoot; + uint64 number; +} + +interface ProofVerifier { + error InvalidL1BlockNumber(); + error InvalidL1BlockHash(); + error InvalidRLPEncodedL1BlockNumber(); + error InvalidRLPEncodedL1StateRoot(); + error InvalidAppHash(); + error InvalidProofKey(); + error InvalidProofValue(); + error InvalidPacketProof(); + error InvalidIbcStateProof(); + error MethodNotImplemented(); + + /** + * @dev verifies if a state update (apphash) is valid, given the provided proofs. + * Reverts in case of failure. + * + * @param l1header RLP "encoded" version of the L1 header that matches with the trusted hash and number + * @param proof l2 state proof. It includes the keys, hashes and storage proofs required to verify the app hash + * @param appHash l2 app hash (state root) to be verified + * @param trustedL1BlockHash trusted L1 block hash. Provided L1 header must match with it. + * @param trustedL1BlockNumber trusted L1 block number. Provided L1 header must match with it. + */ + function verifyStateUpdate( + L1Header calldata l1header, + OpL2StateProof calldata proof, + bytes32 appHash, + bytes32 trustedL1BlockHash, + uint64 trustedL1BlockNumber + ) external view; + + /** + * @dev verifies the provided ICS23 proof given the trusted app hash. Reverts in case of failure. + * + * @param appHash trusted l2 app hash (state root) + * @param key key to be proven + * @param value value to be proven + * @param proof ICS23 membership proof + */ + function verifyMembership(bytes32 appHash, bytes calldata key, bytes calldata value, Ics23Proof calldata proof) + external + pure; + + /** + * @dev verifies the provided ICS23 proof given the trusted app hash. Reverts in case of failure. + * + * @param appHash trusted l2 app hash (state root) + * @param key key to be proven non-existing + * @param proof ICS23 non-membership proof + */ + function verifyNonMembership(bytes32 appHash, bytes calldata key, Ics23Proof calldata proof) external pure; +} + +// lib/base64/base64.sol + +/// @title Base64 +/// @author Brecht Devos - <brecht@loopring.org> +/// @notice Provides functions for encoding/decoding base64 +library Base64 { + string internal constant TABLE_ENCODE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + bytes internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000" + hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000" + hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000" + hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000"; + + function encode(bytes memory data) internal pure returns (string memory) { + if (data.length == 0) return ""; + + // load the table into memory + string memory table = TABLE_ENCODE; + + // multiply by 4/3 rounded up + uint256 encodedLen = 4 * ((data.length + 2) / 3); + + // add some extra buffer at the end required for the writing + string memory result = new string(encodedLen + 32); + + assembly { + // set the actual output length + mstore(result, encodedLen) + + // prepare the lookup table + let tablePtr := add(table, 1) + + // input ptr + let dataPtr := data + let endPtr := add(dataPtr, mload(data)) + + // result ptr, jump over length + let resultPtr := add(result, 32) + + // run over the input, 3 bytes at a time + for {} lt(dataPtr, endPtr) {} { + // read 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // write 4 characters + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) + } + + // padding with '=' + switch mod(mload(data), 3) + case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) } + case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) } + } + + return result; + } + + function decode(string memory _data) internal pure returns (bytes memory) { + bytes memory data = bytes(_data); + + if (data.length == 0) return new bytes(0); + require(data.length % 4 == 0, "invalid base64 decoder input"); + + // load the table into memory + bytes memory table = TABLE_DECODE; + + // every 4 characters represent 3 bytes + uint256 decodedLen = (data.length / 4) * 3; + + // add some extra buffer at the end required for the writing + bytes memory result = new bytes(decodedLen + 32); + + assembly { + // padding with '=' + let lastBytes := mload(add(data, mload(data))) + if eq(and(lastBytes, 0xFF), 0x3d) { + decodedLen := sub(decodedLen, 1) + if eq(and(lastBytes, 0xFFFF), 0x3d3d) { decodedLen := sub(decodedLen, 1) } + } + + // set the actual output length + mstore(result, decodedLen) + + // prepare the lookup table + let tablePtr := add(table, 1) + + // input ptr + let dataPtr := data + let endPtr := add(dataPtr, mload(data)) + + // result ptr, jump over length + let resultPtr := add(result, 32) + + // run over the input, 4 characters at a time + for {} lt(dataPtr, endPtr) {} { + // read 4 characters + dataPtr := add(dataPtr, 4) + let input := mload(dataPtr) + + // write 3 bytes + let output := + add( + add( + shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)), + shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF)) + ), + add( + shl(6, and(mload(add(tablePtr, and(shr(8, input), 0xFF))), 0xFF)), + and(mload(add(tablePtr, and(input, 0xFF))), 0xFF) + ) + ) + mstore(resultPtr, shl(232, output)) + resultPtr := add(resultPtr, 3) + } + } + + return result; + } +} + +// lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) + +/** + * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. + * + * _Available since v4.8.3._ + */ +interface IERC1967 { + /** + * @dev Emitted when the implementation is upgraded. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Emitted when the admin account has changed. + */ + event AdminChanged(address previousAdmin, address newAdmin); + + /** + * @dev Emitted when the beacon is changed. + */ + event BeaconUpgraded(address indexed beacon); +} + +// lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol + +// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) + +/** + * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified + * proxy whose upgrades are fully controlled by the current implementation. + */ +interface IERC1822Proxiable { + /** + * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation + * address. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. + */ + function proxiableUUID() external view returns (bytes32); +} + +// lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol + +// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) + +/** + * @dev This is the interface that {BeaconProxy} expects of its beacon. + */ +interface IBeacon { + /** + * @dev Must return an address that can be used as a delegate call target. + * + * {BeaconProxy} will check that this address is a contract. + */ + function implementation() external view returns (address); +} + +// lib/openzeppelin-contracts/contracts/utils/Address.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * + * Furthermore, `isContract` will also return true if the target contract within + * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, + * which only has an effect at the end of a transaction. + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions + * pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success,) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use + * https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) + internal + returns (bytes memory) + { + require(address(this).balance >= value, "Address: insufficient balance for call"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) + internal + view + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) + internal + pure + returns (bytes memory) + { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/Context.sol + +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} + +// lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) +// This file was procedurally generated from scripts/generate/templates/StorageSlot.js. + +/** + * @dev Library for reading and writing primitive types to specific storage slots. + * + * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. + * This library helps with reading and writing to such slots without the need for inline assembly. + * + * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. + * + * Example usage to set ERC1967 implementation slot: + * ```solidity + * contract ERC1967 { + * bytes32 internal constant _IMPLEMENTATION_SLOT = + * 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + * + * function _getImplementation() internal view returns (address) { + * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + * } + * + * function _setImplementation(address newImplementation) internal { + * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * ``` + * + * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ + * _Available since v4.9 for `string`, `bytes`._ + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `StringSlot` with member `value` located at `slot`. + */ + function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `StringSlot` representation of the string storage pointer `store`. + */ + function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := store.slot + } + } + + /** + * @dev Returns an `BytesSlot` with member `value` located at `slot`. + */ + function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. + */ + function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := store.slot + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Down, // Toward negative infinity + Up, // Toward infinity + Zero // Toward zero + + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds up instead + * of rounding down. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0 + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) + * with further edits by Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always + // >= 1. + // See https://cs.stackexchange.com/q/138556/92363. + + // Does not overflow because the denominator cannot be zero at this stage in the function. + uint256 twos = denominator & (~denominator + 1); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works + // in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} + +// lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol + +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) + +/** + * @dev Collection of functions related to the address type + */ +library AddressUpgradeable { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * + * Furthermore, `isContract` will also return true if the target contract within + * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, + * which only has an effect at the end of a transaction. + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions + * pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success,) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use + * https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) + internal + returns (bytes memory) + { + require(address(this).balance >= value, "Address: insufficient balance for call"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data, string memory errorMessage) + internal + view + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data, string memory errorMessage) + internal + returns (bytes memory) + { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) + internal + pure + returns (bytes memory) + { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} + +// lib/proto/ProtoBufRuntime.sol + +/** + * @title Runtime library for ProtoBuf serialization and/or deserialization. + * All ProtoBuf generated code will use this library. + */ +library ProtoBufRuntime { + // Types defined in ProtoBuf + enum WireType { + Varint, + Fixed64, + LengthDelim, + StartGroup, + EndGroup, + Fixed32 + } + // Constants for bytes calculation + + uint256 constant WORD_LENGTH = 32; + uint256 constant HEADER_SIZE_LENGTH_IN_BYTES = 4; + uint256 constant BYTE_SIZE = 8; + uint256 constant REMAINING_LENGTH = WORD_LENGTH - HEADER_SIZE_LENGTH_IN_BYTES; + string constant OVERFLOW_MESSAGE = "length overflow"; + + //Storages + /** + * @dev Encode to storage location using assembly to save storage space. + * @param location The location of storage + * @param encoded The encoded ProtoBuf bytes + */ + function encodeStorage(bytes storage location, bytes memory encoded) internal { + /** + * This code use the first four bytes as size, + * and then put the rest of `encoded` bytes. + */ + uint256 length = encoded.length; + uint256 firstWord; + uint256 wordLength = WORD_LENGTH; + uint256 remainingLength = REMAINING_LENGTH; + + assembly { + firstWord := mload(add(encoded, wordLength)) + } + firstWord = + (firstWord >> (BYTE_SIZE * HEADER_SIZE_LENGTH_IN_BYTES)) | (length << (BYTE_SIZE * REMAINING_LENGTH)); + + assembly { + sstore(location.slot, firstWord) + } + + if (length > REMAINING_LENGTH) { + length -= REMAINING_LENGTH; + for (uint256 i = 0; i < ceil(length, WORD_LENGTH); i++) { + assembly { + let offset := add(mul(i, wordLength), remainingLength) + let slotIndex := add(i, 1) + sstore(add(location.slot, slotIndex), mload(add(add(encoded, wordLength), offset))) + } + } + } + } + + /** + * @dev Decode storage location using assembly using the format in `encodeStorage`. + * @param location The location of storage + * @return The encoded bytes + */ + function decodeStorage(bytes storage location) internal view returns (bytes memory) { + /** + * This code is to decode the first four bytes as size, + * and then decode the rest using the decoded size. + */ + uint256 firstWord; + uint256 remainingLength = REMAINING_LENGTH; + uint256 wordLength = WORD_LENGTH; + + assembly { + firstWord := sload(location.slot) + } + + uint256 length = firstWord >> (BYTE_SIZE * REMAINING_LENGTH); + bytes memory encoded = new bytes(length); + + assembly { + mstore(add(encoded, remainingLength), firstWord) + } + + if (length > REMAINING_LENGTH) { + length -= REMAINING_LENGTH; + for (uint256 i = 0; i < ceil(length, WORD_LENGTH); i++) { + assembly { + let offset := add(mul(i, wordLength), remainingLength) + let slotIndex := add(i, 1) + mstore(add(add(encoded, wordLength), offset), sload(add(location.slot, slotIndex))) + } + } + } + return encoded; + } + + /** + * @dev Fast memory copy of bytes using assembly. + * @param src The source memory address + * @param dest The destination memory address + * @param len The length of bytes to copy + */ + function copyBytes(uint256 src, uint256 dest, uint256 len) internal pure { + if (len == 0) { + return; + } + + // Copy word-length chunks while possible + for (; len > WORD_LENGTH; len -= WORD_LENGTH) { + assembly { + mstore(dest, mload(src)) + } + dest += WORD_LENGTH; + src += WORD_LENGTH; + } + + // Copy remaining bytes + uint256 mask = 256 ** (WORD_LENGTH - len) - 1; + assembly { + let srcpart := and(mload(src), not(mask)) + let destpart := and(mload(dest), mask) + mstore(dest, or(destpart, srcpart)) + } + } + + /** + * @dev Use assembly to get memory address. + * @param r The in-memory bytes array + * @return The memory address of `r` + */ + function getMemoryAddress(bytes memory r) internal pure returns (uint256) { + uint256 addr; + assembly { + addr := r + } + return addr; + } + + /** + * @dev Implement Math function of ceil + * @param a The denominator + * @param m The numerator + * @return r The result of ceil(a/m) + */ + function ceil(uint256 a, uint256 m) internal pure returns (uint256 r) { + return (a + m - 1) / m; + } + + // Decoders + /** + * This section of code `_decode_(u)int(32|64)`, `_decode_enum` and `_decode_bool` + * is to decode ProtoBuf native integers, + * using the `varint` encoding. + */ + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_uint32(uint256 p, bytes memory bs) internal pure returns (uint32, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + return (uint32(varint), sz); + } + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_uint64(uint256 p, bytes memory bs) internal pure returns (uint64, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + return (uint64(varint), sz); + } + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_int32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + int32 r; + assembly { + r := varint + } + return (r, sz); + } + + /** + * @dev Decode integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_int64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + int64 r; + assembly { + r := varint + } + return (r, sz); + } + + /** + * @dev Decode enum + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded enum's integer + * @return The length of `bs` used to get decoded + */ + function _decode_enum(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + return _decode_int64(p, bs); + } + + /** + * @dev Decode enum + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded boolean + * @return The length of `bs` used to get decoded + */ + function _decode_bool(uint256 p, bytes memory bs) internal pure returns (bool, uint256) { + (uint256 varint, uint256 sz) = _decode_varint(p, bs); + if (varint == 0) { + return (false, sz); + } + return (true, sz); + } + + /** + * This section of code `_decode_sint(32|64)` + * is to decode ProtoBuf native signed integers, + * using the `zig-zag` encoding. + */ + + /** + * @dev Decode signed integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_sint32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (int256 varint, uint256 sz) = _decode_varints(p, bs); + return (int32(varint), sz); + } + + /** + * @dev Decode signed integers + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded integer + * @return The length of `bs` used to get decoded + */ + function _decode_sint64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (int256 varint, uint256 sz) = _decode_varints(p, bs); + return (int64(varint), sz); + } + + /** + * @dev Decode string + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded string + * @return The length of `bs` used to get decoded + */ + function _decode_string(uint256 p, bytes memory bs) internal pure returns (string memory, uint256) { + (bytes memory x, uint256 sz) = _decode_lendelim(p, bs); + return (string(x), sz); + } + + /** + * @dev Decode bytes array + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded bytes array + * @return The length of `bs` used to get decoded + */ + function _decode_bytes(uint256 p, bytes memory bs) internal pure returns (bytes memory, uint256) { + return _decode_lendelim(p, bs); + } + + /** + * @dev Decode ProtoBuf key + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded field ID + * @return The decoded WireType specified in ProtoBuf + * @return The length of `bs` used to get decoded + */ + function _decode_key(uint256 p, bytes memory bs) internal pure returns (uint256, WireType, uint256) { + (uint256 x, uint256 n) = _decode_varint(p, bs); + WireType typeId = WireType(x & 7); + uint256 fieldId = x / 8; + return (fieldId, typeId, n); + } + + /** + * @dev Decode ProtoBuf varint + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded unsigned integer + * @return The length of `bs` used to get decoded + */ + function _decode_varint(uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + /** + * Read a byte. + * Use the lower 7 bits and shift it to the left, + * until the most significant bit is 0. + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 x = 0; + uint256 sz = 0; + uint256 length = bs.length + WORD_LENGTH; + assembly { + let b := 0x80 + p := add(bs, p) + for {} eq(0x80, and(b, 0x80)) {} { + if eq(lt(sub(p, bs), length), 0) { + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) //error function + // selector + mstore(4, 32) + mstore(36, 15) + mstore(68, 0x6c656e677468206f766572666c6f770000000000000000000000000000000000) // length overflow in + // hex + revert(0, 83) + } + let tmp := mload(p) + let pos := 0 + for {} and(eq(0x80, and(b, 0x80)), lt(pos, 32)) {} { + if eq(lt(sub(p, bs), length), 0) { + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) //error function + // selector + mstore(4, 32) + mstore(36, 15) + mstore(68, 0x6c656e677468206f766572666c6f770000000000000000000000000000000000) // length + // overflow in hex + revert(0, 83) + } + b := byte(pos, tmp) + x := or(x, shl(mul(7, sz), and(0x7f, b))) + sz := add(sz, 1) + pos := add(pos, 1) + p := add(p, 0x01) + } + } + } + return (x, sz); + } + + /** + * @dev Decode ProtoBuf zig-zag encoding + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded signed integer + * @return The length of `bs` used to get decoded + */ + function _decode_varints(uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + (uint256 u, uint256 sz) = _decode_varint(p, bs); + int256 s; + assembly { + s := xor(shr(1, u), add(not(and(u, 1)), 1)) + } + return (s, sz); + } + + /** + * @dev Decode ProtoBuf fixed-length encoding + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded unsigned integer + * @return The length of `bs` used to get decoded + */ + function _decode_uintf(uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256, uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 x = 0; + uint256 length = bs.length + WORD_LENGTH; + assert(p + sz <= length); + assembly { + let i := 0 + p := add(bs, p) + let tmp := mload(p) + for {} lt(i, sz) {} { + x := or(x, shl(mul(8, i), byte(i, tmp))) + p := add(p, 0x01) + i := add(i, 1) + } + } + return (x, sz); + } + + /** + * `_decode_(s)fixed(32|64)` is the concrete implementation of `_decode_uintf` + */ + function _decode_fixed32(uint256 p, bytes memory bs) internal pure returns (uint32, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 4); + return (uint32(x), sz); + } + + function _decode_fixed64(uint256 p, bytes memory bs) internal pure returns (uint64, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 8); + return (uint64(x), sz); + } + + function _decode_sfixed32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 4); + int256 r; + assembly { + r := x + } + return (int32(r), sz); + } + + function _decode_sfixed64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (uint256 x, uint256 sz) = _decode_uintf(p, bs, 8); + int256 r; + assembly { + r := x + } + return (int64(r), sz); + } + + /** + * @dev Decode bytes array + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The decoded bytes array + * @return The length of `bs` used to get decoded + */ + function _decode_lendelim(uint256 p, bytes memory bs) internal pure returns (bytes memory, uint256) { + /** + * First read the size encoded in `varint`, then use the size to read bytes. + */ + (uint256 len, uint256 sz) = _decode_varint(p, bs); + bytes memory b = new bytes(len); + uint256 length = bs.length + WORD_LENGTH; + assert(p + sz + len <= length); + uint256 sourcePtr; + uint256 destPtr; + assembly { + destPtr := add(b, 32) + sourcePtr := add(add(bs, p), sz) + } + copyBytes(sourcePtr, destPtr, len); + return (b, sz + len); + } + + /** + * @dev Skip the decoding of a single field + * @param wt The WireType of the field + * @param p The memory offset of `bs` + * @param bs The bytes array to be decoded + * @return The length of `bs` to skipped + */ + function _skip_field_decode(WireType wt, uint256 p, bytes memory bs) internal pure returns (uint256) { + if (wt == ProtoBufRuntime.WireType.Fixed64) { + return 8; + } else if (wt == ProtoBufRuntime.WireType.Fixed32) { + return 4; + } else if (wt == ProtoBufRuntime.WireType.Varint) { + (, uint256 size) = ProtoBufRuntime._decode_varint(p, bs); + return size; + } else { + require(wt == ProtoBufRuntime.WireType.LengthDelim); + (uint256 len, uint256 size) = ProtoBufRuntime._decode_varint(p, bs); + return size + len; + } + } + + // Encoders + /** + * @dev Encode ProtoBuf key + * @param x The field ID + * @param wt The WireType specified in ProtoBuf + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_key(uint256 x, WireType wt, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 i; + assembly { + i := or(mul(x, 8), mod(wt, 8)) + } + return _encode_varint(i, p, bs); + } + + /** + * @dev Encode ProtoBuf varint + * @param x The unsigned integer to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_varint(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 sz = 0; + assembly { + let bsptr := add(bs, p) + let byt := and(x, 0x7f) + for {} gt(shr(7, x), 0) {} { + mstore8(bsptr, or(0x80, byt)) + bsptr := add(bsptr, 1) + sz := add(sz, 1) + x := shr(7, x) + byt := and(x, 0x7f) + } + mstore8(bsptr, byt) + sz := add(sz, 1) + } + return sz; + } + + /** + * @dev Encode ProtoBuf zig-zag encoding + * @param x The signed integer to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_varints(int256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * Refer to https://developers.google.com/protocol-buffers/docs/encoding + */ + uint256 encodedInt = _encode_zigzag(x); + return _encode_varint(encodedInt, p, bs); + } + + /** + * @dev Encode ProtoBuf bytes + * @param xs The bytes array to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_bytes(bytes memory xs, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 xsLength = xs.length; + uint256 sz = _encode_varint(xsLength, p, bs); + uint256 count = 0; + assembly { + let bsptr := add(bs, add(p, sz)) + let xsptr := add(xs, 32) + for {} lt(count, xsLength) {} { + mstore8(bsptr, byte(0, mload(xsptr))) + bsptr := add(bsptr, 1) + xsptr := add(xsptr, 1) + count := add(count, 1) + } + } + return sz + count; + } + + /** + * @dev Encode ProtoBuf string + * @param xs The string to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_string(string memory xs, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_bytes(bytes(xs), p, bs); + } + + /** + * `_encode_(u)int(32|64)`, `_encode_enum` and `_encode_bool` + * are concrete implementation of `_encode_varint` + */ + function _encode_uint32(uint32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varint(x, p, bs); + } + + function _encode_uint64(uint64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varint(x, p, bs); + } + + function _encode_int32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint64 twosComplement; + assembly { + twosComplement := x + } + return _encode_varint(twosComplement, p, bs); + } + + function _encode_int64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint64 twosComplement; + assembly { + twosComplement := x + } + return _encode_varint(twosComplement, p, bs); + } + + function _encode_enum(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_int32(x, p, bs); + } + + function _encode_bool(bool x, uint256 p, bytes memory bs) internal pure returns (uint256) { + if (x) { + return _encode_varint(1, p, bs); + } else { + return _encode_varint(0, p, bs); + } + } + + /** + * `_encode_sint(32|64)`, `_encode_enum` and `_encode_bool` + * are the concrete implementation of `_encode_varints` + */ + function _encode_sint32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varints(x, p, bs); + } + + function _encode_sint64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_varints(x, p, bs); + } + + /** + * `_encode_(s)fixed(32|64)` is the concrete implementation of `_encode_uintf` + */ + function _encode_fixed32(uint32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_uintf(x, p, bs, 4); + } + + function _encode_fixed64(uint64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_uintf(x, p, bs, 8); + } + + function _encode_sfixed32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint32 twosComplement; + assembly { + twosComplement := x + } + return _encode_uintf(twosComplement, p, bs, 4); + } + + function _encode_sfixed64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint64 twosComplement; + assembly { + twosComplement := x + } + return _encode_uintf(twosComplement, p, bs, 8); + } + + /** + * @dev Encode ProtoBuf fixed-length integer + * @param x The unsigned integer to be encoded + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The length of encoded bytes + */ + function _encode_uintf(uint256 x, uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256) { + assembly { + let bsptr := add(sz, add(bs, p)) + let count := sz + for {} gt(count, 0) {} { + bsptr := sub(bsptr, 1) + mstore8(bsptr, byte(sub(32, count), x)) + count := sub(count, 1) + } + } + return sz; + } + + /** + * @dev Encode ProtoBuf zig-zag signed integer + * @param i The unsigned integer to be encoded + * @return The encoded unsigned integer + */ + function _encode_zigzag(int256 i) internal pure returns (uint256) { + if (i >= 0) { + return uint256(i) * 2; + } else { + return uint256(i * -2) - 1; + } + } + + // Estimators + /** + * @dev Estimate the length of encoded LengthDelim + * @param i The length of LengthDelim + * @return The estimated encoded length + */ + function _sz_lendelim(uint256 i) internal pure returns (uint256) { + return i + _sz_varint(i); + } + + /** + * @dev Estimate the length of encoded ProtoBuf field ID + * @param i The field ID + * @return The estimated encoded length + */ + function _sz_key(uint256 i) internal pure returns (uint256) { + if (i < 16) { + return 1; + } else if (i < 2048) { + return 2; + } else if (i < 262_144) { + return 3; + } else { + revert("not supported"); + } + } + + /** + * @dev Estimate the length of encoded ProtoBuf varint + * @param i The unsigned integer + * @return The estimated encoded length + */ + function _sz_varint(uint256 i) internal pure returns (uint256) { + uint256 count = 1; + assembly { + i := shr(7, i) + for {} gt(i, 0) {} { + i := shr(7, i) + count := add(count, 1) + } + } + return count; + } + + /** + * `_sz_(u)int(32|64)` and `_sz_enum` are the concrete implementation of `_sz_varint` + */ + function _sz_uint32(uint32 i) internal pure returns (uint256) { + return _sz_varint(i); + } + + function _sz_uint64(uint64 i) internal pure returns (uint256) { + return _sz_varint(i); + } + + function _sz_int32(int32 i) internal pure returns (uint256) { + if (i < 0) { + return 10; + } else { + return _sz_varint(uint32(i)); + } + } + + function _sz_int64(int64 i) internal pure returns (uint256) { + if (i < 0) { + return 10; + } else { + return _sz_varint(uint64(i)); + } + } + + function _sz_enum(int64 i) internal pure returns (uint256) { + if (i < 0) { + return 10; + } else { + return _sz_varint(uint64(i)); + } + } + + /** + * `_sz_sint(32|64)` and `_sz_enum` are the concrete implementation of zig-zag encoding + */ + function _sz_sint32(int32 i) internal pure returns (uint256) { + return _sz_varint(_encode_zigzag(i)); + } + + function _sz_sint64(int64 i) internal pure returns (uint256) { + return _sz_varint(_encode_zigzag(i)); + } + + /** + * `_estimate_packed_repeated_(uint32|uint64|int32|int64|sint32|sint64)` + */ + function _estimate_packed_repeated_uint32(uint32[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_uint32(a[i]); + } + return e; + } + + function _estimate_packed_repeated_uint64(uint64[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_uint64(a[i]); + } + return e; + } + + function _estimate_packed_repeated_int32(int32[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_int32(a[i]); + } + return e; + } + + function _estimate_packed_repeated_int64(int64[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_int64(a[i]); + } + return e; + } + + function _estimate_packed_repeated_sint32(int32[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_sint32(a[i]); + } + return e; + } + + function _estimate_packed_repeated_sint64(int64[] memory a) internal pure returns (uint256) { + uint256 e = 0; + for (uint256 i = 0; i < a.length; i++) { + e += _sz_sint64(a[i]); + } + return e; + } + + // Element counters for packed repeated fields + function _count_packed_repeated_varint(uint256 p, uint256 len, bytes memory bs) internal pure returns (uint256) { + uint256 count = 0; + uint256 end = p + len; + while (p < end) { + uint256 sz; + (, sz) = _decode_varint(p, bs); + p += sz; + count += 1; + } + return count; + } + + // Soltype extensions + /** + * @dev Decode Solidity integer and/or fixed-size bytes array, filling from lowest bit. + * @param n The maximum number of bytes to read + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The bytes32 representation + * @return The number of bytes used to decode + */ + function _decode_sol_bytesN_lower(uint8 n, uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + uint256 r; + (uint256 len, uint256 sz) = _decode_varint(p, bs); + if (len + sz > n + 3) { + revert(OVERFLOW_MESSAGE); + } + p += 3; + assert(p < bs.length + WORD_LENGTH); + assembly { + r := mload(add(p, bs)) + } + for (uint256 i = len - 2; i < WORD_LENGTH; i++) { + r /= 256; + } + return (bytes32(r), len + sz); + } + + /** + * @dev Decode Solidity integer and/or fixed-size bytes array, filling from highest bit. + * @param n The maximum number of bytes to read + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The bytes32 representation + * @return The number of bytes used to decode + */ + function _decode_sol_bytesN(uint8 n, uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + (uint256 len, uint256 sz) = _decode_varint(p, bs); + uint256 wordLength = WORD_LENGTH; + uint256 byteSize = BYTE_SIZE; + if (len + sz > n + 3) { + revert(OVERFLOW_MESSAGE); + } + p += 3; + bytes32 acc; + assert(p < bs.length + WORD_LENGTH); + assembly { + acc := mload(add(p, bs)) + let difference := sub(wordLength, sub(len, 2)) + let bits := mul(byteSize, difference) + acc := shl(bits, shr(bits, acc)) + } + return (acc, len + sz); + } + + /* + * `_decode_sol*` are the concrete implementation of decoding Solidity types + */ + function _decode_sol_address(uint256 p, bytes memory bs) internal pure returns (address, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytesN(20, p, bs); + return (address(bytes20(r)), sz); + } + + function _decode_sol_bool(uint256 p, bytes memory bs) internal pure returns (bool, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(1, p, bs); + if (r == 0) { + return (false, sz); + } + return (true, sz); + } + + function _decode_sol_uint(uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + return _decode_sol_uint256(p, bs); + } + + function _decode_sol_uintN(uint8 n, uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + (bytes32 u, uint256 sz) = _decode_sol_bytesN_lower(n, p, bs); + uint256 r; + assembly { + r := u + } + return (r, sz); + } + + function _decode_sol_uint8(uint256 p, bytes memory bs) internal pure returns (uint8, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(1, p, bs); + return (uint8(r), sz); + } + + function _decode_sol_uint16(uint256 p, bytes memory bs) internal pure returns (uint16, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(2, p, bs); + return (uint16(r), sz); + } + + function _decode_sol_uint24(uint256 p, bytes memory bs) internal pure returns (uint24, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(3, p, bs); + return (uint24(r), sz); + } + + function _decode_sol_uint32(uint256 p, bytes memory bs) internal pure returns (uint32, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(4, p, bs); + return (uint32(r), sz); + } + + function _decode_sol_uint40(uint256 p, bytes memory bs) internal pure returns (uint40, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(5, p, bs); + return (uint40(r), sz); + } + + function _decode_sol_uint48(uint256 p, bytes memory bs) internal pure returns (uint48, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(6, p, bs); + return (uint48(r), sz); + } + + function _decode_sol_uint56(uint256 p, bytes memory bs) internal pure returns (uint56, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(7, p, bs); + return (uint56(r), sz); + } + + function _decode_sol_uint64(uint256 p, bytes memory bs) internal pure returns (uint64, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(8, p, bs); + return (uint64(r), sz); + } + + function _decode_sol_uint72(uint256 p, bytes memory bs) internal pure returns (uint72, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(9, p, bs); + return (uint72(r), sz); + } + + function _decode_sol_uint80(uint256 p, bytes memory bs) internal pure returns (uint80, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(10, p, bs); + return (uint80(r), sz); + } + + function _decode_sol_uint88(uint256 p, bytes memory bs) internal pure returns (uint88, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(11, p, bs); + return (uint88(r), sz); + } + + function _decode_sol_uint96(uint256 p, bytes memory bs) internal pure returns (uint96, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(12, p, bs); + return (uint96(r), sz); + } + + function _decode_sol_uint104(uint256 p, bytes memory bs) internal pure returns (uint104, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(13, p, bs); + return (uint104(r), sz); + } + + function _decode_sol_uint112(uint256 p, bytes memory bs) internal pure returns (uint112, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(14, p, bs); + return (uint112(r), sz); + } + + function _decode_sol_uint120(uint256 p, bytes memory bs) internal pure returns (uint120, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(15, p, bs); + return (uint120(r), sz); + } + + function _decode_sol_uint128(uint256 p, bytes memory bs) internal pure returns (uint128, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(16, p, bs); + return (uint128(r), sz); + } + + function _decode_sol_uint136(uint256 p, bytes memory bs) internal pure returns (uint136, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(17, p, bs); + return (uint136(r), sz); + } + + function _decode_sol_uint144(uint256 p, bytes memory bs) internal pure returns (uint144, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(18, p, bs); + return (uint144(r), sz); + } + + function _decode_sol_uint152(uint256 p, bytes memory bs) internal pure returns (uint152, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(19, p, bs); + return (uint152(r), sz); + } + + function _decode_sol_uint160(uint256 p, bytes memory bs) internal pure returns (uint160, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(20, p, bs); + return (uint160(r), sz); + } + + function _decode_sol_uint168(uint256 p, bytes memory bs) internal pure returns (uint168, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(21, p, bs); + return (uint168(r), sz); + } + + function _decode_sol_uint176(uint256 p, bytes memory bs) internal pure returns (uint176, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(22, p, bs); + return (uint176(r), sz); + } + + function _decode_sol_uint184(uint256 p, bytes memory bs) internal pure returns (uint184, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(23, p, bs); + return (uint184(r), sz); + } + + function _decode_sol_uint192(uint256 p, bytes memory bs) internal pure returns (uint192, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(24, p, bs); + return (uint192(r), sz); + } + + function _decode_sol_uint200(uint256 p, bytes memory bs) internal pure returns (uint200, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(25, p, bs); + return (uint200(r), sz); + } + + function _decode_sol_uint208(uint256 p, bytes memory bs) internal pure returns (uint208, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(26, p, bs); + return (uint208(r), sz); + } + + function _decode_sol_uint216(uint256 p, bytes memory bs) internal pure returns (uint216, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(27, p, bs); + return (uint216(r), sz); + } + + function _decode_sol_uint224(uint256 p, bytes memory bs) internal pure returns (uint224, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(28, p, bs); + return (uint224(r), sz); + } + + function _decode_sol_uint232(uint256 p, bytes memory bs) internal pure returns (uint232, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(29, p, bs); + return (uint232(r), sz); + } + + function _decode_sol_uint240(uint256 p, bytes memory bs) internal pure returns (uint240, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(30, p, bs); + return (uint240(r), sz); + } + + function _decode_sol_uint248(uint256 p, bytes memory bs) internal pure returns (uint248, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(31, p, bs); + return (uint248(r), sz); + } + + function _decode_sol_uint256(uint256 p, bytes memory bs) internal pure returns (uint256, uint256) { + (uint256 r, uint256 sz) = _decode_sol_uintN(32, p, bs); + return (uint256(r), sz); + } + + function _decode_sol_int(uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + return _decode_sol_int256(p, bs); + } + + function _decode_sol_intN(uint8 n, uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + (bytes32 u, uint256 sz) = _decode_sol_bytesN_lower(n, p, bs); + int256 r; + assembly { + r := u + r := signextend(sub(sz, 4), r) + } + return (r, sz); + } + + function _decode_sol_bytes(uint8 n, uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + (bytes32 u, uint256 sz) = _decode_sol_bytesN(n, p, bs); + return (u, sz); + } + + function _decode_sol_int8(uint256 p, bytes memory bs) internal pure returns (int8, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(1, p, bs); + return (int8(r), sz); + } + + function _decode_sol_int16(uint256 p, bytes memory bs) internal pure returns (int16, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(2, p, bs); + return (int16(r), sz); + } + + function _decode_sol_int24(uint256 p, bytes memory bs) internal pure returns (int24, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(3, p, bs); + return (int24(r), sz); + } + + function _decode_sol_int32(uint256 p, bytes memory bs) internal pure returns (int32, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(4, p, bs); + return (int32(r), sz); + } + + function _decode_sol_int40(uint256 p, bytes memory bs) internal pure returns (int40, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(5, p, bs); + return (int40(r), sz); + } + + function _decode_sol_int48(uint256 p, bytes memory bs) internal pure returns (int48, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(6, p, bs); + return (int48(r), sz); + } + + function _decode_sol_int56(uint256 p, bytes memory bs) internal pure returns (int56, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(7, p, bs); + return (int56(r), sz); + } + + function _decode_sol_int64(uint256 p, bytes memory bs) internal pure returns (int64, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(8, p, bs); + return (int64(r), sz); + } + + function _decode_sol_int72(uint256 p, bytes memory bs) internal pure returns (int72, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(9, p, bs); + return (int72(r), sz); + } + + function _decode_sol_int80(uint256 p, bytes memory bs) internal pure returns (int80, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(10, p, bs); + return (int80(r), sz); + } + + function _decode_sol_int88(uint256 p, bytes memory bs) internal pure returns (int88, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(11, p, bs); + return (int88(r), sz); + } + + function _decode_sol_int96(uint256 p, bytes memory bs) internal pure returns (int96, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(12, p, bs); + return (int96(r), sz); + } + + function _decode_sol_int104(uint256 p, bytes memory bs) internal pure returns (int104, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(13, p, bs); + return (int104(r), sz); + } + + function _decode_sol_int112(uint256 p, bytes memory bs) internal pure returns (int112, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(14, p, bs); + return (int112(r), sz); + } + + function _decode_sol_int120(uint256 p, bytes memory bs) internal pure returns (int120, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(15, p, bs); + return (int120(r), sz); + } + + function _decode_sol_int128(uint256 p, bytes memory bs) internal pure returns (int128, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(16, p, bs); + return (int128(r), sz); + } + + function _decode_sol_int136(uint256 p, bytes memory bs) internal pure returns (int136, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(17, p, bs); + return (int136(r), sz); + } + + function _decode_sol_int144(uint256 p, bytes memory bs) internal pure returns (int144, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(18, p, bs); + return (int144(r), sz); + } + + function _decode_sol_int152(uint256 p, bytes memory bs) internal pure returns (int152, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(19, p, bs); + return (int152(r), sz); + } + + function _decode_sol_int160(uint256 p, bytes memory bs) internal pure returns (int160, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(20, p, bs); + return (int160(r), sz); + } + + function _decode_sol_int168(uint256 p, bytes memory bs) internal pure returns (int168, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(21, p, bs); + return (int168(r), sz); + } + + function _decode_sol_int176(uint256 p, bytes memory bs) internal pure returns (int176, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(22, p, bs); + return (int176(r), sz); + } + + function _decode_sol_int184(uint256 p, bytes memory bs) internal pure returns (int184, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(23, p, bs); + return (int184(r), sz); + } + + function _decode_sol_int192(uint256 p, bytes memory bs) internal pure returns (int192, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(24, p, bs); + return (int192(r), sz); + } + + function _decode_sol_int200(uint256 p, bytes memory bs) internal pure returns (int200, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(25, p, bs); + return (int200(r), sz); + } + + function _decode_sol_int208(uint256 p, bytes memory bs) internal pure returns (int208, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(26, p, bs); + return (int208(r), sz); + } + + function _decode_sol_int216(uint256 p, bytes memory bs) internal pure returns (int216, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(27, p, bs); + return (int216(r), sz); + } + + function _decode_sol_int224(uint256 p, bytes memory bs) internal pure returns (int224, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(28, p, bs); + return (int224(r), sz); + } + + function _decode_sol_int232(uint256 p, bytes memory bs) internal pure returns (int232, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(29, p, bs); + return (int232(r), sz); + } + + function _decode_sol_int240(uint256 p, bytes memory bs) internal pure returns (int240, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(30, p, bs); + return (int240(r), sz); + } + + function _decode_sol_int248(uint256 p, bytes memory bs) internal pure returns (int248, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(31, p, bs); + return (int248(r), sz); + } + + function _decode_sol_int256(uint256 p, bytes memory bs) internal pure returns (int256, uint256) { + (int256 r, uint256 sz) = _decode_sol_intN(32, p, bs); + return (int256(r), sz); + } + + function _decode_sol_bytes1(uint256 p, bytes memory bs) internal pure returns (bytes1, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(1, p, bs); + return (bytes1(r), sz); + } + + function _decode_sol_bytes2(uint256 p, bytes memory bs) internal pure returns (bytes2, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(2, p, bs); + return (bytes2(r), sz); + } + + function _decode_sol_bytes3(uint256 p, bytes memory bs) internal pure returns (bytes3, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(3, p, bs); + return (bytes3(r), sz); + } + + function _decode_sol_bytes4(uint256 p, bytes memory bs) internal pure returns (bytes4, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(4, p, bs); + return (bytes4(r), sz); + } + + function _decode_sol_bytes5(uint256 p, bytes memory bs) internal pure returns (bytes5, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(5, p, bs); + return (bytes5(r), sz); + } + + function _decode_sol_bytes6(uint256 p, bytes memory bs) internal pure returns (bytes6, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(6, p, bs); + return (bytes6(r), sz); + } + + function _decode_sol_bytes7(uint256 p, bytes memory bs) internal pure returns (bytes7, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(7, p, bs); + return (bytes7(r), sz); + } + + function _decode_sol_bytes8(uint256 p, bytes memory bs) internal pure returns (bytes8, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(8, p, bs); + return (bytes8(r), sz); + } + + function _decode_sol_bytes9(uint256 p, bytes memory bs) internal pure returns (bytes9, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(9, p, bs); + return (bytes9(r), sz); + } + + function _decode_sol_bytes10(uint256 p, bytes memory bs) internal pure returns (bytes10, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(10, p, bs); + return (bytes10(r), sz); + } + + function _decode_sol_bytes11(uint256 p, bytes memory bs) internal pure returns (bytes11, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(11, p, bs); + return (bytes11(r), sz); + } + + function _decode_sol_bytes12(uint256 p, bytes memory bs) internal pure returns (bytes12, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(12, p, bs); + return (bytes12(r), sz); + } + + function _decode_sol_bytes13(uint256 p, bytes memory bs) internal pure returns (bytes13, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(13, p, bs); + return (bytes13(r), sz); + } + + function _decode_sol_bytes14(uint256 p, bytes memory bs) internal pure returns (bytes14, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(14, p, bs); + return (bytes14(r), sz); + } + + function _decode_sol_bytes15(uint256 p, bytes memory bs) internal pure returns (bytes15, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(15, p, bs); + return (bytes15(r), sz); + } + + function _decode_sol_bytes16(uint256 p, bytes memory bs) internal pure returns (bytes16, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(16, p, bs); + return (bytes16(r), sz); + } + + function _decode_sol_bytes17(uint256 p, bytes memory bs) internal pure returns (bytes17, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(17, p, bs); + return (bytes17(r), sz); + } + + function _decode_sol_bytes18(uint256 p, bytes memory bs) internal pure returns (bytes18, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(18, p, bs); + return (bytes18(r), sz); + } + + function _decode_sol_bytes19(uint256 p, bytes memory bs) internal pure returns (bytes19, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(19, p, bs); + return (bytes19(r), sz); + } + + function _decode_sol_bytes20(uint256 p, bytes memory bs) internal pure returns (bytes20, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(20, p, bs); + return (bytes20(r), sz); + } + + function _decode_sol_bytes21(uint256 p, bytes memory bs) internal pure returns (bytes21, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(21, p, bs); + return (bytes21(r), sz); + } + + function _decode_sol_bytes22(uint256 p, bytes memory bs) internal pure returns (bytes22, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(22, p, bs); + return (bytes22(r), sz); + } + + function _decode_sol_bytes23(uint256 p, bytes memory bs) internal pure returns (bytes23, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(23, p, bs); + return (bytes23(r), sz); + } + + function _decode_sol_bytes24(uint256 p, bytes memory bs) internal pure returns (bytes24, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(24, p, bs); + return (bytes24(r), sz); + } + + function _decode_sol_bytes25(uint256 p, bytes memory bs) internal pure returns (bytes25, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(25, p, bs); + return (bytes25(r), sz); + } + + function _decode_sol_bytes26(uint256 p, bytes memory bs) internal pure returns (bytes26, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(26, p, bs); + return (bytes26(r), sz); + } + + function _decode_sol_bytes27(uint256 p, bytes memory bs) internal pure returns (bytes27, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(27, p, bs); + return (bytes27(r), sz); + } + + function _decode_sol_bytes28(uint256 p, bytes memory bs) internal pure returns (bytes28, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(28, p, bs); + return (bytes28(r), sz); + } + + function _decode_sol_bytes29(uint256 p, bytes memory bs) internal pure returns (bytes29, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(29, p, bs); + return (bytes29(r), sz); + } + + function _decode_sol_bytes30(uint256 p, bytes memory bs) internal pure returns (bytes30, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(30, p, bs); + return (bytes30(r), sz); + } + + function _decode_sol_bytes31(uint256 p, bytes memory bs) internal pure returns (bytes31, uint256) { + (bytes32 r, uint256 sz) = _decode_sol_bytes(31, p, bs); + return (bytes31(r), sz); + } + + function _decode_sol_bytes32(uint256 p, bytes memory bs) internal pure returns (bytes32, uint256) { + return _decode_sol_bytes(32, p, bs); + } + + /* + * `_encode_sol*` are the concrete implementation of encoding Solidity types + */ + function _encode_sol_address(address x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(uint160(x)), 20, p, bs); + } + + function _encode_sol_uint(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 32, p, bs); + } + + function _encode_sol_uint8(uint8 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 1, p, bs); + } + + function _encode_sol_uint16(uint16 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 2, p, bs); + } + + function _encode_sol_uint24(uint24 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 3, p, bs); + } + + function _encode_sol_uint32(uint32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 4, p, bs); + } + + function _encode_sol_uint40(uint40 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 5, p, bs); + } + + function _encode_sol_uint48(uint48 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 6, p, bs); + } + + function _encode_sol_uint56(uint56 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 7, p, bs); + } + + function _encode_sol_uint64(uint64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 8, p, bs); + } + + function _encode_sol_uint72(uint72 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 9, p, bs); + } + + function _encode_sol_uint80(uint80 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 10, p, bs); + } + + function _encode_sol_uint88(uint88 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 11, p, bs); + } + + function _encode_sol_uint96(uint96 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 12, p, bs); + } + + function _encode_sol_uint104(uint104 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 13, p, bs); + } + + function _encode_sol_uint112(uint112 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 14, p, bs); + } + + function _encode_sol_uint120(uint120 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 15, p, bs); + } + + function _encode_sol_uint128(uint128 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 16, p, bs); + } + + function _encode_sol_uint136(uint136 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 17, p, bs); + } + + function _encode_sol_uint144(uint144 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 18, p, bs); + } + + function _encode_sol_uint152(uint152 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 19, p, bs); + } + + function _encode_sol_uint160(uint160 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 20, p, bs); + } + + function _encode_sol_uint168(uint168 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 21, p, bs); + } + + function _encode_sol_uint176(uint176 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 22, p, bs); + } + + function _encode_sol_uint184(uint184 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 23, p, bs); + } + + function _encode_sol_uint192(uint192 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 24, p, bs); + } + + function _encode_sol_uint200(uint200 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 25, p, bs); + } + + function _encode_sol_uint208(uint208 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 26, p, bs); + } + + function _encode_sol_uint216(uint216 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 27, p, bs); + } + + function _encode_sol_uint224(uint224 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 28, p, bs); + } + + function _encode_sol_uint232(uint232 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 29, p, bs); + } + + function _encode_sol_uint240(uint240 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 30, p, bs); + } + + function _encode_sol_uint248(uint248 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 31, p, bs); + } + + function _encode_sol_uint256(uint256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(uint256(x), 32, p, bs); + } + + function _encode_sol_int(int256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(x, 32, p, bs); + } + + function _encode_sol_int8(int8 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 1, p, bs); + } + + function _encode_sol_int16(int16 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 2, p, bs); + } + + function _encode_sol_int24(int24 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 3, p, bs); + } + + function _encode_sol_int32(int32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 4, p, bs); + } + + function _encode_sol_int40(int40 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 5, p, bs); + } + + function _encode_sol_int48(int48 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 6, p, bs); + } + + function _encode_sol_int56(int56 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 7, p, bs); + } + + function _encode_sol_int64(int64 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 8, p, bs); + } + + function _encode_sol_int72(int72 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 9, p, bs); + } + + function _encode_sol_int80(int80 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 10, p, bs); + } + + function _encode_sol_int88(int88 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 11, p, bs); + } + + function _encode_sol_int96(int96 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 12, p, bs); + } + + function _encode_sol_int104(int104 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 13, p, bs); + } + + function _encode_sol_int112(int112 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 14, p, bs); + } + + function _encode_sol_int120(int120 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 15, p, bs); + } + + function _encode_sol_int128(int128 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 16, p, bs); + } + + function _encode_sol_int136(int136 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 17, p, bs); + } + + function _encode_sol_int144(int144 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 18, p, bs); + } + + function _encode_sol_int152(int152 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 19, p, bs); + } + + function _encode_sol_int160(int160 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 20, p, bs); + } + + function _encode_sol_int168(int168 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 21, p, bs); + } + + function _encode_sol_int176(int176 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 22, p, bs); + } + + function _encode_sol_int184(int184 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 23, p, bs); + } + + function _encode_sol_int192(int192 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 24, p, bs); + } + + function _encode_sol_int200(int200 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 25, p, bs); + } + + function _encode_sol_int208(int208 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 26, p, bs); + } + + function _encode_sol_int216(int216 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 27, p, bs); + } + + function _encode_sol_int224(int224 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 28, p, bs); + } + + function _encode_sol_int232(int232 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 29, p, bs); + } + + function _encode_sol_int240(int240 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 30, p, bs); + } + + function _encode_sol_int248(int248 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(int256(x), 31, p, bs); + } + + function _encode_sol_int256(int256 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol(x, 32, p, bs); + } + + function _encode_sol_bytes1(bytes1 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 1, p, bs); + } + + function _encode_sol_bytes2(bytes2 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 2, p, bs); + } + + function _encode_sol_bytes3(bytes3 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 3, p, bs); + } + + function _encode_sol_bytes4(bytes4 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 4, p, bs); + } + + function _encode_sol_bytes5(bytes5 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 5, p, bs); + } + + function _encode_sol_bytes6(bytes6 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 6, p, bs); + } + + function _encode_sol_bytes7(bytes7 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 7, p, bs); + } + + function _encode_sol_bytes8(bytes8 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 8, p, bs); + } + + function _encode_sol_bytes9(bytes9 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 9, p, bs); + } + + function _encode_sol_bytes10(bytes10 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 10, p, bs); + } + + function _encode_sol_bytes11(bytes11 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 11, p, bs); + } + + function _encode_sol_bytes12(bytes12 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 12, p, bs); + } + + function _encode_sol_bytes13(bytes13 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 13, p, bs); + } + + function _encode_sol_bytes14(bytes14 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 14, p, bs); + } + + function _encode_sol_bytes15(bytes15 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 15, p, bs); + } + + function _encode_sol_bytes16(bytes16 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 16, p, bs); + } + + function _encode_sol_bytes17(bytes17 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 17, p, bs); + } + + function _encode_sol_bytes18(bytes18 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 18, p, bs); + } + + function _encode_sol_bytes19(bytes19 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 19, p, bs); + } + + function _encode_sol_bytes20(bytes20 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 20, p, bs); + } + + function _encode_sol_bytes21(bytes21 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 21, p, bs); + } + + function _encode_sol_bytes22(bytes22 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 22, p, bs); + } + + function _encode_sol_bytes23(bytes23 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 23, p, bs); + } + + function _encode_sol_bytes24(bytes24 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 24, p, bs); + } + + function _encode_sol_bytes25(bytes25 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 25, p, bs); + } + + function _encode_sol_bytes26(bytes26 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 26, p, bs); + } + + function _encode_sol_bytes27(bytes27 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 27, p, bs); + } + + function _encode_sol_bytes28(bytes28 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 28, p, bs); + } + + function _encode_sol_bytes29(bytes29 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 29, p, bs); + } + + function _encode_sol_bytes30(bytes30 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 30, p, bs); + } + + function _encode_sol_bytes31(bytes31 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(bytes32(x), 31, p, bs); + } + + function _encode_sol_bytes32(bytes32 x, uint256 p, bytes memory bs) internal pure returns (uint256) { + return _encode_sol_bytes(x, 32, p, bs); + } + + /** + * @dev Encode the key of Solidity integer and/or fixed-size bytes array. + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol_header(uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + p += _encode_varint(sz + 2, p, bs); + p += _encode_key(1, WireType.LengthDelim, p, bs); + p += _encode_varint(sz, p, bs); + return p - offset; + } + + /** + * @dev Encode Solidity type + * @param x The unsinged integer to be encoded + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol(uint256 x, uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 size; + p += 3; + size = _encode_sol_raw_other(x, p, bs, sz); + p += size; + _encode_sol_header(size, offset, bs); + return p - offset; + } + + /** + * @dev Encode Solidity type + * @param x The signed integer to be encoded + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol(int256 x, uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 size; + p += 3; + size = _encode_sol_raw_other(x, p, bs, sz); + p += size; + _encode_sol_header(size, offset, bs); + return p - offset; + } + + /** + * @dev Encode Solidity type + * @param x The fixed-size byte array to be encoded + * @param sz The number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes used to encode + */ + function _encode_sol_bytes(bytes32 x, uint256 sz, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 size; + p += 3; + size = _encode_sol_raw_bytes_array(x, p, bs, sz); + p += size; + _encode_sol_header(size, offset, bs); + return p - offset; + } + + /** + * @dev Get the actual size needed to encoding an unsigned integer + * @param x The unsigned integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @return The number of bytes needed for encoding `x` + */ + function _get_real_size(uint256 x, uint256 sz) internal pure returns (uint256) { + uint256 base = 0xff; + uint256 realSize = sz; + while (x & (base << (realSize * BYTE_SIZE - BYTE_SIZE)) == 0 && realSize > 0) { + realSize -= 1; + } + if (realSize == 0) { + realSize = 1; + } + return realSize; + } + + /** + * @dev Get the actual size needed to encoding an signed integer + * @param x The signed integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @return The number of bytes needed for encoding `x` + */ + function _get_real_size(int256 x, uint256 sz) internal pure returns (uint256) { + int256 base = 0xff; + if (x >= 0) { + uint256 tmp = _get_real_size(uint256(x), sz); + int256 remainder = (x & (base << (tmp * BYTE_SIZE - BYTE_SIZE))) >> (tmp * BYTE_SIZE - BYTE_SIZE); + if (remainder >= 128) { + tmp += 1; + } + return tmp; + } + + uint256 realSize = sz; + while ( + x & (base << (realSize * BYTE_SIZE - BYTE_SIZE)) == (base << (realSize * BYTE_SIZE - BYTE_SIZE)) + && realSize > 0 + ) { + realSize -= 1; + } + { + int256 remainder = (x & (base << (realSize * BYTE_SIZE - BYTE_SIZE))) >> (realSize * BYTE_SIZE - BYTE_SIZE); + if (remainder < 128) { + realSize += 1; + } + } + return realSize; + } + + /** + * @dev Encode the fixed-bytes array + * @param x The fixed-size byte array to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes needed for encoding `x` + */ + function _encode_sol_raw_bytes_array(bytes32 x, uint256 p, bytes memory bs, uint256 sz) + internal + pure + returns (uint256) + { + /** + * The idea is to not encode the leading bytes of zero. + */ + uint256 actualSize = sz; + for (uint256 i = 0; i < sz; i++) { + uint8 current = uint8(x[sz - 1 - i]); + if (current == 0 && actualSize > 1) { + actualSize--; + } else { + break; + } + } + assembly { + let bsptr := add(bs, p) + let count := actualSize + for {} gt(count, 0) {} { + mstore8(bsptr, byte(sub(actualSize, count), x)) + bsptr := add(bsptr, 1) + count := sub(count, 1) + } + } + return actualSize; + } + + /** + * @dev Encode the signed integer + * @param x The signed integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes needed for encoding `x` + */ + function _encode_sol_raw_other(int256 x, uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256) { + /** + * The idea is to not encode the leading bytes of zero.or one, + * depending on whether it is positive. + */ + uint256 realSize = _get_real_size(x, sz); + assembly { + let bsptr := add(bs, p) + let count := realSize + for {} gt(count, 0) {} { + mstore8(bsptr, byte(sub(32, count), x)) + bsptr := add(bsptr, 1) + count := sub(count, 1) + } + } + return realSize; + } + + /** + * @dev Encode the unsigned integer + * @param x The unsigned integer to be encoded + * @param sz The maximum number of bytes used to encode Solidity types + * @param p The offset of bytes array `bs` + * @param bs The bytes array to encode + * @return The number of bytes needed for encoding `x` + */ + function _encode_sol_raw_other(uint256 x, uint256 p, bytes memory bs, uint256 sz) internal pure returns (uint256) { + uint256 realSize = _get_real_size(x, sz); + assembly { + let bsptr := add(bs, p) + let count := realSize + for {} gt(count, 0) {} { + mstore8(bsptr, byte(sub(32, count), x)) + bsptr := add(bsptr, 1) + count := sub(count, 1) + } + } + return realSize; + } +} + +// contracts/interfaces/LightClient.sol + +interface LightClient { + /** + * addOpConsensusState adds an appHash to internal store and + * returns the fraud proof end time, and a bool flag indicating if + * the fraud proof window has passed according to the block's time stamp. + */ + function addOpConsensusState( + L1Header calldata l1header, + OpL2StateProof calldata proof, + uint256 height, + uint256 appHash + ) external returns (uint256 endTime, bool ended); + + /** + * + */ + function getFraudProofEndtime(uint256 height) external returns (uint256 endTime); + + /** + * verifyMembership checks if the current state + * can be used to perform the membership test and if so, it uses + * the verifier to perform membership check. + */ + function verifyMembership(Ics23Proof calldata proof, bytes memory key, bytes memory expectedValue) external; + + /** + * + */ + function verifyNonMembership(Ics23Proof calldata proof, bytes memory key) external; + + /** + * + */ + function getState(uint256 height) external view returns (uint256 appHash, uint256 fraudProofEndTime, bool ended); +} + +// lib/openzeppelin-contracts/contracts/access/Ownable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} + +// lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ```solidity + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable_0 { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a + * constructor. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: setting the version to 255 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * For example: + * + * [.hljs-theme-light.nopadding] + * ```solidity + * contract MyToken is ERC20Upgradeable { + * function initialize() initializer public { + * __ERC20_init("MyToken", "MTK"); + * } + * } + * + * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { + * function initializeV2() reinitializer(2) public { + * __ERC20Permit_init("MyToken"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable_1 { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a + * constructor. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: setting the version to 255 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} + +// lib/proto/GoogleProtobufAny.sol + +library GoogleProtobufAny { + //struct definition + struct Data { + string type_url; + bytes value; + } + + // Decoder section + + /** + * @dev The main decoder for memory + * @param bs The bytes array to be decoded + * @return The decoded struct + */ + function decode(bytes memory bs) internal pure returns (Data memory) { + (Data memory x,) = _decode(32, bs, bs.length); + return x; + } + + /** + * @dev The main decoder for storage + * @param self The in-storage struct + * @param bs The bytes array to be decoded + */ + function decode(Data storage self, bytes memory bs) internal { + (Data memory x,) = _decode(32, bs, bs.length); + store(x, self); + } + // inner decoder + + /** + * @dev The decoder for internal usage + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param sz The number of bytes expected + * @return The decoded struct + * @return The number of bytes decoded + */ + function _decode(uint256 p, bytes memory bs, uint256 sz) internal pure returns (Data memory, uint256) { + Data memory r; + uint256[3] memory counters; + uint256 fieldId; + ProtoBufRuntime.WireType wireType; + uint256 bytesRead; + uint256 offset = p; + uint256 pointer = p; + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 1) { + pointer += _read_type_url(pointer, bs, r, counters); + } else if (fieldId == 2) { + pointer += _read_value(pointer, bs, r, counters); + } else { + if (wireType == ProtoBufRuntime.WireType.Fixed64) { + uint256 size; + (, size) = ProtoBufRuntime._decode_fixed64(pointer, bs); + pointer += size; + } + if (wireType == ProtoBufRuntime.WireType.Fixed32) { + uint256 size; + (, size) = ProtoBufRuntime._decode_fixed32(pointer, bs); + pointer += size; + } + if (wireType == ProtoBufRuntime.WireType.Varint) { + uint256 size; + (, size) = ProtoBufRuntime._decode_varint(pointer, bs); + pointer += size; + } + if (wireType == ProtoBufRuntime.WireType.LengthDelim) { + uint256 size; + (, size) = ProtoBufRuntime._decode_lendelim(pointer, bs); + pointer += size; + } + } + } + return (r, sz); + } + + // field readers + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @param counters The counters for repeated fields + * @return The number of bytes decoded + */ + function _read_type_url(uint256 p, bytes memory bs, Data memory r, uint256[3] memory counters) + internal + pure + returns (uint256) + { + /** + * if `r` is NULL, then only counting the number of fields. + */ + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + if (isNil(r)) { + counters[1] += 1; + } else { + r.type_url = x; + if (counters[1] > 0) counters[1] -= 1; + } + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @param counters The counters for repeated fields + * @return The number of bytes decoded + */ + function _read_value(uint256 p, bytes memory bs, Data memory r, uint256[3] memory counters) + internal + pure + returns (uint256) + { + /** + * if `r` is NULL, then only counting the number of fields. + */ + (bytes memory x, uint256 sz) = ProtoBufRuntime._decode_bytes(p, bs); + if (isNil(r)) { + counters[2] += 1; + } else { + r.value = x; + if (counters[2] > 0) counters[2] -= 1; + } + return sz; + } + + // Encoder section + + /** + * @dev The main encoder for memory + * @param r The struct to be encoded + * @return The encoded byte array + */ + function encode(Data memory r) internal pure returns (bytes memory) { + bytes memory bs = new bytes(_estimate(r)); + uint256 sz = _encode(r, 32, bs); + assembly { + mstore(bs, sz) + } + return bs; + } + // inner encoder + + /** + * @dev The encoder for internal usage + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 pointer = p; + + pointer += ProtoBufRuntime._encode_key(1, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.type_url, pointer, bs); + pointer += ProtoBufRuntime._encode_key(2, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_bytes(r.value, pointer, bs); + return pointer - offset; + } + // nested encoder + + /** + * @dev The encoder for inner struct + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode_nested(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * First encoded `r` into a temporary array, and encode the actual size used. + * Then copy the temporary array into `bs`. + */ + uint256 offset = p; + uint256 pointer = p; + bytes memory tmp = new bytes(_estimate(r)); + uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp); + uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs); + uint256 size = _encode(r, 32, tmp); + pointer += ProtoBufRuntime._encode_varint(size, pointer, bs); + ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size); + pointer += size; + delete tmp; + return pointer - offset; + } + // estimator + + /** + * @dev The estimator for a struct + * @param r The struct to be encoded + * @return The number of bytes encoded in estimation + */ + function _estimate(Data memory r) internal pure returns (uint256) { + uint256 e; + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.type_url).length); + e += 1 + ProtoBufRuntime._sz_lendelim(r.value.length); + return e; + } + + //store function + /** + * @dev Store in-memory struct to storage + * @param input The in-memory struct + * @param output The in-storage struct + */ + function store(Data memory input, Data storage output) internal { + output.type_url = input.type_url; + output.value = input.value; + } + + //utility functions + /** + * @dev Return an empty struct + * @return r The empty struct + */ + function nil() internal pure returns (Data memory r) { + assembly { + r := 0 + } + } + + /** + * @dev Test whether a struct is empty + * @param x The struct to be tested + * @return r True if it is empty + */ + function isNil(Data memory x) internal pure returns (bool r) { + assembly { + r := iszero(x) + } + } +} +//library Any + +// lib/openzeppelin-contracts/contracts/utils/Strings.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal + * representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} + +// lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract ContextUpgradeable is Initializable_1 { + function __Context_init() internal onlyInitializing {} + + function __Context_init_unchained() internal onlyInitializing {} + + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[50] private __gap; +} + +// lib/proto/channel.sol + +library ProtoChannel { + //struct definition + struct Data { + int32 state; + int32 ordering; + ProtoCounterparty.Data counterparty; + string[] connection_hops; + string version; + } + + // Decoder section + + /** + * @dev The main decoder for memory + * @param bs The bytes array to be decoded + * @return The decoded struct + */ + function decode(bytes memory bs) internal pure returns (Data memory) { + (Data memory x,) = _decode(32, bs, bs.length); + return x; + } + + /** + * @dev The main decoder for storage + * @param self The in-storage struct + * @param bs The bytes array to be decoded + */ + function decode(Data storage self, bytes memory bs) internal { + (Data memory x,) = _decode(32, bs, bs.length); + store(x, self); + } + // inner decoder + + /** + * @dev The decoder for internal usage + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param sz The number of bytes expected + * @return The decoded struct + * @return The number of bytes decoded + */ + function _decode(uint256 p, bytes memory bs, uint256 sz) internal pure returns (Data memory, uint256) { + Data memory r; + uint256[6] memory counters; + uint256 fieldId; + ProtoBufRuntime.WireType wireType; + uint256 bytesRead; + uint256 offset = p; + uint256 pointer = p; + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 1) { + pointer += _read_state(pointer, bs, r); + } else if (fieldId == 2) { + pointer += _read_ordering(pointer, bs, r); + } else if (fieldId == 3) { + pointer += _read_counterparty(pointer, bs, r); + } else if (fieldId == 4) { + pointer += _read_unpacked_repeated_connection_hops(pointer, bs, nil(), counters); + } else if (fieldId == 5) { + pointer += _read_version(pointer, bs, r); + } else { + pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); + } + } + pointer = offset; + if (counters[4] > 0) { + require(r.connection_hops.length == 0); + r.connection_hops = new string[](counters[4]); + } + + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 4) { + pointer += _read_unpacked_repeated_connection_hops(pointer, bs, r, counters); + } else { + pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); + } + } + return (r, sz); + } + + // field readers + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_state(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (int32 x, uint256 sz) = ProtoBufRuntime._decode_int32(p, bs); + r.state = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_ordering(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (int32 x, uint256 sz) = ProtoBufRuntime._decode_int32(p, bs); + r.ordering = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_counterparty(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (ProtoCounterparty.Data memory x, uint256 sz) = _decode_ProtoCounterparty(p, bs); + r.counterparty = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @param counters The counters for repeated fields + * @return The number of bytes decoded + */ + function _read_unpacked_repeated_connection_hops( + uint256 p, + bytes memory bs, + Data memory r, + uint256[6] memory counters + ) internal pure returns (uint256) { + /** + * if `r` is NULL, then only counting the number of fields. + */ + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + if (isNil(r)) { + counters[4] += 1; + } else { + r.connection_hops[r.connection_hops.length - counters[4]] = x; + counters[4] -= 1; + } + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_version(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + r.version = x; + return sz; + } + + // struct decoder + /** + * @dev The decoder for reading a inner struct field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The decoded inner-struct + * @return The number of bytes used to decode + */ + function _decode_ProtoCounterparty(uint256 p, bytes memory bs) + internal + pure + returns (ProtoCounterparty.Data memory, uint256) + { + uint256 pointer = p; + (uint256 sz, uint256 bytesRead) = ProtoBufRuntime._decode_varint(pointer, bs); + pointer += bytesRead; + (ProtoCounterparty.Data memory r,) = ProtoCounterparty._decode(pointer, bs, sz); + return (r, sz + bytesRead); + } + + // Encoder section + + /** + * @dev The main encoder for memory + * @param r The struct to be encoded + * @return The encoded byte array + */ + function encode(Data memory r) internal pure returns (bytes memory) { + bytes memory bs = new bytes(_estimate(r)); + uint256 sz = _encode(r, 32, bs); + assembly { + mstore(bs, sz) + } + return bs; + } + // inner encoder + + /** + * @dev The encoder for internal usage + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 pointer = p; + uint256 i; + if (r.state != 0) { + pointer += ProtoBufRuntime._encode_key(1, ProtoBufRuntime.WireType.Varint, pointer, bs); + pointer += ProtoBufRuntime._encode_int32(r.state, pointer, bs); + } + if (r.ordering != 0) { + pointer += ProtoBufRuntime._encode_key(2, ProtoBufRuntime.WireType.Varint, pointer, bs); + pointer += ProtoBufRuntime._encode_int32(r.ordering, pointer, bs); + } + + pointer += ProtoBufRuntime._encode_key(3, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoCounterparty._encode_nested(r.counterparty, pointer, bs); + + if (r.connection_hops.length != 0) { + for (i = 0; i < r.connection_hops.length; i++) { + pointer += ProtoBufRuntime._encode_key(4, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.connection_hops[i], pointer, bs); + } + } + if (bytes(r.version).length != 0) { + pointer += ProtoBufRuntime._encode_key(5, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.version, pointer, bs); + } + return pointer - offset; + } + // nested encoder + + /** + * @dev The encoder for inner struct + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode_nested(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * First encoded `r` into a temporary array, and encode the actual size used. + * Then copy the temporary array into `bs`. + */ + uint256 offset = p; + uint256 pointer = p; + bytes memory tmp = new bytes(_estimate(r)); + uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp); + uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs); + uint256 size = _encode(r, 32, tmp); + pointer += ProtoBufRuntime._encode_varint(size, pointer, bs); + ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size); + pointer += size; + delete tmp; + return pointer - offset; + } + // estimator + + /** + * @dev The estimator for a struct + * @param r The struct to be encoded + * @return The number of bytes encoded in estimation + */ + function _estimate(Data memory r) internal pure returns (uint256) { + uint256 e; + uint256 i; + e += 1 + ProtoBufRuntime._sz_int32(r.state); + e += 1 + ProtoBufRuntime._sz_int32(r.ordering); + e += 1 + ProtoBufRuntime._sz_lendelim(ProtoCounterparty._estimate(r.counterparty)); + for (i = 0; i < r.connection_hops.length; i++) { + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.connection_hops[i]).length); + } + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.version).length); + return e; + } + // empty checker + + function _empty(Data memory r) internal pure returns (bool) { + if (r.state != 0) { + return false; + } + + if (r.ordering != 0) { + return false; + } + + if (r.connection_hops.length != 0) { + return false; + } + + if (bytes(r.version).length != 0) { + return false; + } + + return true; + } + + //store function + /** + * @dev Store in-memory struct to storage + * @param input The in-memory struct + * @param output The in-storage struct + */ + function store(Data memory input, Data storage output) internal { + output.state = input.state; + output.ordering = input.ordering; + ProtoCounterparty.store(input.counterparty, output.counterparty); + output.connection_hops = input.connection_hops; + output.version = input.version; + } + + //array helpers for ConnectionHops + /** + * @dev Add value to an array + * @param self The in-memory struct + * @param value The value to add + */ + function addConnectionHops(Data memory self, string memory value) internal pure { + /** + * First resize the array. Then add the new element to the end. + */ + string[] memory tmp = new string[](self.connection_hops.length + 1); + for (uint256 i = 0; i < self.connection_hops.length; i++) { + tmp[i] = self.connection_hops[i]; + } + tmp[self.connection_hops.length] = value; + self.connection_hops = tmp; + } + + //utility functions + /** + * @dev Return an empty struct + * @return r The empty struct + */ + function nil() internal pure returns (Data memory r) { + assembly { + r := 0 + } + } + + /** + * @dev Test whether a struct is empty + * @param x The struct to be tested + * @return r True if it is empty + */ + function isNil(Data memory x) internal pure returns (bool r) { + assembly { + r := iszero(x) + } + } +} +//library ProtoChannel + +library ProtoCounterparty { + //struct definition + struct Data { + string port_id; + string channel_id; + } + + // Decoder section + + /** + * @dev The main decoder for memory + * @param bs The bytes array to be decoded + * @return The decoded struct + */ + function decode(bytes memory bs) internal pure returns (Data memory) { + (Data memory x,) = _decode(32, bs, bs.length); + return x; + } + + /** + * @dev The main decoder for storage + * @param self The in-storage struct + * @param bs The bytes array to be decoded + */ + function decode(Data storage self, bytes memory bs) internal { + (Data memory x,) = _decode(32, bs, bs.length); + store(x, self); + } + // inner decoder + + /** + * @dev The decoder for internal usage + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param sz The number of bytes expected + * @return The decoded struct + * @return The number of bytes decoded + */ + function _decode(uint256 p, bytes memory bs, uint256 sz) internal pure returns (Data memory, uint256) { + Data memory r; + uint256 fieldId; + ProtoBufRuntime.WireType wireType; + uint256 bytesRead; + uint256 offset = p; + uint256 pointer = p; + while (pointer < offset + sz) { + (fieldId, wireType, bytesRead) = ProtoBufRuntime._decode_key(pointer, bs); + pointer += bytesRead; + if (fieldId == 1) { + pointer += _read_port_id(pointer, bs, r); + } else if (fieldId == 2) { + pointer += _read_channel_id(pointer, bs, r); + } else { + pointer += ProtoBufRuntime._skip_field_decode(wireType, pointer, bs); + } + } + return (r, sz); + } + + // field readers + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_port_id(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + r.port_id = x; + return sz; + } + + /** + * @dev The decoder for reading a field + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @param r The in-memory struct + * @return The number of bytes decoded + */ + function _read_channel_id(uint256 p, bytes memory bs, Data memory r) internal pure returns (uint256) { + (string memory x, uint256 sz) = ProtoBufRuntime._decode_string(p, bs); + r.channel_id = x; + return sz; + } + + // Encoder section + + /** + * @dev The main encoder for memory + * @param r The struct to be encoded + * @return The encoded byte array + */ + function encode(Data memory r) internal pure returns (bytes memory) { + bytes memory bs = new bytes(_estimate(r)); + uint256 sz = _encode(r, 32, bs); + assembly { + mstore(bs, sz) + } + return bs; + } + // inner encoder + + /** + * @dev The encoder for internal usage + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + uint256 offset = p; + uint256 pointer = p; + + if (bytes(r.port_id).length != 0) { + pointer += ProtoBufRuntime._encode_key(1, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.port_id, pointer, bs); + } + if (bytes(r.channel_id).length != 0) { + pointer += ProtoBufRuntime._encode_key(2, ProtoBufRuntime.WireType.LengthDelim, pointer, bs); + pointer += ProtoBufRuntime._encode_string(r.channel_id, pointer, bs); + } + return pointer - offset; + } + // nested encoder + + /** + * @dev The encoder for inner struct + * @param r The struct to be encoded + * @param p The offset of bytes array to start decode + * @param bs The bytes array to be decoded + * @return The number of bytes encoded + */ + function _encode_nested(Data memory r, uint256 p, bytes memory bs) internal pure returns (uint256) { + /** + * First encoded `r` into a temporary array, and encode the actual size used. + * Then copy the temporary array into `bs`. + */ + uint256 offset = p; + uint256 pointer = p; + bytes memory tmp = new bytes(_estimate(r)); + uint256 tmpAddr = ProtoBufRuntime.getMemoryAddress(tmp); + uint256 bsAddr = ProtoBufRuntime.getMemoryAddress(bs); + uint256 size = _encode(r, 32, tmp); + pointer += ProtoBufRuntime._encode_varint(size, pointer, bs); + ProtoBufRuntime.copyBytes(tmpAddr + 32, bsAddr + pointer, size); + pointer += size; + delete tmp; + return pointer - offset; + } + // estimator + + /** + * @dev The estimator for a struct + * @param r The struct to be encoded + * @return The number of bytes encoded in estimation + */ + function _estimate(Data memory r) internal pure returns (uint256) { + uint256 e; + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.port_id).length); + e += 1 + ProtoBufRuntime._sz_lendelim(bytes(r.channel_id).length); + return e; + } + // empty checker + + function _empty(Data memory r) internal pure returns (bool) { + if (bytes(r.port_id).length != 0) { + return false; + } + + if (bytes(r.channel_id).length != 0) { + return false; + } + + return true; + } + + //store function + /** + * @dev Store in-memory struct to storage + * @param input The in-memory struct + * @param output The in-storage struct + */ + function store(Data memory input, Data storage output) internal { + output.port_id = input.port_id; + output.channel_id = input.channel_id; + } + + //utility functions + /** + * @dev Return an empty struct + * @return r The empty struct + */ + function nil() internal pure returns (Data memory r) { + assembly { + r := 0 + } + } + + /** + * @dev Test whether a struct is empty + * @param x The struct to be tested + * @return r True if it is empty + */ + function isNil(Data memory x) internal pure returns (bool r) { + assembly { + r := iszero(x) + } + } +} +//library ProtoCounterparty + +// lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract OwnableUpgradeable is Initializable_1, ContextUpgradeable { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + function __Ownable_init() internal onlyInitializing { + __Ownable_init_unchained(); + } + + function __Ownable_init_unchained() internal onlyInitializing { + _transferOwnership(_msgSender()); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[49] private __gap; +} + +// lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) + +/** + * @dev This abstract contract provides getters and event emitting update functions for + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. + * + * _Available since v4.1._ + */ +abstract contract ERC1967Upgrade is IERC1967 { + // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 + bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @dev Returns the current implementation address. + */ + function _getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 implementation slot. + */ + function _setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + } + + /** + * @dev Perform implementation upgrade + * + * Emits an {Upgraded} event. + */ + function _upgradeTo(address newImplementation) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + /** + * @dev Perform implementation upgrade with additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { + _upgradeTo(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + } + + /** + * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { + // Upgrades from old implementations will perform a rollback test. This test requires the new + // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing + // this special case will break upgrade paths from old UUPS implementation to new ones. + if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { + _setImplementation(newImplementation); + } else { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { + require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); + } catch { + revert("ERC1967Upgrade: new implementation is not UUPS"); + } + _upgradeToAndCall(newImplementation, data, forceCall); + } + } + + /** + * @dev Storage slot with the admin of the contract. + * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + /** + * @dev Returns the current admin. + */ + function _getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 admin slot. + */ + function _setAdmin(address newAdmin) private { + require(newAdmin != address(0), "ERC1967: new admin is the zero address"); + StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {AdminChanged} event. + */ + function _changeAdmin(address newAdmin) internal { + emit AdminChanged(_getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + /** + * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. + * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. + */ + bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + /** + * @dev Returns the current beacon. + */ + function _getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(_BEACON_SLOT).value; + } + + /** + * @dev Stores a new beacon in the EIP1967 beacon slot. + */ + function _setBeacon(address newBeacon) private { + require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); + require( + Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" + ); + StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; + } + + /** + * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does + * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). + * + * Emits a {BeaconUpgraded} event. + */ + function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); + } + } +} + +// lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol + +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol) + +/** + * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an + * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. + * + * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is + * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing + * `UUPSUpgradeable` with a custom implementation of upgrades. + * + * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. + * + * _Available since v4.1._ + */ +abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address private immutable __self = address(this); + + /** + * @dev Check that the execution is being performed through a delegatecall call and that the execution context is + * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case + * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a + * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to + * fail. + */ + modifier onlyProxy() { + require(address(this) != __self, "Function must be called through delegatecall"); + require(_getImplementation() == __self, "Function must be called through active proxy"); + _; + } + + /** + * @dev Check that the execution is not being performed through a delegate call. This allows a function to be + * callable on the implementing contract but not through proxies. + */ + modifier notDelegated() { + require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); + _; + } + + /** + * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the + * implementation. It is used to validate the implementation's compatibility when performing an upgrade. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. + */ + function proxiableUUID() external view virtual override notDelegated returns (bytes32) { + return _IMPLEMENTATION_SLOT; + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeTo(address newImplementation) public virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call + * encoded in `data`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, data, true); + } + + /** + * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by + * {upgradeTo} and {upgradeToAndCall}. + * + * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. + * + * ```solidity + * function _authorizeUpgrade(address) internal override onlyOwner {} + * ``` + */ + function _authorizeUpgrade(address newImplementation) internal virtual; +} + +// contracts/libs/Ibc.sol + +/** + * Ibc.sol + * Basic IBC data structures and utilities. + */ + +/// IbcPacket represents the packet data structure received from a remote chain +/// over an IBC channel. +struct IbcPacket { + /// identifies the channel and port on the sending chain. + IbcEndpoint src; + /// identifies the channel and port on the receiving chain. + IbcEndpoint dest; + /// The sequence number of the packet on the given channel + uint64 sequence; + bytes data; + /// block height after which the packet times out + Height timeoutHeight; + /// block timestamp (in nanoseconds) after which the packet times out + uint64 timeoutTimestamp; +} + +// UniversalPacke represents the data field of an IbcPacket +struct UniversalPacket { + bytes32 srcPortAddr; + // source middleware ids bitmap, ie. logic OR of all MW IDs in the MW stack. + uint256 mwBitmap; + bytes32 destPortAddr; + bytes appData; +} + +/// Height is a monotonically increasing data type +/// that can be compared against another Height for the purposes of updating and +/// freezing clients +/// +/// Normally the RevisionHeight is incremented at each height while keeping +/// RevisionNumber the same. However some consensus algorithms may choose to +/// reset the height in certain conditions e.g. hard forks, state-machine +/// breaking changes In these cases, the RevisionNumber is incremented so that +/// height continues to be monitonically increasing even as the RevisionHeight +/// gets reset +struct Height { + uint64 revision_number; + uint64 revision_height; +} + +struct AckPacket { + // success indicates the dApp-level logic. Even when a dApp fails to process a packet per its dApp logic, the + // delivery of packet and ack packet are still considered successful. + bool success; + bytes data; +} + +struct IncentivizedAckPacket { + bool success; + // Forward relayer's payee address, an EMV address registered on Polymer chain with `RegisterCounterpartyPayee` + // endpoint. + // In case of missing payee, zero address is used on Polymer. + // The relayer payee address is set when incentivized ack is created on Polymer. + bytes relayer; + bytes data; +} + +enum ChannelOrder { + NONE, + UNORDERED, + ORDERED +} + +enum ChannelState { + // Default State + UNINITIALIZED, + // A channel has just started the opening handshake. + INIT, + // A channel has acknowledged the handshake step on the counterparty chain. + TRYOPEN, + // A channel has completed the handshake. Open channels are + // ready to send and receive packets. + OPEN, + // A channel has been closed and can no longer be used to send or receive + // packets. + CLOSED, + // A channel has been forced closed due to a frozen client in the connection + // path. + FROZEN, + // A channel has acknowledged the handshake step on the counterparty chain, but not yet confirmed with a virtual + // chain. Virtual channel end ONLY. + TRY_PENDING, + // A channel has finished the ChanOpenAck handshake step on chain A, but not yet confirmed with the corresponding + // virtual chain. Virtual channel end ONLY. + ACK_PENDING, + // A channel has finished the ChanOpenConfirm handshake step on chain B, but not yet confirmed with the + // corresponding + // virtual chain. Virtual channel end ONLY. + CONFIRM_PENDING, + // A channel has finished the ChanCloseConfirm step on chainB, but not yet confirmed with the corresponding + // virtual chain. Virtual channel end ONLY. + CLOSE_CONFIRM_PENDING +} + +struct Channel { + string version; + ChannelOrder ordering; + bool feeEnabled; + string[] connectionHops; + string counterpartyPortId; + bytes32 counterpartyChannelId; +} + +struct ChannelEnd { + string portId; + bytes32 channelId; + string version; +} + +struct IbcEndpoint { + string portId; + bytes32 channelId; +} + +struct Proof { + // block height at which the proof is valid for a membership or non-membership at the given keyPath + Height proofHeight; + // ics23 merkle proof + bytes proof; +} + +// misc errors. +library IBCErrors { + error invalidCounterParty(); + error invalidCounterPartyPortId(); + error invalidHexStringLength(); + error invalidRelayerAddress(); + error consensusStateVerificationFailed(); + error packetNotTimedOut(); + error invalidAddress(); + + // packet sequence related errors. + error invalidPacketSequence(); + error unexpectedPacketSequence(); + + // channel related errors. + error channelNotOwnedBySender(); + error channelNotOwnedByPortAddress(); + + // client related errors. + error clientAlreadyCreated(); + error clientNotCreated(); + + // packet commitment related errors. + error packetCommitmentNotFound(); + error ackPacketCommitmentAlreadyExists(); + error packetReceiptAlreadyExists(); + + // receiver related errors. + error receiverNotIntendedPacketDestination(); + error receiverNotOriginPacketSender(); + + error invalidChannelType(string channelType); +} + +// define a library of Ibc utility functions +library IbcUtils { + error StringTooLong(); + + // fromUniversalPacketBytes converts UniversalPacketDataBytes to UniversalPacketData, per how its packed into bytes + function fromUniversalPacketBytes(bytes calldata data) + external + pure + returns (UniversalPacket memory universalPacketData) + { + bytes32 srcPortAddr; + uint256 mwBitmap; + bytes32 destPortAddr; + assembly { + // Keep reusing 0x0 to move from calldata to return vars + calldatacopy(0x0, data.offset, 32) + srcPortAddr := mload(0x0) + calldatacopy(0x0, add(data.offset, 32), 32) + mwBitmap := mload(0x0) + calldatacopy(0x0, add(data.offset, 64), 32) + destPortAddr := mload(0x0) + } + universalPacketData = UniversalPacket(srcPortAddr, uint256(mwBitmap), destPortAddr, data[96:data.length]); + } + + /** + * Convert a non-0x-prefixed hex string to an address + * @param hexStr hex string to convert to address. Note that the hex string must not include a 0x prefix. + * hexStr is case-insensitive. + */ + function hexStrToAddress(string memory hexStr) public pure returns (address addr) { + if (bytes(hexStr).length != 40) { + revert IBCErrors.invalidHexStringLength(); + } + + bytes memory strBytes = bytes(hexStr); + bytes memory addrBytes = new bytes(20); + + for (uint256 i = 0; i < 20; i++) { + uint8 high = uint8(strBytes[i * 2]); + uint8 low = uint8(strBytes[1 + i * 2]); + // Convert to lowercase if the character is in uppercase + if (high >= 65 && high <= 90) { + high += 32; + } + if (low >= 65 && low <= 90) { + low += 32; + } + uint8 digit = (high - (high >= 97 ? 87 : 48)) * 16 + (low - (low >= 97 ? 87 : 48)); + addrBytes[i] = bytes1(digit); + } + + assembly { + addr := mload(add(addrBytes, 20)) + } + + return addr; + } + + // For XXXX => vIBC direction, SC needs to verify the proof of membership of TRY_PENDING + // For vIBC initiated channel, SC doesn't need to verify any proof, and these should be all empty + function isChannelOpenTry(ChannelEnd calldata counterparty) public pure returns (bool open) { + if (counterparty.channelId == bytes32(0) && bytes(counterparty.version).length == 0) { + return false; + // ChanOpenInit with unknow conterparty + } else if (counterparty.channelId != bytes32(0) && bytes(counterparty.version).length != 0) { + // this is the ChanOpenTry; counterparty must not be zero-value + return true; + } else { + revert IBCErrors.invalidCounterParty(); + } + } + + function toUniversalPacketBytes(UniversalPacket memory data) internal pure returns (bytes memory packetBytes) { + packetBytes = bytes.concat(data.srcPortAddr, bytes32(data.mwBitmap), data.destPortAddr, data.appData); + } + + // addressToPortId converts an address to a port ID + function addressToPortId(string memory portPrefix, address addr) internal pure returns (string memory portId) { + portId = string(abi.encodePacked(portPrefix, toHexStr(addr))); + } + + // convert an address to its hex string, but without 0x prefix + function toHexStr(address addr) internal pure returns (bytes memory hexStr) { + bytes memory addrWithPrefix = abi.encodePacked(Strings.toHexString(addr)); + bytes memory addrWithoutPrefix = new bytes(addrWithPrefix.length - 2); + for (uint256 i = 0; i < addrWithoutPrefix.length; i++) { + addrWithoutPrefix[i] = addrWithPrefix[i + 2]; + } + hexStr = addrWithoutPrefix; + } + + // toAddress converts a bytes32 to an address + function toAddress(bytes32 b) internal pure returns (address out) { + out = address(uint160(uint256(b))); + } + + // toBytes32 converts an address to a bytes32 + function toBytes32(address a) internal pure returns (bytes32 out) { + out = bytes32(uint256(uint160(a))); + } + + function toBytes32(string memory s) internal pure returns (bytes32 result) { + bytes memory b = bytes(s); + if (b.length > 32) revert StringTooLong(); + + assembly { + result := mload(add(b, 32)) + } + } +} + +library Ibc { + /** + * Convert a non-0x-prefixed hex string to an address + * @param hexStr hex string to convert to address. Note that the hex string must not include a 0x prefix. + * hexStr is case-insensitive. + */ + function _hexStrToAddress(string memory hexStr) external pure returns (address addr) { + if (bytes(hexStr).length != 40) { + revert IBCErrors.invalidHexStringLength(); + } + + bytes memory strBytes = bytes(hexStr); + bytes memory addrBytes = new bytes(20); + + for (uint256 i = 0; i < 20; i++) { + uint8 high = uint8(strBytes[i * 2]); + uint8 low = uint8(strBytes[1 + i * 2]); + // Convert to lowercase if the character is in uppercase + if (high >= 65 && high <= 90) { + high += 32; + } + if (low >= 65 && low <= 90) { + low += 32; + } + uint8 digit = (high - (high >= 97 ? 87 : 48)) * 16 + (low - (low >= 97 ? 87 : 48)); + addrBytes[i] = bytes1(digit); + } + + assembly { + addr := mload(add(addrBytes, 20)) + } + } + + // For XXXX => vIBC direction, SC needs to verify the proof of membership of TRY_PENDING + // For vIBC initiated channel, SC doesn't need to verify any proof, and these should be all empty + function _isChannelOpenTry(ChannelEnd calldata counterparty) external pure returns (bool open) { + if (counterparty.channelId == bytes32(0) && bytes(counterparty.version).length == 0) { + open = false; + // ChanOpenInit with unknow conterparty + } else if (counterparty.channelId != bytes32(0) && bytes(counterparty.version).length != 0) { + // this is the ChanOpenTry; counterparty must not be zero-value + open = true; + } else { + revert IBCErrors.invalidCounterParty(); + } + } + + function toStr(bytes32 b) public pure returns (string memory outStr) { + uint8 i = 0; + while (i < 32 && b[i] != 0) { + i++; + } + bytes memory bytesArray = new bytes(i); + for (uint8 j = 0; j < i; j++) { + bytesArray[j] = b[j]; + } + outStr = string(bytesArray); + } + + function toStr(uint256 _number) public pure returns (string memory outStr) { + if (_number == 0) { + return "0"; + } + + uint256 length; + uint256 number = _number; + + // Determine the length of the string + while (number != 0) { + length++; + number /= 10; + } + + bytes memory buffer = new bytes(length); + + // Convert each digit to its ASCII representation + for (uint256 i = length; i > 0; i--) { + buffer[i - 1] = bytes1(uint8(48 + (_number % 10))); + _number /= 10; + } + + outStr = string(buffer); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/24-host/keys.go#L135 + function channelProofKey(string calldata portId, bytes32 channelId) public pure returns (bytes memory proofKey) { + proofKey = abi.encodePacked("channelEnds/ports/", portId, "/channels/", toStr(channelId)); + } + + // protobuf encoding of a channel object + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/04-channel/keeper/keeper.go#L92 + function channelProofValue( + ChannelState state, + ChannelOrder ordering, + string calldata version, + string[] calldata connectionHops, + ChannelEnd calldata counterparty + ) public pure returns (bytes memory proofValue) { + proofValue = ProtoChannel.encode( + ProtoChannel.Data( + int32(uint32(state)), + int32(uint32(ordering)), + ProtoCounterparty.Data(counterparty.portId, toStr(counterparty.channelId)), + connectionHops, + version + ) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/24-host/keys.go#L185 + function packetCommitmentProofKey(IbcPacket calldata packet) public pure returns (bytes memory proofKey) { + proofKey = abi.encodePacked( + "commitments/ports/", + packet.src.portId, + "/channels/", + toStr(packet.src.channelId), + "/sequences/", + toStr(packet.sequence) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/04-channel/types/packet.go#L19 + function packetCommitmentProofValue(IbcPacket calldata packet) public pure returns (bytes32 proofValue) { + proofValue = sha256( + abi.encodePacked( + packet.timeoutTimestamp, + packet.timeoutHeight.revision_number, + packet.timeoutHeight.revision_height, + sha256(packet.data) + ) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/24-host/keys.go#L201 + function ackProofKey(IbcPacket calldata packet) public pure returns (bytes memory proofKey) { + proofKey = abi.encodePacked( + "acks/ports/", + packet.dest.portId, + "/channels/", + toStr(packet.dest.channelId), + "/sequences/", + toStr(packet.sequence) + ); + } + + // https://github.com/open-ibc/ibcx-go/blob/ef80dd6784fd/modules/core/04-channel/types/packet.go#L38 + function ackProofValue(bytes calldata ack) public pure returns (bytes32 proofValue) { + proofValue = sha256(ack); + } + + function parseAckData(bytes calldata ack) public pure returns (AckPacket memory ackData) { + // this hex value is '"result"' + ackData = (keccak256(ack[1:9]) == keccak256(hex"22726573756c7422")) + ? AckPacket(true, Base64.decode(string(ack[11:ack.length - 2]))) // result success + : AckPacket(false, ack[10:ack.length - 2]); // this is an error + } +} + +// contracts/interfaces/IbcDispatcher.sol + +/** + * @title IbcPacketSender + * @author Polymer Labs + * @dev IBC packet sender interface. + */ +interface IbcPacketSender { + function sendPacket(bytes32 channelId, bytes calldata payload, uint64 timeoutTimestamp) external; +} + +/** + * @title IbcDispatcher + * @author Polymer Labs + * @notice IBC dispatcher interface is the Polymer Core Smart Contract that implements the core IBC protocol. + * @dev IBC-compatible contracts depend on this interface to actively participate in the IBC protocol. + * Other features are implemented as callback methods in the IbcReceiver interface. + */ +interface IbcDispatcher is IbcPacketSender { + function channelOpenInit( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external; + + function closeIbcChannel(bytes32 channelId) external; + + function portPrefix() external view returns (string memory portPrefix); +} + +/** + * @title IbcEventsEmitter + * @notice IBC CoreSC events interface. + */ +interface IbcEventsEmitter { + // + // channel events + // + event ChannelOpenInit( + address indexed recevier, + string version, + ChannelOrder ordering, + bool feeEnabled, + string[] connectionHops, + string counterpartyPortId + ); + event ChannelOpenInitError(address indexed receiver, bytes error); + + event ChannelOpenTry( + address indexed receiver, + string version, + ChannelOrder ordering, + bool feeEnabled, + string[] connectionHops, + string counterpartyPortId, + bytes32 counterpartyChannelId + ); + event ChannelOpenTryError(address indexed receiver, bytes error); + + event ChannelOpenAck(address indexed receiver, bytes32 channelId); + event ChannelOpenAckError(address indexed receiver, bytes error); + + event ChannelOpenConfirm(address indexed receiver, bytes32 channelId); + event ChannelOpenConfirmError(address indexed receiver, bytes error); + + event CloseIbcChannel(address indexed portAddress, bytes32 indexed channelId); + + event CloseIbcChannelError(address indexed receiver, bytes error); + event AcknowledgementError(address indexed receiver, bytes error); + event TimeoutError(address indexed receiver, bytes error); + + // + // packet events + // + event SendPacket( + address indexed sourcePortAddress, + bytes32 indexed sourceChannelId, + bytes packet, + uint64 sequence, + // timeoutTimestamp is in UNIX nano seconds; packet will be rejected if + // delivered after this timestamp on the receiving chain. + // Timeout semantics is compliant to IBC spec and ibc-go implementation + uint64 timeoutTimestamp + ); + + event Acknowledgement(address indexed sourcePortAddress, bytes32 indexed sourceChannelId, uint64 sequence); + + event Timeout(address indexed sourcePortAddress, bytes32 indexed sourceChannelId, uint64 indexed sequence); + + event RecvPacket(address indexed destPortAddress, bytes32 indexed destChannelId, uint64 sequence); + + event WriteAckPacket( + address indexed writerPortAddress, bytes32 indexed writerChannelId, uint64 sequence, AckPacket ackPacket + ); + + event WriteTimeoutPacket( + address indexed writerPortAddress, + bytes32 indexed writerChannelId, + uint64 sequence, + Height timeoutHeight, + uint64 timeoutTimestamp + ); +} + +// contracts/interfaces/IbcReceiver.sol + +/** + * @title IbcChannelReceiver + * @dev This interface must be implemented by IBC-enabled contracts that act as channel owners and process channel + * handshake callbacks. + */ +interface IbcChannelReceiver { + function onChanOpenInit( + ChannelOrder order, + string[] calldata connectionHops, + string calldata counterpartyPortIdentifier, + string calldata version + ) external returns (string memory selectedVersion); + + function onChanOpenTry( + ChannelOrder order, + string[] memory connectionHops, + bytes32 channelId, + string memory counterpartyPortIdentifier, + bytes32 counterpartychannelId, + string memory counterpartyVersion + ) external returns (string memory selectedVersion); + + function onChanOpenAck(bytes32 channelId, bytes32 counterpartychannelId, string calldata counterpartyVersion) + external; + + function onChanOpenConfirm(bytes32 channelId) external; + function onCloseIbcChannel( + bytes32 channelId, + string calldata counterpartyPortIdentifier, + bytes32 counterpartyChannelId + ) external; +} + +/** + * @title IbcPacketReceiver + * @notice Packet handler interface must be implemented by a IBC-enabled contract. + * @dev Packet handling callback methods are invoked by the IBC dispatcher. + */ +interface IbcPacketReceiver { + function onRecvPacket(IbcPacket calldata packet) external returns (AckPacket memory ackPacket); + + function onAcknowledgementPacket(IbcPacket calldata packet, AckPacket calldata ack) external; + + function onTimeoutPacket(IbcPacket calldata packet) external; +} + +/** + * @title IbcReceiver + * @author Polymer Labs + * @notice IBC receiver interface must be implemented by a IBC-enabled contract. + * The implementer, aka. dApp devs, should implement channel handshake and packet handling methods. + */ +interface IbcReceiver is IbcChannelReceiver, IbcPacketReceiver {} + +contract IbcReceiverBase is Ownable { + IbcDispatcher public dispatcher; + + error notIbcDispatcher(); + error UnsupportedVersion(); + error ChannelNotFound(); + + /** + * @dev Modifier to restrict access to only the IBC dispatcher. + * Only the address with the IBC_ROLE can execute the function. + * Should add this modifier to all IBC-related callback functions. + */ + modifier onlyIbcDispatcher() { + if (msg.sender != address(dispatcher)) { + revert notIbcDispatcher(); + } + _; + } + + /** + * @dev Constructor function that takes an IbcDispatcher address and grants the IBC_ROLE to the Polymer IBC + * Dispatcher. + * @param _dispatcher The address of the IbcDispatcher contract. + */ + constructor(IbcDispatcher _dispatcher) Ownable() { + dispatcher = _dispatcher; + } + + /// This function is called for plain Ether transfers, i.e. for every call with empty calldata. + // An empty function body is sufficient to receive packet fee refunds. + receive() external payable {} +} + +// contracts/interfaces/IDispatcher.sol + +interface IDispatcherRc4 is IbcDispatcher, IbcEventsEmitter { + function setPortPrefix(string calldata _portPrefix) external; + + function updateClientWithOptimisticConsensusState( + L1Header calldata l1header, + OpL2StateProof calldata proof, + uint256 height, + uint256 appHash + ) external returns (uint256 fraudProofEndTime, bool ended); + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenInit. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenInit( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external; + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenTry. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenTry( + ChannelEnd calldata local, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external; + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the third channel handshake method: ChanOpenAck + */ + function channelOpenAck( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external; + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the last channel handshake method: + * ChannelOpenConfirm + */ + function channelOpenConfirm( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external; + + function closeIbcChannel(bytes32 channelId) external; + + function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) external; + + function acknowledgement(IbcPacket calldata packet, bytes calldata ack, Ics23Proof calldata proof) external; + + function timeout(IbcPacket calldata packet, Ics23Proof calldata proof) external; + + function writeTimeoutPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external; + + function recvPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external; + + function getOptimisticConsensusState(uint256 height) + external + view + returns (uint256 appHash, uint256 fraudProofEndTime, bool ended); + + function getChannel(address portAddress, bytes32 channelId) external view returns (Channel memory channel); +} + +// contracts/core/Dispatcher.sol + +/** + * @title Dispatcher + * @author Polymer Labs + * @notice + * Contract callers call this contract to send IBC-like msg, + * which can be relayed to a rollup module on the Polymerase chain + */ +contract DispatcherRc4 is OwnableUpgradeable, UUPSUpgradeable, IDispatcherRc4 { + uint256[49] private __gap; + + // + // fields + // + // IBC_PortID = portPrefix + address (hex string without 0x prefix, case insensitive) + string public portPrefix; + uint32 public portPrefixLen; + + mapping(address => mapping(bytes32 => Channel)) private _portChannelMap; + mapping(address => mapping(bytes32 => uint64)) private _nextSequenceSend; + // keep track of received packets' sequences to ensure channel ordering is enforced for ordered channels + mapping(address => mapping(bytes32 => uint64)) private _nextSequenceRecv; + mapping(address => mapping(bytes32 => uint64)) private _nextSequenceAck; + // only stores a bit to mark packet has not been ack'ed or timed out yet; actual IBC packet verification is done on + // Polymer chain. + // Keep track of sent packets + mapping(address => mapping(bytes32 => mapping(uint64 => bool))) private _sendPacketCommitment; + // keep track of received packets to prevent replay attack + mapping(address => mapping(bytes32 => mapping(uint64 => bool))) private _recvPacketReceipt; + // keep track of outbound ack packets to prevent replay attack + mapping(address => mapping(bytes32 => mapping(uint64 => bool))) private _ackPacketCommitment; + + LightClient _lightClient; // Can't be set to immutable since it needs to be called in the initializer; not the + + //////// NEW storage + mapping(bytes32 => string) private _channelIdToConnection; + + // constructor + + // + // methods + // + constructor() { + _disableInitializers(); + } + + function initialize(string memory initPortPrefix, LightClient lightClient) public initializer { + __Ownable_init(); + portPrefix = initPortPrefix; + portPrefixLen = uint32(bytes(initPortPrefix).length); + _lightClient = lightClient; + } + + // + // CoreSC maaintainer methods, only invoked by the owner + // + function setPortPrefix(string calldata _portPrefix) external onlyOwner { + portPrefix = _portPrefix; + portPrefixLen = uint32(bytes(_portPrefix).length); + } + + // updateClientWithOptimisticConsensusState updates the client + // with the optimistic consensus state. The optimistic consensus + // is accepted and will be open for verify in the fraud proof + // window. + function updateClientWithOptimisticConsensusState( + L1Header calldata l1header, + OpL2StateProof calldata proof, + uint256 height, + uint256 appHash + ) external returns (uint256 fraudProofEndTime, bool ended) { + return _lightClient.addOpConsensusState(l1header, proof, height, appHash); + } + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenInit. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenInit( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external { + if (bytes(counterpartyPortId).length == 0) { + revert IBCErrors.invalidCounterPartyPortId(); + } + + // Have to encode here to avoid stack-too-deep error + bytes memory chanOpenInitArgs = abi.encode(ordering, connectionHops, counterpartyPortId, version); + (bool success, bytes memory data) = + _callIfContract(msg.sender, bytes.concat(IbcChannelReceiver.onChanOpenInit.selector, chanOpenInitArgs)); + + if (success) { + emit ChannelOpenInit( + msg.sender, abi.decode(data, (string)), ordering, feeEnabled, connectionHops, counterpartyPortId + ); + } else { + emit ChannelOpenInitError(msg.sender, data); + } + } + + /** + * This function is called by a 'relayer' on behalf of a dApp. The dApp should implement IbcChannelHandler's + * onChanOpenTry. If the callback succeeds, the dApp should return the selected version and the emitted event + * will be relayed to the IBC/VIBC hub chain. + */ + function channelOpenTry( + ChannelEnd calldata local, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external { + if (bytes(counterparty.portId).length == 0) { + revert IBCErrors.invalidCounterPartyPortId(); + } + + _lightClient.verifyMembership( + proof, + Ibc.channelProofKey(local.portId, local.channelId), + Ibc.channelProofValue(ChannelState.TRY_PENDING, ordering, local.version, connectionHops, counterparty) + ); + + address receiver = _getAddressFromPort(local.portId); + (bool success, bytes memory data) = _callIfContract( + receiver, + abi.encodeWithSelector( + IbcChannelReceiver.onChanOpenTry.selector, + ordering, + connectionHops, + local.channelId, + counterparty.portId, + counterparty.channelId, + counterparty.version + ) + ); + + if (success) { + emit ChannelOpenTry( + receiver, + abi.decode(data, (string)), + ordering, + feeEnabled, + connectionHops, + counterparty.portId, + counterparty.channelId + ); + } else { + emit ChannelOpenTryError(receiver, data); + } + } + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the third channel handshake method: ChanOpenAck + */ + function channelOpenAck( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external { + _lightClient.verifyMembership( + proof, + Ibc.channelProofKey(local.portId, local.channelId), + Ibc.channelProofValue(ChannelState.ACK_PENDING, ordering, local.version, connectionHops, counterparty) + ); + + address receiver = _getAddressFromPort(local.portId); + (bool success, bytes memory data) = _callIfContract( + receiver, + abi.encodeWithSelector( + IbcChannelReceiver.onChanOpenAck.selector, local.channelId, counterparty.channelId, counterparty.version + ) + ); + + if (success) { + _connectChannel(IbcChannelReceiver(receiver), local, connectionHops, ordering, feeEnabled, counterparty); + emit ChannelOpenAck(receiver, local.channelId); + } else { + emit ChannelOpenAckError(receiver, data); + } + } + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed the ChannelOpenTry event. + * The dApp should implement the onChannelConnect method to handle the last channel handshake method: + * ChannelOpenConfirm + */ + function channelOpenConfirm( + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty, + Ics23Proof calldata proof + ) external { + _lightClient.verifyMembership( + proof, + Ibc.channelProofKey(local.portId, local.channelId), + Ibc.channelProofValue(ChannelState.CONFIRM_PENDING, ordering, local.version, connectionHops, counterparty) + ); + + address receiver = _getAddressFromPort(local.portId); + (bool success, bytes memory data) = _callIfContract( + receiver, + abi.encodeWithSelector(IbcChannelReceiver.onChanOpenConfirm.selector, local.channelId, counterparty.version) + ); + + if (success) { + _connectChannel(IbcChannelReceiver(receiver), local, connectionHops, ordering, feeEnabled, counterparty); + emit ChannelOpenConfirm(receiver, local.channelId); + } else { + emit ChannelOpenConfirmError(receiver, data); + } + } + + /** + * @dev Emits a `CloseIbcChannel` event with the given `channelId` and the address of the message sender + * @notice Close the specified IBC channel by channel ID + * Must be called by the channel owner, ie. _portChannelMap[msg.sender][channelId] must exist + */ + function closeIbcChannel(bytes32 channelId) external { + Channel memory channel = _portChannelMap[msg.sender][channelId]; + if (channel.counterpartyChannelId == bytes32(0)) { + revert IBCErrors.channelNotOwnedBySender(); + } + + (bool success, bytes memory data) = _callIfContract( + msg.sender, + abi.encodeWithSelector( + IbcChannelReceiver.onCloseIbcChannel.selector, + channelId, + channel.counterpartyPortId, + channel.counterpartyChannelId + ) + ); + if (success) { + emit CloseIbcChannel(msg.sender, channelId); + } else { + emit CloseIbcChannelError(address(msg.sender), data); + } + } + + /** + * This func is called by a 'relayer' after the IBC/VIBC hub chain has processed ChanCloseConfirm event. + * The dApp's onCloseIbcChannel callback is invoked. + * dApp should throw an error if the channel should not be closed. + */ + // FIXME this is commented out to make the contract size smaller. We need to optimise for size + // function onCloseIbcChannel(address portAddress, bytes32 channelId, Ics23Proof calldata proof) external { + // // verify VIBC/IBC hub chain has processed ChanCloseConfirm event + // _lightClient.verifyMembership( + // proof, + // bytes('channel/path/to/be/added/here'), + // bytes('expected channel bytes constructed from params. Channel.State = {Closed(_Pending?)}') + // ); + // + // // ensure port owns channel + // Channel memory channel = _portChannelMap[portAddress][channelId]; + // if (channel.counterpartyChannelId == bytes32(0)) { + // revert channelNotOwnedByPortAddress(); + // } + // + // // confirm with dApp by calling its callback + // IbcChannelReceiver reciever = IbcChannelReceiver(portAddress); + // reciever.onCloseIbcChannel(channelId, channel.counterpartyPortId, + // channel.counterpartyChannelId); + // delete _portChannelMap[portAddress][channelId]; + // emit CloseIbcChannel(portAddress, channelId); + // } + + // + // IBC Packet methods + // + + /** + * @notice Sends an IBC packet on a existing channel with the specified packet data and timeout block timestamp. + * @notice Data should be encoded in a format defined by the channel version, and the module on the other side + * should know how to parse this. + * @dev Emits an `IbcPacketEvent` event containing the sender address, channel ID, packet data, and timeout block + * timestamp. + * @param channelId The ID of the channel on which to send the packet. + * @param packet The packet data to send. + * @param timeoutTimestamp The timestamp in nanoseconds after which the packet times out if it has not been + * received. + */ + function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) external { + // ensure port owns channel + Channel memory channel = _portChannelMap[msg.sender][channelId]; + if (channel.counterpartyChannelId == bytes32(0)) { + revert IBCErrors.channelNotOwnedBySender(); + } + + _sendPacket(msg.sender, channelId, packet, timeoutTimestamp); + } + /** + * @notice Handle the acknowledgement of an IBC packet by the counterparty + * @dev Verifies the given proof and calls the `onAcknowledgementPacket` function on the given `receiver` contract, + * ie. the IBC dApp. + * Prerequisite: the original packet is committed and not ack'ed or timed out yet. + * Note: If the receiving dapp doesn't satisfy the interface, the transaction will be reverted. + * @param packet The IbcPacket data for the acknowledged packet + * @param ack The acknowledgement receipt for the packet + * @param proof The membership proof to verify the packet acknowledgement committed on Polymer chain + */ + + function acknowledgement(IbcPacket calldata packet, bytes calldata ack, Ics23Proof calldata proof) external { + address receiver = _getAddressFromPort(packet.src.portId); + // prove ack packet is on Polymer chain + _lightClient.verifyMembership(proof, Ibc.ackProofKey(packet), abi.encode(Ibc.ackProofValue(ack))); + // verify packet has been committed and not yet ack'ed or timed out + bool hasCommitment = _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + if (!hasCommitment) { + revert IBCErrors.packetCommitmentNotFound(); + } + + // enforce ack'ed packet sequences always increment by 1 for ordered channels + Channel memory channel = _portChannelMap[receiver][packet.src.channelId]; + (bool success, bytes memory data) = _callIfContract( + receiver, + abi.encodeWithSelector(IbcPacketReceiver.onAcknowledgementPacket.selector, packet, Ibc.parseAckData(ack)) + ); + + if (success) { + if (channel.ordering == ChannelOrder.ORDERED) { + if (packet.sequence != _nextSequenceAck[receiver][packet.src.channelId]) { + revert IBCErrors.unexpectedPacketSequence(); + } + + _nextSequenceAck[receiver][packet.src.channelId] = packet.sequence + 1; + } + + // delete packet commitment to avoid double ack + delete _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + emit Acknowledgement(receiver, packet.src.channelId, packet.sequence); + } else { + emit AcknowledgementError(receiver, data); + } + } + + /** + * @notice Timeout of an IBC packet + * @dev Verifies the given proof and calls the `onTimeoutPacket` function on the given `receiver` contract, ie. the + * IBC-dApp. + * Prerequisite: the original packet is committed and not ack'ed or timed out yet. + * If the receiving dapp doesn't satisfy the interface, the transaction will be reverted. + * @param packet The IbcPacket data for the timed-out packet + * @param proof The non-membership proof data needed to verify the packet timeout + */ + function timeout(IbcPacket calldata packet, Ics23Proof calldata proof) external { + // prove absence of packet receipt on Polymer chain + // TODO: add non membership support + _lightClient.verifyNonMembership(proof, "packet/receipt/path"); + + address receiver = _getAddressFromPort(packet.src.portId); + // verify packet has been committed and not yet ack'ed or timed out + bool hasCommitment = _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + if (!hasCommitment) { + revert IBCErrors.packetCommitmentNotFound(); + } + + (bool success, bytes memory data) = + _callIfContract(receiver, abi.encodeWithSelector(IbcPacketReceiver.onTimeoutPacket.selector, packet)); + if (success) { + // delete packet commitment to avoid double timeout + delete _sendPacketCommitment[receiver][packet.src.channelId][packet.sequence]; + emit Timeout(receiver, packet.src.channelId, packet.sequence); + } else { + emit TimeoutError(receiver, data); + } + } + + /** + * @notice Receive an IBC packet and then pass it to the IBC-dApp for processing if verification succeeds. + * @dev Verifies the given proof and calls the `onRecvPacket` function on the given `receiver` contract + * If the address doesn't satisfy the interface, the transaction will be reverted. + * The receiver must be the intended packet destination, which is the same as packet.dest.portId. + * @param packet The IbcPacket data for the received packet + * @param proof The proof data needed to verify the packet receipt + * @dev Emit an `RecvPacket` event with the details of the received packet; + * Also emit a WriteAckPacket event, which can be relayed to Polymer chain by relayers + */ + function recvPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external { + address receiver = _getAddressFromPort(packet.dest.portId); + _lightClient.verifyMembership( + proof, Ibc.packetCommitmentProofKey(packet), abi.encode(Ibc.packetCommitmentProofValue(packet)) + ); + + // verify packet has not been received yet + bool hasReceipt = _recvPacketReceipt[receiver][packet.dest.channelId][packet.sequence]; + if (hasReceipt) { + revert IBCErrors.packetReceiptAlreadyExists(); + } + + _recvPacketReceipt[receiver][packet.dest.channelId][packet.sequence] = true; + + // enforce recv'ed packet sequences always increment by 1 for ordered channels + Channel memory channel = _portChannelMap[receiver][packet.dest.channelId]; + if (channel.ordering == ChannelOrder.ORDERED) { + if (packet.sequence != _nextSequenceRecv[receiver][packet.dest.channelId]) { + revert IBCErrors.unexpectedPacketSequence(); + } + + _nextSequenceRecv[receiver][packet.dest.channelId] = packet.sequence + 1; + } + + // Emit recv packet event to prove the relayer did the correct job, and pkt is received. + emit RecvPacket(receiver, packet.dest.channelId, packet.sequence); + + // If pkt is already timed out, then return early so dApps won't receive it. + if (_isPacketTimeout(packet)) { + emit WriteTimeoutPacket( + receiver, packet.dest.channelId, packet.sequence, packet.timeoutHeight, packet.timeoutTimestamp + ); + return; + } + + // Not timeout yet, then do normal handling + IbcPacket memory pkt = packet; + AckPacket memory ack; + (bool success, bytes memory data) = + _callIfContract(receiver, abi.encodeWithSelector(IbcPacketReceiver.onRecvPacket.selector, pkt)); + if (success) { + (ack) = abi.decode(data, (AckPacket)); + } else { + ack = AckPacket(false, data); + } + bool hasAckPacketCommitment = _ackPacketCommitment[receiver][packet.dest.channelId][packet.sequence]; + // check is not necessary for sync-acks + if (hasAckPacketCommitment) { + revert IBCErrors.ackPacketCommitmentAlreadyExists(); + } + + _ackPacketCommitment[receiver][packet.dest.channelId][packet.sequence] = true; + + emit WriteAckPacket(receiver, packet.dest.channelId, packet.sequence, ack); + } + + /** + * Generate a timeout packet for the given packet + */ + function writeTimeoutPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external { + _lightClient.verifyMembership( + proof, Ibc.packetCommitmentProofKey(packet), abi.encode(Ibc.packetCommitmentProofValue(packet)) + ); + + address receiver = _getAddressFromPort(packet.src.portId); + // verify packet does not have a receipt + bool hasReceipt = _recvPacketReceipt[receiver][packet.dest.channelId][packet.sequence]; + if (hasReceipt) { + revert IBCErrors.packetReceiptAlreadyExists(); + } + + // verify packet has timed out; zero-value in packet.timeout means no timeout set + if (!_isPacketTimeout(packet)) { + revert IBCErrors.packetNotTimedOut(); + } + + emit WriteTimeoutPacket( + receiver, packet.dest.channelId, packet.sequence, packet.timeoutHeight, packet.timeoutTimestamp + ); + } + + /** + * @notice Get the IBC channel with the specified port and channel ID + * @param portAddress EVM address of the IBC port + * @param channelId IBC channel ID from the port perspective + * @return channel A channel struct is always returned. If it doesn't exists, the channel struct is populated with + * default + * values per EVM. + */ + function getChannel(address portAddress, bytes32 channelId) external view returns (Channel memory channel) { + channel = _portChannelMap[portAddress][channelId]; + } + + // getOptimisticConsensusState + function getOptimisticConsensusState(uint256 height) + external + view + returns (uint256 appHash, uint256 fraudProofEndTime, bool ended) + { + return _lightClient.getState(height); + } + + // Prerequisite: must verify sender is authorized to send packet on the channel + function _sendPacket(address sender, bytes32 channelId, bytes memory packet, uint64 timeoutTimestamp) internal { + // current packet sequence + uint64 sequence = _nextSequenceSend[sender][channelId]; + if (sequence == 0) { + revert IBCErrors.invalidPacketSequence(); + } + + // packet commitment + _sendPacketCommitment[sender][channelId][sequence] = true; + // increment nextSendPacketSequence + _nextSequenceSend[sender][channelId] = sequence + 1; + + emit SendPacket(sender, channelId, packet, sequence, timeoutTimestamp); + } + + function _connectChannel( + IbcChannelReceiver portAddress, + ChannelEnd calldata local, + string[] calldata connectionHops, + ChannelOrder ordering, + bool feeEnabled, + ChannelEnd calldata counterparty + ) internal { + // Register port and channel mapping + // TODO: check duplicated channel registration? + // TODO: The call to `Channel` constructor MUST be move to `openIbcChannel` phase + // Then `connectIbcChannel` phase can use the `version` as part of `require` condition. + _portChannelMap[address(portAddress)][local.channelId] = Channel( + counterparty.version, // TODO: this should be self version instead of counterparty version + ordering, + feeEnabled, + connectionHops, + counterparty.portId, + counterparty.channelId + ); + + // initialize channel sequences + _nextSequenceSend[address(portAddress)][local.channelId] = 1; + _nextSequenceRecv[address(portAddress)][local.channelId] = 1; + _nextSequenceAck[address(portAddress)][local.channelId] = 1; + _channelIdToConnection[local.channelId] = connectionHops[0]; // Set channel to connection mapping for + // finding + } + + // Returns the result of the call if no revert, otherwise returns the error if thrown. + function _callIfContract(address receiver, bytes memory args) + internal + returns (bool success, bytes memory message) + { + if (!Address.isContract(receiver)) { + return (false, bytes("call to non-contract")); + } + // Only call if we are sure receiver is a contract + // Note: This tx won't revert if the low-level call fails, see + // https://docs.soliditylang.org/en/latest/cheatsheet.html#members-of-address + (success, message) = receiver.call(args); + } + + function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} + + // _isPacketTimeout returns true if the given packet has timed out acoording to host chain's block height and + // timestamp + function _isPacketTimeout(IbcPacket calldata packet) internal view returns (bool isTimeOut) { + return ( + isTimeOut = (packet.timeoutTimestamp != 0 && block.timestamp >= packet.timeoutTimestamp) + // TODO: check timeoutHeight.revision_number? + || (packet.timeoutHeight.revision_height != 0 && block.number >= packet.timeoutHeight.revision_height) + ); + } + + function _getAddressFromPort(string calldata port) internal view returns (address addr) { + addr = Ibc._hexStrToAddress(port[portPrefixLen:]); + } +} diff --git a/test/utils/Dispatcher.base.t.sol b/test/utils/Dispatcher.base.t.sol index 00f162c2..788b06c9 100644 --- a/test/utils/Dispatcher.base.t.sol +++ b/test/utils/Dispatcher.base.t.sol @@ -13,6 +13,7 @@ import "../../contracts/core/OptimisticLightClient.sol"; import "../../contracts/utils/DummyLightClient.sol"; import "../../contracts/core/OptimisticProofVerifier.sol"; import {TestUtilsTest} from "./TestUtils.t.sol"; +import {stdStorage, StdStorage} from "forge-std/Test.sol"; struct LocalEnd { IbcChannelReceiver receiver; @@ -33,6 +34,8 @@ struct ChannelHandshakeSetting { // Base contract for testing Dispatcher contract Base is IbcEventsEmitter, ProofBase, TestUtilsTest { + using stdStorage for StdStorage; + uint32 CONNECTION_TO_CLIENT_ID_STARTING_SLOT = 161; uint32 SEND_PACKET_COMMITMENT_STARTING_SLOT = 156; uint64 UINT64_MAX = 18_446_744_073_709_551_615; @@ -188,6 +191,11 @@ contract Base is IbcEventsEmitter, ProofBase, TestUtilsTest { : abi.encodePacked('{"error":"', ack.data, '"}'); } + // genAckPacket generates an ack packet for the given packet sequence + function genAckPacket(string memory packetSeq) internal pure returns (bytes memory) { + return ackToBytes(AckPacket(true, bytes(packetSeq))); + } + // Store connection in channelid to connection mapping using store function _storeChannelidToConnectionMapping(bytes32 channelId, bytes32 connection) internal { bytes32 chanIdToConnectionMapping = keccak256(abi.encode(channelId, uint32(160))); @@ -211,4 +219,19 @@ contract Base is IbcEventsEmitter, ProofBase, TestUtilsTest { bytes32 clientIdSlot = keccak256(abi.encode(connection, CONNECTION_TO_CLIENT_ID_STARTING_SLOT)); clientId = uint256(vm.load(address(dispatcherProxy), clientIdSlot)); } + + function load_proof(string memory filepath) internal returns (Ics23Proof memory) { + (bytes32 apphash, Ics23Proof memory proof) = + abi.decode(vm.parseBytes(vm.readFile(string.concat(rootDir, filepath))), (bytes32, Ics23Proof)); + + // this loads the app hash we got from the testing data into the consensus state manager internals + // at the height it's supposed to go. That is, a block less than where the proof was generated from. + stdstore.target(address(opLightClient)).sig("consensusStates(uint256)").with_key(proof.height - 1).checked_write( + apphash + ); + // trick the fraud time window check + vm.warp(block.timestamp + 1); + + return proof; + } }