From 4f280a22234e2b1bc500bcb078c318ba923b4ef2 Mon Sep 17 00:00:00 2001 From: RnkSngh Date: Mon, 24 Jun 2024 15:30:39 -0400 Subject: [PATCH 1/2] return sequence in dispatcher sendPacket --- contracts/core/Dispatcher.sol | 10 +- contracts/interfaces/IDispatcher.sol | 4 +- contracts/interfaces/IbcDispatcher.sol | 4 +- .../DispatcherRC4.upgrade.t.sol | 189 +- test/upgradeableProxy/upgrades/EarthRc4.sol | 4562 +++++++++++++++++ test/upgradeableProxy/upgrades/MarsRc4.sol | 4485 ++++++++++++++++ 6 files changed, 9184 insertions(+), 70 deletions(-) create mode 100644 test/upgradeableProxy/upgrades/EarthRc4.sol create mode 100644 test/upgradeableProxy/upgrades/MarsRc4.sol diff --git a/contracts/core/Dispatcher.sol b/contracts/core/Dispatcher.sol index 2076e454..cba4b7a0 100644 --- a/contracts/core/Dispatcher.sol +++ b/contracts/core/Dispatcher.sol @@ -473,8 +473,14 @@ contract Dispatcher is OwnableUpgradeable, UUPSUpgradeable, ReentrancyGuard, IDi * @param packet The packet data to send. * @param timeoutTimestamp The timestamp, in seconds after the unix epoch, after which the packet times out if it * has not been received. + * @return sequence The sequence number of the packet, starting from 1 and incremented with each sendPacket. This + * sequence number is used to link with depositing packet fees in the fee vault */ - function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) external nonReentrant { + function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) + external + nonReentrant + returns (uint64 sequence) + { // ensure port owns channel if (_portChannelMap[msg.sender][channelId].counterpartyChannelId == bytes32(0)) { revert IBCErrors.channelNotOwnedBySender(); @@ -484,7 +490,7 @@ contract Dispatcher is OwnableUpgradeable, UUPSUpgradeable, ReentrancyGuard, IDi } // current packet sequence - uint64 sequence = _nextSequenceSend[msg.sender][channelId]; + sequence = _nextSequenceSend[msg.sender][channelId]; if (sequence == 0) { revert IBCErrors.invalidPacketSequence(); } diff --git a/contracts/interfaces/IDispatcher.sol b/contracts/interfaces/IDispatcher.sol index 3343e57e..4f6d064d 100644 --- a/contracts/interfaces/IDispatcher.sol +++ b/contracts/interfaces/IDispatcher.sol @@ -94,7 +94,9 @@ interface IDispatcher is IbcDispatcher, IbcEventsEmitter { function channelCloseConfirm(address portAddress, bytes32 channelId, Ics23Proof calldata proof) external; function channelCloseInit(bytes32 channelId) external; - function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) external; + function sendPacket(bytes32 channelId, bytes calldata packet, uint64 timeoutTimestamp) + external + returns (uint64 sequence); function acknowledgement(IbcPacket calldata packet, bytes calldata ack, Ics23Proof calldata proof) external; diff --git a/contracts/interfaces/IbcDispatcher.sol b/contracts/interfaces/IbcDispatcher.sol index 1a4407f9..798019ed 100644 --- a/contracts/interfaces/IbcDispatcher.sol +++ b/contracts/interfaces/IbcDispatcher.sol @@ -26,7 +26,9 @@ import {Ics23Proof} from "./IProofVerifier.sol"; * @dev IBC packet sender interface. */ interface IbcPacketSender { - function sendPacket(bytes32 channelId, bytes calldata payload, uint64 timeoutTimestamp) external; + function sendPacket(bytes32 channelId, bytes calldata payload, uint64 timeoutTimestamp) + external + returns (uint64 sequence); } /** diff --git a/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol b/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol index 4dcc3592..91af2580 100644 --- a/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol +++ b/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol @@ -5,23 +5,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 {Earth} from "../../contracts/examples/Earth.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, - UniversalPacket + ChannelEnd, ChannelOrder, ChannelState, IbcEndpoint, IbcPacket, 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"; @@ -35,50 +25,80 @@ import {IDispatcherRc4, DispatcherRc4} from "./upgrades/DispatcherRc4.sol"; import {IUniversalChannelHandler} from "../../contracts/interfaces/IUniversalChannelHandler.sol"; import {VirtualChain} from "../VirtualChain.sol"; import {GeneralMiddleware} from "../../contracts/base/GeneralMiddleware.sol"; +import {Mars as MarsRc4, IbcDispatcher as IbcDispatcherRc4} from "./upgrades/MarsRc4.sol"; +import { + Earth as EarthRc4, + UniversalPacket as UniversalPacketRc4, + AckPacket as AckPacketRc4, + IbcUtils +} from "./upgrades/EarthRc4.sol"; + +abstract contract DispatcherRC4TestUtils is ChannelHandShakeUpgradeUtil { + function sendOnePacketRc4(bytes32 channelId, uint64 packetSeq, MarsRc4 sender) public { + vm.expectEmit(true, true, true, true); + emit SendPacket(address(sender), channelId, abi.encodePacked("msgPayload"), packetSeq, timeoutTimestamp); + sender.greet(payload, channelId, timeoutTimestamp); + } + + function sendPacketRc4(bytes32 channelId, MarsRc4 mars) public { + for (uint64 index = 0; index < 3; index++) { + uint64 packetSeq = index + 1; + sendOnePacketRc4(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); + packets[index] = IbcPacket(src, dest, packetSeq, bytes(payload), ZERO_HEIGHT, maxTimeout); + } + } +} // 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; +contract DispatcherRC4UpgradeTest is DispatcherRC4TestUtils, UpgradeTestUtils { + MarsRc4 sendingMars; + MarsRc4 receivingMars; + MarsRc4 dummyMars; + IbcDispatcherRc4 oldDummyDispatcherProxy; + IbcDispatcherRc4 oldDispatcherInterface; IUniversalChannelHandler uch; LocalEnd _localUch; - Earth earth; + EarthRc4 earth; 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); + oldDummyDispatcherProxy = IbcDispatcherRc4(address(deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient))); // we have to manually cast here because solidity is confused by having interfaces coming from seperate files // 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); + oldDispatcherInterface = IbcDispatcherRc4(address(deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient2))); + dispatcherProxy = IDispatcher(address(oldDispatcherInterface)); uch = deployUCHV2ProxyAndImpl(address(dispatcherProxy)); - earth = new Earth(address(uch)); + earth = new EarthRc4(address(uch)); // Set up dispatcher with non-trivial state - mars = new Mars(dispatcherProxy); - receivingMars = new Mars(dispatcherProxy); - string memory sendingPortId = IbcUtils.addressToPortId(portPrefix, address(mars)); + sendingMars = new MarsRc4(oldDispatcherInterface); + receivingMars = new MarsRc4(oldDispatcherInterface); + string memory sendingPortId = IbcUtils.addressToPortId(portPrefix, address(sendingMars)); string memory uchSendingPortId = IbcUtils.addressToPortId(portPrefix, address(uch)); string memory receivingPortId = IbcUtils.addressToPortId(portPrefix, address(receivingMars)); - _local = LocalEnd(mars, sendingPortId, "channel-1", connectionHops1, "1.0", "1.0"); + _local = LocalEnd(IbcReceiver(address(sendingMars)), sendingPortId, "channel-1", connectionHops1, "1.0", "1.0"); _localUch = LocalEnd(uch, uchSendingPortId, "uch-channel", 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"); + _localDummy = + LocalEnd(IbcReceiver(address(sendingMars)), 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); + sendPacketRc4(_local.channelId, sendingMars); // Do channel handshake via uch doProofChannelHandshake(_localUch, _remote); - earth.greet(address(mars), _localUch.channelId, bytes("hello mars"), UINT64_MAX); + earth.greet(address(sendingMars), _localUch.channelId, bytes("hello sendingMars"), UINT64_MAX); // Upgrade dispatcherProxy and uch for tests upgradeDispatcher(portPrefix, address(dispatcherProxy)); @@ -90,27 +110,39 @@ contract DispatcherRC4UpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUti 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))) + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(sendingMars), _local.channelId))) ); assertEq(4, nextSequenceSendValue); // Validate packets from previous send - 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); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(sendingMars), _local.channelId, 1)) + > 0 + ); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(sendingMars), _local.channelId, 2)) + > 0 + ); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(sendingMars), _local.channelId, 3)) + > 0 + ); assert( vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(uch), _localUch.channelId, 1)) > 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); + sendOnePacketRc4(_local.channelId, 4, sendingMars); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(sendingMars), _local.channelId, 4)) + > 0 + ); uint64 nextSequenceSendAfterSending = uint64( - uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _local.channelId))) + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(sendingMars), _local.channelId))) ); assertEq(5, nextSequenceSendAfterSending); - earth.greet(address(receivingMars), _localUch.channelId, bytes("hello from upgrade mars!"), UINT64_MAX); + earth.greet(address(receivingMars), _localUch.channelId, bytes("hello from upgrade sendingMars!"), UINT64_MAX); assert( vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(uch), _localUch.channelId, 2)) > 0 ); @@ -122,35 +154,43 @@ contract DispatcherRC4UpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUti 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)))); + uint64 nextSequenceRecvValue = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceRecv(address(sendingMars), _local.channelId))) + ); + uint64 nextSequenceAckValue = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceAck(address(sendingMars), _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); + sendOnePacketRc4(_localDummy.channelId, 1, sendingMars); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(sendingMars), _local.channelId, 1)) + > 0 + ); uint64 nextSequenceSendAfterSendingDummy = uint64( - uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _localDummy.channelId))) + uint256( + vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(sendingMars), _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); + MarsRc4 mars2 = new MarsRc4(oldDispatcherInterface); string memory portId2 = IbcUtils.addressToPortId(portPrefix, address(mars2)); - LocalEnd memory _local2 = LocalEnd(mars2, portId2, "channel-1", connectionHops1, "1.0", "1.0"); + LocalEnd memory _local2 = + LocalEnd(IbcReceiver(address(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); + sendOnePacketRc4(_local2.channelId, 1, mars2); assert( vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars2), _local2.channelId, 1)) > 0 ); @@ -162,8 +202,10 @@ contract DispatcherRC4UpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUti } // Contract to test that state upgrades within mappings are preserved . -contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils { - Mars receivingMars; +contract DispatcherRC4MidwayUpgradeTest is DispatcherRC4TestUtils, UpgradeTestUtils { + IbcDispatcherRc4 oldDispatcherInterface; + MarsRc4 sendingMars; + MarsRc4 receivingMars; LocalEnd _re; ChannelEnd _le; string sendingPortId; @@ -171,30 +213,36 @@ contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeT DummyLightClient dummyLightClient2; IUniversalChannelHandler uch; LocalEnd _localUch; - Earth earth; + EarthRc4 earth; + + event WriteAckPacket( + address indexed writerPortAddress, bytes32 indexed writerChannelId, uint64 sequence, AckPacketRc4 ackPacket + ); 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))); + oldDispatcherInterface = + IbcDispatcherRc4(address(new ERC1967Proxy(address(oldOpDispatcherImplementation), initData))); + dispatcherProxy = IDispatcher(address(oldDispatcherInterface)); dummyLightClient2 = new DummyLightClient(); - mars = new Mars(dispatcherProxy); + sendingMars = new MarsRc4(oldDispatcherInterface); uch = deployUCHV2ProxyAndImpl(address(dispatcherProxy)); - earth = new Earth(address(uch)); - receivingMars = new Mars(dispatcherProxy); + earth = new EarthRc4(address(uch)); + receivingMars = new MarsRc4(oldDispatcherInterface); - sendingPortId = IbcUtils.addressToPortId(portPrefix, address(mars)); + sendingPortId = IbcUtils.addressToPortId(portPrefix, address(sendingMars)); string memory uchSendingPortId = IbcUtils.addressToPortId(portPrefix, address(uch)); receivingPortId = IbcUtils.addressToPortId(portPrefix, address(receivingMars)); // LocalEnd version of _remote - _re = LocalEnd(receivingMars, receivingPortId, "channel-2", connectionHops1, "1.0", "1.0"); + _re = LocalEnd(IbcReceiver(address(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"); + _local = LocalEnd(IbcReceiver(address(sendingMars)), sendingPortId, "channel-1", connectionHops1, "1.0", "1.0"); _localUch = LocalEnd(uch, uchSendingPortId, "uch-channel", connectionHops1, "1.0", "1.0"); _remote = ChannelEnd(receivingPortId, "channel-2", "1.0"); @@ -205,7 +253,7 @@ contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeT // Do channel handshake via uch doProofChannelHandshake(_localUch, _remote); - earth.greet(address(mars), _localUch.channelId, bytes("hello mars"), UINT64_MAX); + earth.greet(address(sendingMars), _localUch.channelId, bytes("hello sendingMars"), UINT64_MAX); } // Test that channel handshake can be finished even if done during an upgrade @@ -225,16 +273,19 @@ contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeT channelOpenConfirm(_re, _le, setting, true); // Send packet before upgrade - sendOnePacket(_local.channelId, 1, mars); + sendOnePacketRc4(_local.channelId, 1, sendingMars); // Ensure packet is sent correctly - assert(vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(mars), _local.channelId, 1)) > 0); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(sendingMars), _local.channelId, 1)) + > 0 + ); // Do upgrade before finishing packet handshake upgradeDispatcher(portPrefix, address(dispatcherProxy)); upgradeUch(address(uch)); dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient2); - earth.authorizeChannel(_localUch.channelId); + // earth.authorizeChannel(_localUch.channelId); // Now recv and ack packet IbcEndpoint memory src = IbcEndpoint(sendingPortId, _local.channelId); @@ -248,13 +299,17 @@ contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeT 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); + assert( + vm.load(address(dispatcherProxy), findSendPacketCommitmentSlot(address(sendingMars), _local.channelId, 1)) + == 0 + ); - uint64 nextSequenceAckValue = - uint64(uint256(vm.load(address(dispatcherProxy), findNextSequenceAck(address(mars), _local.channelId)))); + uint64 nextSequenceAckValue = uint64( + uint256(vm.load(address(dispatcherProxy), findNextSequenceAck(address(sendingMars), _local.channelId))) + ); uint64 nextSequenceSendValue = uint64( - uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(mars), _local.channelId))) + uint256(vm.load(address(dispatcherProxy), findNextSequenceSendSlot(address(sendingMars), _local.channelId))) ); assertEq(2, nextSequenceAckValue); @@ -262,8 +317,9 @@ contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeT // Now recv uch packet bytes memory appData = abi.encodePacked("hello using mw stack"); - UniversalPacket memory ucPacket = - UniversalPacket(IbcUtils.toBytes32(address(mars)), uch.MW_ID(), IbcUtils.toBytes32(address(earth)), appData); + UniversalPacketRc4 memory ucPacket = UniversalPacketRc4( + IbcUtils.toBytes32(address(sendingMars)), uch.MW_ID(), IbcUtils.toBytes32(address(earth)), appData + ); bytes memory packetData = IbcUtils.toUniversalPacketBytes(ucPacket); IbcPacket memory uchPacket = IbcPacket( IbcEndpoint(sendingPortId, _local.channelId), @@ -274,12 +330,13 @@ contract DispatcherRC4MidwayUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeT maxTimeout ); - AckPacket memory earthAck = earth.generateAckPacket(0x0, address(mars), appData); + AckPacketRc4 memory earthAck = earth.generateAckPacket(0x0, address(sendingMars), appData); + vm.expectEmit(true, true, true, true); emit WriteAckPacket(address(uch), _localUch.channelId, 1, earthAck); dispatcherProxy.recvPacket(uchPacket, validProof); - (bytes32 actualChannelId, UniversalPacket memory storedUcPacket) = earth.recvedPackets(0); + (bytes32 actualChannelId, UniversalPacketRc4 memory storedUcPacket) = earth.recvedPackets(0); assertEq(actualChannelId, _localUch.channelId); assertEq(storedUcPacket.appData, ucPacket.appData); } diff --git a/test/upgradeableProxy/upgrades/EarthRc4.sol b/test/upgradeableProxy/upgrades/EarthRc4.sol new file mode 100644 index 00000000..33e6a01c --- /dev/null +++ b/test/upgradeableProxy/upgrades/EarthRc4.sol @@ -0,0 +1,4562 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.0 ^0.8.0 ^0.8.15 ^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 - +/// @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/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/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/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; + } +} + +// 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/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/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 + +// 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/IbcMiddleware.sol + +/** + * @title IbcUniversalPacketSender + * @dev IbcUniversalPacketSender is called by end-users of IBC middleware contracts to send a packet over a MW stack. + */ +interface IbcUniversalPacketSender { + function sendUniversalPacket( + bytes32 channelId, + bytes32 destPortAddr, + bytes calldata appData, + uint64 timeoutTimestamp + ) external; +} + +interface IbcMwPacketSender { + // sendMWPacket must be called by another authorized IBC middleware contract. + // NEVER by a dApp contract. + // The middleware contract may choose to send the packet by calling IbcCoreSC or another IBC MW. + function sendMWPacket( + bytes32 channelId, + // original source address of the packet + bytes32 srcPortAddr, + bytes32 destPortAddr, + // source middleware ids bit AND + uint256 srcMwIds, + bytes calldata appData, + uint64 timeoutTimestamp + ) external; +} + +// IBC middleware contracts must implement this interface to relay universal channel packets to other IBC middleware +// contracts. +// If the MW contract also receives ucPacket as the final destination, it must also implement +// IbcUniversalPacketReceiver. +interface IbcMwPacketReceiver { + function onRecvMWPacket( + bytes32 channelId, + UniversalPacket calldata ucPacket, + // 0-based receiver middleware index in the MW stack. + // 0 for the first MW directly called by UniversalChannel MW. + // `mwIndex-1` is the last MW that delivers the packet to the non-MW dApp. + // Each mw in the stack must increment mwIndex by 1 before calling the next MW. + uint256 mwIndex, + address[] calldata mwAddrs + ) external returns (AckPacket memory ackPacket); + + function onRecvMWAck( + bytes32 channelId, + UniversalPacket calldata ucPacket, + // 0-based receiver middleware index in the MW stack. + // 0 for the first MW directly called by UniversalChannel MW. + // `mwIndex-1` is the last MW that delivers the packet to the non-MW dApp. + // Each mw in the stack must increment mwIndex by 1 before calling the next MW. + uint256 mwIndex, + address[] calldata mwAddrs, + AckPacket calldata ack + ) external; + + function onRecvMWTimeout( + bytes32 channelId, + UniversalPacket calldata ucPacket, + uint256 mwIndex, + address[] calldata mwAddrs + ) external; +} + +// dApps and IBC middleware contracts need to implement this interface to receive universal channel packets as packets' +// final destination. +interface IbcUniversalPacketReceiver { + function onRecvUniversalPacket(bytes32 channelId, UniversalPacket calldata ucPacket) + external + returns (AckPacket memory ackPacket); + + function onUniversalAcknowledgement(bytes32 channelId, UniversalPacket memory packet, AckPacket calldata ack) + external; + + function onTimeoutUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external; +} + +interface IbcMiddlwareProvider is IbcUniversalPacketSender, IbcMwPacketSender { + /** + * @dev MW_ID is the ID of MW contract on all supported virtual chains. + * MW_ID must: + * - be globally unique, ie. no two MWs should have the same MW_ID registered on Polymer chain. + * - be identical on all supported virtual chains. + * - be identical on one virtual chain across multiple deployed MW instances. Each MW instance belong exclusively to + * one MW stack. + * - be 1 << N, where N is a non-negative integer [0,255], and not in conflict with other MWs. + */ + function MW_ID() external view returns (uint256 MWID); +} + +/** + * @title IbcMiddleware + * @notice IBC middleware interface must be implemented by a IBC-middleware contract, similar to ICS-30 + * https://github.com/cosmos/ibc/tree/main/spec/app/ics-030-middleware. + * Current limitations: + * - IbcMiddleware must sit on top of a UniversalChannel MW or another IbcMiddleware. + * - IbcMiddleware cannnot own an IBC channel. Instead, UniversalChannel MW owns channels. + */ +interface IbcMiddleware is IbcMiddlwareProvider, IbcMwPacketReceiver, IbcUniversalPacketReceiver {} + +/** + * @title IbcUniversalChannelMW + * @notice This interface must be implemented by IBC universal channel middleware contracts. + * IbcUniversalChannelMW is a special type of IbcMiddleware that owns IBC channels, which are multiplexed for other + * IbcMiddleware. + * IbcUniversalChannelMW cannot sit on top of other MW, and must talk to IbcDispatcher directly. + */ +interface IbcUniversalChannelMW is IbcMiddlwareProvider, IbcPacketReceiver, IbcChannelReceiver { + error MwBitmpaCannotBeZero(); +} + +/** + * @title IbcMwEventsEmitter + * @notice IBC middleware events interface. + * @dev IBC middleware contracts should emit events specific to their own middleware, + * and can choose to emit events not defined in this interface if needed. + */ +interface IbcMwEventsEmitter { + event SendMWPacket( + bytes32 indexed channelId, + bytes32 indexed srcPortAddr, + bytes32 indexed destPortAddr, + // middleware UID + uint256 mwId, + bytes appData, + uint64 timeoutTimestamp, + bytes mwData + ); + event RecvMWPacket( + bytes32 indexed channelId, + bytes32 indexed srcPortAddr, + bytes32 indexed destPortAddr, + // middleware UID + uint256 mwId, + bytes appData, + bytes mwData + ); + event RecvMWAck( + bytes32 indexed channelId, + bytes32 indexed srcPortAddr, + bytes32 indexed destPortAddr, + // middleware UID + uint256 mwId, + bytes appData, + bytes mwData, + AckPacket ack + ); + event RecvMWTimeout( + bytes32 indexed channelId, + bytes32 indexed srcPortAddr, + bytes32 indexed destPortAddr, + // middleware UID + uint256 mwId, + bytes appData, + bytes mwData + ); +} + +/** + * @title IbcMwUser + * @dev Contracts that send and recv universal packets via IBC MW should inherit IbcMwUser or implement similiar + * functions. + * @notice IbcMwUser ensures only authorized IBC middleware can call IBC callback functions. + */ +contract IbcMwUser is Ownable { + // default middleware + address public mw; + mapping(address => bool) public authorizedMws; + + error UnauthorizedIbcMiddleware(); + error ackDataTooShort(); + error ackAddressMismatch(); + + /** + * @dev Modifier to restrict access to only the IBC middleware. + * Only the address with the IBC_ROLE can execute the function. + * Should add this modifier to all IBC-related callback functions. + */ + modifier onlyIbcMw() { + if (!authorizedMws[msg.sender]) { + revert UnauthorizedIbcMiddleware(); + } + _; + } + + /** + * @dev Constructor function that takes an IbcMiddleware address and grants the IBC_ROLE to the Polymer IBC + * Dispatcher. + * @param _middleware The address of the IbcMiddleware contract. + */ + constructor(address _middleware) Ownable() { + mw = _middleware; + _authorizeMiddleware(_middleware); + } + + /// 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 {} + + /** + * @dev Set the default IBC middleware contract in the MW stack. + * When sending packets, the default middleware is the next middleware in the MW stack. + * When receiving packets, the default middleware is the previous middleware in the MW stack. + * @param _middleware The address of the IbcMiddleware contract. + * @notice The default middleware is authorized automatically. + */ + function setDefaultMw(address _middleware) external onlyOwner { + _authorizeMiddleware(_middleware); + mw = _middleware; + } + + /** + * @dev register an authorized middleware so that modifier onlyIbcMw can be used to restrict access to only + * authorized middleware. + * Only the address with the IBC_ROLE can execute the function. + * @notice Should add this modifier to all IBC-related callback functions. + */ + function authorizeMiddleware(address middleware) external onlyOwner { + _authorizeMiddleware(middleware); + } + + function _authorizeMiddleware(address middleware) internal { + authorizedMws[address(middleware)] = true; + } +} + +// contracts/examples/Earth.sol + +contract Earth is IbcMwUser, IbcUniversalPacketReceiver { + struct UcPacketWithChannel { + bytes32 channelId; + UniversalPacket packet; + } + + struct UcAckWithChannel { + bytes32 channelId; + UniversalPacket packet; + AckPacket ack; + } + + // received packet as chain B + UcPacketWithChannel[] public recvedPackets; + // received ack packet as chain A + UcAckWithChannel[] public ackPackets; + // received timeout packet as chain A + UcPacketWithChannel[] public timeoutPackets; + + constructor(address _middleware) IbcMwUser(_middleware) {} + + function greet(address destPortAddr, bytes32 channelId, bytes calldata message, uint64 timeoutTimestamp) external { + IbcUniversalPacketSender(mw).sendUniversalPacket( + channelId, IbcUtils.toBytes32(destPortAddr), message, timeoutTimestamp + ); + } + + function onRecvUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) + external + onlyIbcMw + returns (AckPacket memory ackPacket) + { + recvedPackets.push(UcPacketWithChannel(channelId, packet)); + return this.generateAckPacket(channelId, IbcUtils.toAddress(packet.srcPortAddr), packet.appData); + } + + function onUniversalAcknowledgement(bytes32 channelId, UniversalPacket memory packet, AckPacket calldata ack) + external + onlyIbcMw + { + // verify packet's destPortAddr is the ack's first encoded address. See generateAckPacket()) + if (ack.data.length < 20) revert ackDataTooShort(); + address ackSender = address(bytes20(ack.data[0:20])); + if (IbcUtils.toAddress(packet.destPortAddr) != ackSender) revert ackAddressMismatch(); + ackPackets.push(UcAckWithChannel(channelId, packet, ack)); + } + + function onTimeoutUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external onlyIbcMw { + timeoutPackets.push(UcPacketWithChannel(channelId, packet)); + } + + // For testing only; real dApps should implment their own ack logic + function generateAckPacket(bytes32, address srcPortAddr, bytes calldata appData) + external + view + returns (AckPacket memory ackPacket) + { + return AckPacket(true, abi.encodePacked(this, srcPortAddr, "ack-", appData)); + } +} diff --git a/test/upgradeableProxy/upgrades/MarsRc4.sol b/test/upgradeableProxy/upgrades/MarsRc4.sol new file mode 100644 index 00000000..240883ad --- /dev/null +++ b/test/upgradeableProxy/upgrades/MarsRc4.sol @@ -0,0 +1,4485 @@ +//SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.0 ^0.8.0 ^0.8.15 ^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 - +/// @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/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/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/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; + } +} + +// 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/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/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 + +// 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/examples/Mars.sol + +contract Mars is IbcReceiverBase, IbcReceiver { + // received packet as chain B + IbcPacket[] public recvedPackets; + // received ack packet as chain A + AckPacket[] public ackPackets; + // received timeout packet as chain A + IbcPacket[] public timeoutPackets; + bytes32[] public connectedChannels; + + string[] public supportedVersions = ["1.0", "2.0"]; + + constructor(IbcDispatcher _dispatcher) IbcReceiverBase(_dispatcher) {} + + function triggerChannelInit( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external onlyOwner { + dispatcher.channelOpenInit(version, ordering, feeEnabled, connectionHops, counterpartyPortId); + } + + function onRecvPacket(IbcPacket memory packet) + external + virtual + onlyIbcDispatcher + returns (AckPacket memory ackPacket) + { + recvedPackets.push(packet); + + // solhint-disable-next-line quotes + return AckPacket(true, abi.encodePacked('{ "account": "account", "reply": "got the message" }')); + } + + function onAcknowledgementPacket(IbcPacket calldata, AckPacket calldata ack) external virtual onlyIbcDispatcher { + ackPackets.push(ack); + } + + function onTimeoutPacket(IbcPacket calldata packet) external virtual onlyIbcDispatcher { + timeoutPackets.push(packet); + } + + function onCloseIbcChannel(bytes32 channelId, string calldata, bytes32) external virtual onlyIbcDispatcher { + // logic to determin if the channel should be closed + bool channelFound = false; + for (uint256 i = 0; i < connectedChannels.length; i++) { + if (connectedChannels[i] == channelId) { + delete connectedChannels[i]; + channelFound = true; + break; + } + } + if (!channelFound) revert ChannelNotFound(); + } + + /** + * This func triggers channel closure from the dApp. + * Func args can be arbitary, as long as dispatcher.closeIbcChannel is invoked propperly. + */ + function triggerChannelClose(bytes32 channelId) external onlyOwner { + dispatcher.closeIbcChannel(channelId); + } + + /** + * @dev Sends a packet with a greeting message over a specified channel. + * @param message The greeting message to be sent. + * @param channelId The ID of the channel to send the packet to. + * @param timeoutTimestamp The timestamp at which the packet will expire if not received. + */ + function greet(string calldata message, bytes32 channelId, uint64 timeoutTimestamp) external { + dispatcher.sendPacket(channelId, bytes(message), timeoutTimestamp); + } + + function onChanOpenInit(ChannelOrder, string[] calldata, string calldata, string calldata version) + external + view + virtual + onlyIbcDispatcher + returns (string memory selectedVersion) + { + return _openChannel(version); + } + + // solhint-disable-next-line ordering + function onChanOpenTry( + ChannelOrder, + string[] memory, + bytes32 channelId, + string memory, + bytes32, + string calldata counterpartyVersion + ) external virtual onlyIbcDispatcher returns (string memory selectedVersion) { + return _connectChannel(channelId, counterpartyVersion); + } + + function onChanOpenAck(bytes32 channelId, bytes32, string calldata counterpartyVersion) + external + virtual + onlyIbcDispatcher + { + _connectChannel(channelId, counterpartyVersion); + } + + function onChanOpenConfirm(bytes32 channelId) external onlyIbcDispatcher {} + + function _connectChannel(bytes32 channelId, string calldata counterpartyVersion) + private + returns (string memory version) + { + // ensure negotiated version is supported + for (uint256 i = 0; i < supportedVersions.length; i++) { + if (keccak256(abi.encodePacked(counterpartyVersion)) == keccak256(abi.encodePacked(supportedVersions[i]))) { + connectedChannels.push(channelId); + return counterpartyVersion; + } + } + revert UnsupportedVersion(); + } + + function _openChannel(string calldata version) private view returns (string memory selectedVersion) { + for (uint256 i = 0; i < supportedVersions.length; i++) { + if (keccak256(abi.encodePacked(version)) == keccak256(abi.encodePacked(supportedVersions[i]))) { + return version; + } + } + revert UnsupportedVersion(); + } +} + +/* + * These contracts are the exact same as Mars, but they revert/panick in different ways. + * they are used to test that transport error is seperated from errors thrown in onRecvPacket + */ +contract RevertingStringMars is Mars { + constructor(IbcDispatcher _dispatcher) Mars(_dispatcher) {} + + // solhint-disable-next-line + function onChanOpenInit(ChannelOrder, string[] calldata, string calldata, string calldata) + external + view + virtual + override + onlyIbcDispatcher + returns (string memory selectedVersion) + { + // solhint-disable-next-line + require(false, "open ibc channel is reverting"); + return ""; + } + + // solhint-disable-next-line + function onRecvPacket(IbcPacket memory) external view override onlyIbcDispatcher returns (AckPacket memory ack) { + // solhint-disable-next-line + require(false, "on recv packet is reverting"); + ack = AckPacket(false, ""); + } + + // solhint-disable-next-line + function onChanOpenAck(bytes32, bytes32, string calldata) external view override onlyIbcDispatcher { + // solhint-disable-next-line + require(false, "connect ibc channel is reverting"); + } + + // solhint-disable-next-line + function onCloseIbcChannel(bytes32, string calldata, bytes32) external view override onlyIbcDispatcher { + // solhint-disable-next-line + require(false, "close ibc channel is reverting"); + } + + // solhint-disable-next-line + function onAcknowledgementPacket(IbcPacket calldata, AckPacket calldata) external view override onlyIbcDispatcher { + // solhint-disable-next-line + require(false, "acknowledgement packet is reverting"); + } +} + +contract RevertingBytesMars is Mars { + error OnRecvPacketRevert(); + error OnTimeoutPacket(); + + constructor(IbcDispatcher _dispatcher) Mars(_dispatcher) {} + + function onRecvPacket(IbcPacket memory) external view override onlyIbcDispatcher returns (AckPacket memory ack) { + ack = AckPacket(false, ""); + revert OnRecvPacketRevert(); + } + + function onTimeoutPacket(IbcPacket calldata) external view override onlyIbcDispatcher { + // solhint-disable-next-line + revert OnTimeoutPacket(); + } +} + +contract RevertingEmptyMars is Mars { + constructor(IbcDispatcher _dispatcher) Mars(_dispatcher) {} + + function onRecvPacket(IbcPacket memory) external view override onlyIbcDispatcher returns (AckPacket memory ack) { + // solhint-disable-next-line + require(false); + ack = AckPacket(false, ""); + } +} + +contract PanickingMars is Mars { + constructor(IbcDispatcher _dispatcher) Mars(_dispatcher) {} + + function onRecvPacket(IbcPacket memory) external view override onlyIbcDispatcher returns (AckPacket memory ack) { + assert(false); + ack = AckPacket(false, ""); + } +} From 55b7c8cc5521d08af000a355765baf9ccdb728df Mon Sep 17 00:00:00 2001 From: RnkSngh Date: Thu, 6 Jun 2024 10:13:00 -0700 Subject: [PATCH 2/2] add feeVault contract + tests --- contracts/base/GeneralMiddleware.sol | 21 +++-- contracts/core/Dispatcher.sol | 8 +- contracts/core/FeeVault.sol | 91 +++++++++++++++++++ contracts/core/UniversalChannelHandler.sol | 35 ++++++- contracts/examples/Earth.sol | 22 +++++ contracts/examples/Mars.sol | 44 ++++++++- .../implementation_templates/FeeSender.sol | 46 ++++++++++ .../IbcReceiverUpgradeable.sol | 3 +- contracts/interfaces/IDispatcher.sol | 2 + contracts/interfaces/IFeeVault.sol | 63 +++++++++++++ contracts/interfaces/IbcDispatcher.sol | 3 +- contracts/interfaces/IbcMiddleware.sol | 13 ++- test/Dispatcher.gasGriefing.t.sol | 2 +- test/Dispatcher/Dispatcher.client.t.sol | 2 +- test/Dispatcher/Dispatcher.closeChannel.t.sol | 18 ++++ .../Dispatcher.dappHandlerRevert.t.sol | 2 +- test/Dispatcher/Dispatcher.multiclient.sol | 2 +- test/Dispatcher/Dispatcher.proof.t.sol | 22 ++++- test/Dispatcher/Dispatcher.t.sol | 44 ++++++++- test/FeeVault.t.sol | 83 +++++++++++++++++ test/VirtualChain.sol | 9 +- test/universal.channel.t.sol | 28 +++++- .../upgradeableProxy/Dispatcher.upgrade.t.sol | 18 ++-- .../DispatcherRC4.upgrade.t.sol | 13 ++- .../DispatcherUUPS.accessControl.t.sol | 9 +- .../upgrades/DispatcherV2Initializable.sol | 4 +- test/utils/Dispatcher.base.t.sol | 62 +++++++++++++ test/utils/TestUtils.t.sol | 5 +- 28 files changed, 622 insertions(+), 52 deletions(-) create mode 100644 contracts/core/FeeVault.sol create mode 100644 contracts/implementation_templates/FeeSender.sol rename contracts/{interfaces => implementation_templates}/IbcReceiverUpgradeable.sol (96%) create mode 100644 contracts/interfaces/IFeeVault.sol create mode 100644 test/FeeVault.t.sol diff --git a/contracts/base/GeneralMiddleware.sol b/contracts/base/GeneralMiddleware.sol index a4b7850f..3d00a7c4 100644 --- a/contracts/base/GeneralMiddleware.sol +++ b/contracts/base/GeneralMiddleware.sol @@ -61,11 +61,20 @@ contract GeneralMiddleware is IbcMwUser, IbcMiddleware, IbcMwEventsEmitter, IbcM bytes32 destPortAddr, bytes calldata appData, uint64 timeoutTimestamp - ) external override { + ) external override returns (uint64 sequence) { emit UCHPacketSent(msg.sender, destPortAddr); - _sendPacket(channelId, IbcUtils.toBytes32(msg.sender), destPortAddr, 0, appData, timeoutTimestamp); + return _sendPacket(channelId, IbcUtils.toBytes32(msg.sender), destPortAddr, 0, appData, timeoutTimestamp); } + function sendUniversalPacketWithFee( + bytes32 channelId, + bytes32 destPortAddr, + bytes calldata appData, + uint64 timeoutTimestamp, + uint256[2] calldata gasLimits, + uint256[2] calldata gasPrices + ) external payable override returns (uint64 sequence) {} + function sendMWPacket( bytes32 channelId, bytes32 srcPortAddr, @@ -73,8 +82,8 @@ contract GeneralMiddleware is IbcMwUser, IbcMiddleware, IbcMwEventsEmitter, IbcM uint256 srcMwIds, bytes calldata appData, uint64 timeoutTimestamp - ) external override { - _sendPacket(channelId, srcPortAddr, destPortAddr, srcMwIds, appData, timeoutTimestamp); + ) external override returns (uint64 sequence) { + return _sendPacket(channelId, srcPortAddr, destPortAddr, srcMwIds, appData, timeoutTimestamp); } function onRecvMWPacket( @@ -191,7 +200,7 @@ contract GeneralMiddleware is IbcMwUser, IbcMiddleware, IbcMwEventsEmitter, IbcM uint256 srcMwIds, bytes calldata appData, uint64 timeoutTimestamp - ) internal virtual { + ) internal virtual returns (uint64 sequence) { // extra MW custom logic here to process packet, eg. emit MW events, mutate state, etc. // implementer can emit custom data fields suitable for their use cases. // Here we use MW_ID as the custom MW data field. @@ -200,7 +209,7 @@ contract GeneralMiddleware is IbcMwUser, IbcMiddleware, IbcMwEventsEmitter, IbcM ); // send packet to next MW - IbcMwPacketSender(mw).sendMWPacket( + return IbcMwPacketSender(mw).sendMWPacket( channelId, srcPortAddr, destPortAddr, srcMwIds | MW_ID, appData, timeoutTimestamp ); } diff --git a/contracts/core/Dispatcher.sol b/contracts/core/Dispatcher.sol index cba4b7a0..3a5d86f8 100644 --- a/contracts/core/Dispatcher.sol +++ b/contracts/core/Dispatcher.sol @@ -28,6 +28,7 @@ import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard. import {Channel, ChannelEnd, ChannelOrder, IbcPacket, ChannelState, AckPacket, Ibc} from "../libs/Ibc.sol"; import {IBCErrors} from "../libs/IbcErrors.sol"; import {IbcUtils} from "../libs/IbcUtils.sol"; +import {IFeeVault} from "../interfaces/IFeeVault.sol"; /** * @title Dispatcher @@ -64,6 +65,7 @@ contract Dispatcher is OwnableUpgradeable, UUPSUpgradeable, ReentrancyGuard, IDi ILightClient _UNUSED; // From previous dispatcher version mapping(bytes32 => string) private _channelIdToConnection; mapping(string => ILightClient) private _connectionToLightClient; + IFeeVault public feeVault; constructor() { _disableInitializers(); @@ -75,13 +77,17 @@ contract Dispatcher is OwnableUpgradeable, UUPSUpgradeable, ReentrancyGuard, IDi * @dev This method should be called only once during contract deployment. * @dev For contract upgarades, which need to reinitialize the contract, use the reinitializer modifier. */ - function initialize(string memory initPortPrefix) public virtual initializer nonReentrant { + function initialize(string memory initPortPrefix, IFeeVault _feeVault) public virtual initializer nonReentrant { if (bytes(initPortPrefix).length == 0) { revert IBCErrors.invalidPortPrefix(); } + if (address(_feeVault) == address(0)) { + revert IBCErrors.invalidAddress(); + } __Ownable_init(); portPrefix = initPortPrefix; portPrefixLen = uint32(bytes(initPortPrefix).length); + feeVault = _feeVault; } /** diff --git a/contracts/core/FeeVault.sol b/contracts/core/FeeVault.sol new file mode 100644 index 00000000..c56d01a2 --- /dev/null +++ b/contracts/core/FeeVault.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2024, Polymer Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pragma solidity 0.8.15; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IFeeVault} from "../interfaces/IFeeVault.sol"; +import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; +import {ChannelOrder} from "../libs/Ibc.sol"; + +contract FeeVault is Ownable, ReentrancyGuard, IFeeVault { + /** + * @notice Deposits the send packet fee for a given channel and sequence that is used for relaying recieve and + * acknowledge steps of a packet handhsake after a dapp has called the sendPacket on dispatcher. + * @dev This function calculates the required fee based on provided gas limits and gas prices, + * and reverts if the sent value does not match the calculated fee. + * The first entry in `gasLimits` and `gasPrices` arrays corresponds to `recvPacket` fees, + * and the second entry corresponds to `ackPacket` fees. + * @param channelId The identifier of the channel. + * @param sequence The sequence number for the packet, returned from the dispatcher sendPacket call. + * @param gasLimits An array containing two gas limit values: + * - gasLimits[0] for `recvPacket` fees + * - gasLimits[1] for `ackPacket` fees. + * @param gasPrices An array containing two gas price values: + * - gasPrices[0] for `recvPacket` fees, for the dest chain + * - gasPrices[1] for `ackPacket` fees, for the src chain + */ + function depositSendPacketFee( + bytes32 channelId, + uint64 sequence, + uint256[2] calldata gasLimits, + uint256[2] calldata gasPrices + ) external payable nonReentrant { + uint256 fee = gasLimits[0] * gasPrices[0] + gasLimits[1] * gasPrices[1]; + if ((fee) != msg.value) { + revert IncorrectFeeSent(fee, msg.value); + } + emit SendPacketFeeDeposited(channelId, sequence, gasLimits, gasPrices); + } + + /** + * @notice Deposits the fee for a channel handshake, to pay a relayer for relaying the channelOpenTry, + * channelOpenConfirm, and channelOpenAck steps after a dapp has called channelOpenInit + * @dev The fee amount that needs to be sent for Polymer to relay the whole channel handshake can be queried on the + * web2 layer. + * @param src The address of the sender, should be the address in the localportId. + * @param version The version string of the channel, the same argument as that sent in the + * dispatcher.channelOpenInit call + * @param ordering The ordering of the channel, the same argument as that sent in the dispatcher.channelOpenInit + * call + * @param connectionHops An array of connection hops, the same argument as that sent in the + * dispatcher.channelOpenInit call + * @param counterpartyPortId The counterparty port identifier, the same argument as that sent in the + * dispatcher.channelOpenInit call + */ + function depositOpenChannelFee( + address src, + string memory version, + ChannelOrder ordering, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external payable nonReentrant { + if (msg.value == 0) { + revert NoFeeSent(); + } + emit OpenChannelFeeDeposited(src, version, ordering, connectionHops, counterpartyPortId, msg.value); + } + + /** + * @notice Withdraws all collected fees to the contract owner's address. + * @dev Transfers the entire balance of this contract to the owner. + * @dev Anyone can call this, but it will always only be sent to the owner. + */ + function withdrawFeesToOwner() external { + payable(owner()).transfer(address(this).balance); + } +} diff --git a/contracts/core/UniversalChannelHandler.sol b/contracts/core/UniversalChannelHandler.sol index e14736df..7de73e99 100644 --- a/contracts/core/UniversalChannelHandler.sol +++ b/contracts/core/UniversalChannelHandler.sol @@ -19,10 +19,11 @@ pragma solidity 0.8.15; import {IbcDispatcher} from "../interfaces/IbcDispatcher.sol"; import {IbcUniversalChannelMW, IbcUniversalPacketReceiver} from "../interfaces/IbcMiddleware.sol"; -import {IbcReceiverBaseUpgradeable} from "../interfaces/IbcReceiverUpgradeable.sol"; +import {IbcReceiverBaseUpgradeable} from "../implementation_templates/IbcReceiverUpgradeable.sol"; import {ChannelOrder, IbcPacket, AckPacket, UniversalPacket} from "../libs/Ibc.sol"; import {IbcUtils} from "../libs/IbcUtils.sol"; import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; +import {FeeSender} from "../implementation_templates/FeeSender.sol"; /** * @title Universal Channel Handler @@ -31,7 +32,7 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeab * channel handshake to establish a channel. * @dev This contract can integrate directly with dapps, or a middleware stack for packet routing. */ -contract UniversalChannelHandler is IbcReceiverBaseUpgradeable, UUPSUpgradeable, IbcUniversalChannelMW { +contract UniversalChannelHandler is IbcReceiverBaseUpgradeable, FeeSender, UUPSUpgradeable, IbcUniversalChannelMW { bytes32 private _UNUSED; // Storage placeholder to ensure upgrade from this version is backwards compatible string public constant VERSION = "1.0"; @@ -82,12 +83,38 @@ contract UniversalChannelHandler is IbcReceiverBaseUpgradeable, UUPSUpgradeable, bytes32 destPortAddr, bytes calldata appData, uint64 timeoutTimestamp - ) external { + ) external returns (uint64 sequence) { bytes memory packetData = IbcUtils.toUniversalPacketBytes( UniversalPacket(IbcUtils.toBytes32(msg.sender), MW_ID, destPortAddr, appData) ); emit UCHPacketSent(msg.sender, destPortAddr); - dispatcher.sendPacket(channelId, packetData, timeoutTimestamp); + sequence = dispatcher.sendPacket(channelId, packetData, timeoutTimestamp); + } + + /** + * @notice Sends a universal packet over an IBC channel + * @param channelId The channel ID through which the packet is sent on the dispatcher + * @param destPortAddr The destination port address + * @param appData The packet data to be sent + * @param timeoutTimestamp of when the packet can timeout + */ + function sendUniversalPacketWithFee( + bytes32 channelId, + bytes32 destPortAddr, + bytes calldata appData, + uint64 timeoutTimestamp, + uint256[2] calldata gasLimits, + uint256[2] calldata gasPrices + ) external payable returns (uint64 sequence) { + // Cache dispatcher for gas savings + IbcDispatcher _dispatcher = dispatcher; + + bytes memory packetData = IbcUtils.toUniversalPacketBytes( + UniversalPacket(IbcUtils.toBytes32(msg.sender), MW_ID, destPortAddr, appData) + ); + emit UCHPacketSent(msg.sender, destPortAddr); + sequence = _dispatcher.sendPacket(channelId, packetData, timeoutTimestamp); + _depositSendPacketFee(dispatcher, channelId, sequence, gasLimits, gasPrices); } /** diff --git a/contracts/examples/Earth.sol b/contracts/examples/Earth.sol index 2e28abd2..be53099a 100644 --- a/contracts/examples/Earth.sol +++ b/contracts/examples/Earth.sol @@ -20,6 +20,7 @@ pragma solidity ^0.8.9; import {UniversalPacket, AckPacket} from "../libs/Ibc.sol"; import {IbcUtils} from "../libs/IbcUtils.sol"; import {IbcUniversalPacketReceiverBase, IbcUniversalPacketSender} from "../interfaces/IbcMiddleware.sol"; +import {IUniversalChannelHandler} from "../interfaces/IUniversalChannelHandler.sol"; /** * @title Earth @@ -48,12 +49,33 @@ contract Earth is IbcUniversalPacketReceiverBase { constructor(address _middleware) IbcUniversalPacketReceiverBase(_middleware) {} + /** + * @notice Send a packet to a destination chain. without a fee + * @notice this is useful for self-relaying apckets which don't rely on polymer to fund. + * @param destPortAddr The destination chain's port address. + * @param channelId The channel id to send the packet on. + * @param message The message to send. + * @param timeoutTimestamp The timeout timestamp for the packet. + */ function greet(address destPortAddr, bytes32 channelId, bytes calldata message, uint64 timeoutTimestamp) external { IbcUniversalPacketSender(mw).sendUniversalPacket( channelId, IbcUtils.toBytes32(destPortAddr), message, timeoutTimestamp ); } + function greetWithFee( + address destPortAddr, + bytes32 channelId, + bytes calldata message, + uint64 timeoutTimestamp, + uint256[2] memory gasLimits, + uint256[2] memory gasPrices + ) external payable returns (uint64 sequence) { + return IUniversalChannelHandler(mw).sendUniversalPacketWithFee{value: msg.value}( + channelId, IbcUtils.toBytes32(destPortAddr), message, timeoutTimestamp, gasLimits, gasPrices + ); + } + function onRecvUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external onlyIbcMw diff --git a/contracts/examples/Mars.sol b/contracts/examples/Mars.sol index 5a9f4047..fea2ef52 100644 --- a/contracts/examples/Mars.sol +++ b/contracts/examples/Mars.sol @@ -20,6 +20,7 @@ pragma solidity ^0.8.9; import {AckPacket, ChannelOrder} from "../libs/Ibc.sol"; import {IbcReceiverBase, IbcReceiver, IbcPacket} from "../interfaces/IbcReceiver.sol"; import {IbcDispatcher} from "../interfaces/IbcDispatcher.sol"; +import {FeeSender} from "../implementation_templates/FeeSender.sol"; /** * @title Mars @@ -27,7 +28,7 @@ import {IbcDispatcher} from "../interfaces/IbcDispatcher.sol"; * @dev This contract is used for only testing IBC functionality and as an example for dapp developers on how to * integrate with the vibc protocol. */ -contract Mars is IbcReceiverBase, IbcReceiver { +contract Mars is IbcReceiverBase, IbcReceiver, FeeSender { // received packet as chain B IbcPacket[] public recvedPackets; // received ack packet as chain A @@ -50,6 +51,18 @@ contract Mars is IbcReceiverBase, IbcReceiver { dispatcher.channelOpenInit(version, ordering, feeEnabled, connectionHops, counterpartyPortId); } + function triggerChannelInitWithFee( + string calldata version, + ChannelOrder ordering, + bool feeEnabled, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) external payable onlyOwner { + IbcDispatcher _dispatcher = dispatcher; // cache for gas savings to avoid 2 SLOADS + _dispatcher.channelOpenInit(version, ordering, feeEnabled, connectionHops, counterpartyPortId); + _depositOpenChannelFee(_dispatcher, version, ordering, connectionHops, counterpartyPortId); + } + function onRecvPacket(IbcPacket memory packet) external virtual @@ -92,13 +105,36 @@ contract Mars is IbcReceiverBase, IbcReceiver { } /** - * @dev Sends a packet with a greeting message over a specified channel. + * @dev Sends a packet with a greeting message over a specified channel, without depositing any sendPacket relaying + * fees. + * @notice Use greetWithFee for sending packets with fees. * @param message The greeting message to be sent. * @param channelId The ID of the channel to send the packet to. * @param timeoutTimestamp The timestamp at which the packet will expire if not received. + * @dev This method also returns sequence from the dispatcher for easy testing */ - function greet(string calldata message, bytes32 channelId, uint64 timeoutTimestamp) external { - dispatcher.sendPacket(channelId, bytes(message), timeoutTimestamp); + function greet(string calldata message, bytes32 channelId, uint64 timeoutTimestamp) + external + returns (uint64 sequence) + { + sequence = dispatcher.sendPacket(channelId, bytes(message), timeoutTimestamp); + } + + /** + * @dev Sends a packet with a greeting message over a specified channel, and deposits a fee for relaying the packet + * @param message The greeting message to be sent. + * @param channelId The ID of the channel to send the packet to. + * @param timeoutTimestamp The timestamp at which the packet will expire if not received. + */ + function greetWithFee( + string calldata message, + bytes32 channelId, + uint64 timeoutTimestamp, + uint256[2] calldata gasLimits, + uint256[2] calldata gasPrices + ) external payable returns (uint64 sequence) { + sequence = dispatcher.sendPacket(channelId, bytes(message), timeoutTimestamp); + _depositSendPacketFee(dispatcher, channelId, sequence, gasLimits, gasPrices); } function onChanOpenInit(ChannelOrder, string[] calldata, string calldata, string calldata version) diff --git a/contracts/implementation_templates/FeeSender.sol b/contracts/implementation_templates/FeeSender.sol new file mode 100644 index 00000000..06e28006 --- /dev/null +++ b/contracts/implementation_templates/FeeSender.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2024, Polymer Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pragma solidity 0.8.15; + +import {IbcDispatcher} from "../interfaces/IbcDispatcher.sol"; +import {ChannelOrder} from "../libs/Ibc.sol"; + +/// Contract with +abstract contract FeeSender { + function _depositSendPacketFee( + IbcDispatcher dispatcher, + bytes32 channelId, + uint64 sequence, + uint256[2] calldata gasLimits, + uint256[2] calldata gasPrices + ) internal { + dispatcher.feeVault().depositSendPacketFee{value: msg.value}(channelId, sequence, gasLimits, gasPrices); + } + + function _depositOpenChannelFee( + IbcDispatcher dispatcher, + string memory version, + ChannelOrder ordering, + string[] calldata connectionHops, + string calldata counterpartyPortId + ) internal { + dispatcher.feeVault().depositOpenChannelFee{value: msg.value}( + address(this), version, ordering, connectionHops, counterpartyPortId + ); + } +} diff --git a/contracts/interfaces/IbcReceiverUpgradeable.sol b/contracts/implementation_templates/IbcReceiverUpgradeable.sol similarity index 96% rename from contracts/interfaces/IbcReceiverUpgradeable.sol rename to contracts/implementation_templates/IbcReceiverUpgradeable.sol index fc12d784..dfd01d7c 100644 --- a/contracts/interfaces/IbcReceiverUpgradeable.sol +++ b/contracts/implementation_templates/IbcReceiverUpgradeable.sol @@ -18,12 +18,13 @@ pragma solidity ^0.8.9; import {OwnableUpgradeable} from "@openzeppelin-upgradeable/contracts/access/OwnableUpgradeable.sol"; -import {IbcDispatcher} from "./IbcDispatcher.sol"; +import {IbcDispatcher} from "../interfaces/IbcDispatcher.sol"; contract IbcReceiverBaseUpgradeable is OwnableUpgradeable { IbcDispatcher public dispatcher; error notIbcDispatcher(); + error invalidAddress(); error UnsupportedVersion(); error ChannelNotFound(); diff --git a/contracts/interfaces/IDispatcher.sol b/contracts/interfaces/IDispatcher.sol index 4f6d064d..43e052c9 100644 --- a/contracts/interfaces/IDispatcher.sol +++ b/contracts/interfaces/IDispatcher.sol @@ -21,6 +21,7 @@ import {IbcDispatcher, IbcEventsEmitter} from "./IbcDispatcher.sol"; import {L1Header, OpL2StateProof, Ics23Proof} from "./IProofVerifier.sol"; import {Channel, ChannelEnd, ChannelOrder, IbcPacket} from "../libs/Ibc.sol"; import {ILightClient} from "./ILightClient.sol"; +import {IFeeVault} from "./IFeeVault.sol"; interface IDispatcher is IbcDispatcher, IbcEventsEmitter { function setPortPrefix(string calldata _portPrefix) external; @@ -105,6 +106,7 @@ interface IDispatcher is IbcDispatcher, IbcEventsEmitter { function writeTimeoutPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external; function recvPacket(IbcPacket calldata packet, Ics23Proof calldata proof) external; + function feeVault() external returns (IFeeVault feeVault); function getOptimisticConsensusState(uint256 height, string calldata connection) external diff --git a/contracts/interfaces/IFeeVault.sol b/contracts/interfaces/IFeeVault.sol new file mode 100644 index 00000000..2948c556 --- /dev/null +++ b/contracts/interfaces/IFeeVault.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2024, Polymer Labs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pragma solidity 0.8.15; + +import {ChannelOrder} from "../libs/Ibc.sol"; + +struct GasFee { + uint256 gasLimit; + uint256 gasPrice; +} + +struct SendpacketFeeDeposited { + uint256[2] gasLimits; + uint256[2] gasPrices; +} + +interface IFeeVault { + event SendPacketFeeDeposited(bytes32 channelId, uint64 sequence, uint256[2] gasLimits, uint256[2] gasPrices); + event OpenChannelFeeDeposited( + address sourceAddress, + string version, + ChannelOrder ordering, + string[] connectionHops, + string counterpartyPortId, + uint256 feeAmount + ); + + error SenderNotDispatcher(); + error NoFeeSent(); + error IncorrectFeeSent(uint256 expected, uint256 sent); + + function depositSendPacketFee( + bytes32 channelId, + uint64 sequence, + uint256[2] calldata gasLimits, + uint256[2] calldata gasPrices + ) external payable; + + function depositOpenChannelFee( + address sender, + string memory version, + ChannelOrder ordering, + string[] calldata connectionHops, + string memory counterpartyPortId + ) external payable; + + function withdrawFeesToOwner() external; +} diff --git a/contracts/interfaces/IbcDispatcher.sol b/contracts/interfaces/IbcDispatcher.sol index 798019ed..6bff228a 100644 --- a/contracts/interfaces/IbcDispatcher.sol +++ b/contracts/interfaces/IbcDispatcher.sol @@ -19,6 +19,7 @@ pragma solidity ^0.8.9; import {Height, ChannelOrder, AckPacket} from "../libs/Ibc.sol"; import {Ics23Proof} from "./IProofVerifier.sol"; +import {IFeeVault} from "./IFeeVault.sol"; /** * @title IbcPacketSender @@ -49,7 +50,7 @@ interface IbcDispatcher is IbcPacketSender { function channelCloseConfirm(address portAddress, bytes32 channelId, Ics23Proof calldata proof) external; function channelCloseInit(bytes32 channelId) external; - + function feeVault() external returns (IFeeVault feeVault); function portPrefix() external view returns (string memory portPrefix); } diff --git a/contracts/interfaces/IbcMiddleware.sol b/contracts/interfaces/IbcMiddleware.sol index ef98768b..80a2df64 100644 --- a/contracts/interfaces/IbcMiddleware.sol +++ b/contracts/interfaces/IbcMiddleware.sol @@ -31,7 +31,16 @@ interface IbcUniversalPacketSender { bytes32 destPortAddr, bytes calldata appData, uint64 timeoutTimestamp - ) external; + ) external returns (uint64 sequence); + + function sendUniversalPacketWithFee( + bytes32 channelId, + bytes32 destPortAddr, + bytes calldata appData, + uint64 timeoutTimestamp, + uint256[2] calldata gasLimits, + uint256[2] calldata gasPrices + ) external payable returns (uint64 sequence); } interface IbcMwPacketSender { @@ -47,7 +56,7 @@ interface IbcMwPacketSender { uint256 srcMwIds, bytes calldata appData, uint64 timeoutTimestamp - ) external; + ) external returns (uint64 sequence); } // IBC middleware contracts must implement this interface to relay universal channel packets to other IBC middleware diff --git a/test/Dispatcher.gasGriefing.t.sol b/test/Dispatcher.gasGriefing.t.sol index 73c05d8e..9210203f 100644 --- a/test/Dispatcher.gasGriefing.t.sol +++ b/test/Dispatcher.gasGriefing.t.sol @@ -22,7 +22,7 @@ contract DispatcherGasGriefing is Base { ChannelEnd("polyibc.eth.71C95911E9a5D330f4D621842EC243EE1343292e", IbcUtils.toBytes32("channel-1"), "1.0"); function setUp() public override { - (dispatcherProxy, dispatcherImplementation) = TestUtilsTest.deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = TestUtilsTest.deployDispatcherProxyAndImpl(portPrefix, feeVault); gasUsingMars = new GasUsingMars(3_000_000, dispatcherProxy); // Set arbitrarily high gas useage in mars contract bytes32 connectionStr = bytes32(0x636f6e6e656374696f6e2d310000000000000000000000000000000000000018); // connection-1 // in hex diff --git a/test/Dispatcher/Dispatcher.client.t.sol b/test/Dispatcher/Dispatcher.client.t.sol index ee02dcc7..dd6bdc40 100644 --- a/test/Dispatcher/Dispatcher.client.t.sol +++ b/test/Dispatcher/Dispatcher.client.t.sol @@ -31,7 +31,7 @@ abstract contract DispatcherUpdateClientTestSuite is Base { contract DispatcherUpdateClientTest is DispatcherUpdateClientTestSuite { function setUp() public virtual override { - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix, feeVault); dispatcherProxy.setClientForConnection("connection-0", opLightClient); } } diff --git a/test/Dispatcher/Dispatcher.closeChannel.t.sol b/test/Dispatcher/Dispatcher.closeChannel.t.sol index af3ab54e..8647055c 100644 --- a/test/Dispatcher/Dispatcher.closeChannel.t.sol +++ b/test/Dispatcher/Dispatcher.closeChannel.t.sol @@ -21,11 +21,13 @@ contract DispatcherCloseChannelTest is PacketSenderTestBase { } function test_closeChannelInit_success() public { + vm.startPrank(mars.owner()); assertNotEq0(abi.encode(dispatcherProxy.getChannel(address(mars), channelId)), abi.encode(defaultChannel)); vm.expectEmit(true, true, true, true); emit ChannelCloseInit(address(mars), channelId); mars.triggerChannelClose(channelId); assertEq(abi.encode(dispatcherProxy.getChannel(address(mars), channelId)), abi.encode(defaultChannel)); + vm.stopPrank(); } function test_closeChannelInit_mustOwner() public { @@ -56,11 +58,20 @@ contract DispatcherCloseChannelTest is PacketSenderTestBase { } function test_sendPacket_afterChannelCloseInit() public { + vm.startPrank(mars.owner()); mars.triggerChannelClose(channelId); sentPacket = genPacket(nextSendSeq); ackPacket = genAckPacket(Ibc.toStr(nextSendSeq)); vm.expectRevert(IBCErrors.channelNotOwnedBySender.selector); mars.greet(payloadStr, channelId, maxTimeout); + + // Should also revert for fee enabled packets + vm.deal(address(this), totalSendPacketFees); + vm.expectRevert(IBCErrors.channelNotOwnedBySender.selector); + mars.greetWithFee{value: totalSendPacketFees}( + payloadStr, channelId, maxTimeout, sendPacketGasLimit, sendPacketGasPrice + ); + vm.stopPrank(); } function test_sendPacket_afterChannelCloseConfirm() public { @@ -69,6 +80,13 @@ contract DispatcherCloseChannelTest is PacketSenderTestBase { ackPacket = genAckPacket(Ibc.toStr(nextSendSeq)); vm.expectRevert(IBCErrors.channelNotOwnedBySender.selector); mars.greet(payloadStr, channelId, maxTimeout); + + // Should also revert for fee enabled packets + vm.deal(address(this), totalSendPacketFees); + vm.expectRevert(IBCErrors.channelNotOwnedBySender.selector); + mars.greetWithFee{value: totalSendPacketFees}( + payloadStr, channelId, maxTimeout, sendPacketGasLimit, sendPacketGasPrice + ); } } diff --git a/test/Dispatcher/Dispatcher.dappHandlerRevert.t.sol b/test/Dispatcher/Dispatcher.dappHandlerRevert.t.sol index c62f5d88..2ded0a7a 100644 --- a/test/Dispatcher/Dispatcher.dappHandlerRevert.t.sol +++ b/test/Dispatcher/Dispatcher.dappHandlerRevert.t.sol @@ -21,7 +21,7 @@ contract DappHandlerRevertTests is Base { ChannelEnd("polyibc.eth2.71C95911E9a5D330f4D621842EC243EE1343292e", IbcUtils.toBytes32("channel-1"), "1.0"); function setUp() public virtual override { - (dispatcherProxy, dispatcherImplementation) = TestUtilsTest.deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = TestUtilsTest.deployDispatcherProxyAndImpl(portPrefix, feeVault); dispatcherProxy.setClientForConnection(connectionHops0[0], dummyLightClient); dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient); dispatcherProxy.setClientForConnection(connectionHops[0], dummyLightClient); diff --git a/test/Dispatcher/Dispatcher.multiclient.sol b/test/Dispatcher/Dispatcher.multiclient.sol index 8008b544..e897728f 100644 --- a/test/Dispatcher/Dispatcher.multiclient.sol +++ b/test/Dispatcher/Dispatcher.multiclient.sol @@ -24,7 +24,7 @@ contract DispatcherRealProofMultiClient is Base { function setUp() public override { opLightClient = new OptimisticLightClient(1, opProofVerifier, l1BlockProvider); dummyLightClient = new DummyLightClient(); - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl("polyibc.eth1."); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl("polyibc.eth1.", feeVault); dispatcherProxy.setClientForConnection(connectionHops0[0], dummyLightClient); dispatcherProxy.setClientForConnection(connectionHops1[0], opLightClient); address targetMarsAddress = 0x71C95911E9a5D330f4D621842EC243EE1343292e; diff --git a/test/Dispatcher/Dispatcher.proof.t.sol b/test/Dispatcher/Dispatcher.proof.t.sol index 54a7aebc..6e4bbe2f 100644 --- a/test/Dispatcher/Dispatcher.proof.t.sol +++ b/test/Dispatcher/Dispatcher.proof.t.sol @@ -32,6 +32,26 @@ abstract contract DispatcherIbcWithRealProofsSuite is IbcEventsEmitter, Base { dispatcherProxy.channelOpenInit(ch1.version, ChannelOrder.NONE, false, connectionHops1, ch1.portId); } + function test_ibc_channel_open_init_WithFee() public { + vm.deal(address(mars), totalOpenChannelFees); + uint256 startingBal = address(feeVault).balance; + + vm.expectEmit(true, true, true, true, address(dispatcherProxy)); + emit ChannelOpenInit(address(mars), "1.0", ChannelOrder.NONE, false, connectionHops1, ch1.portId); + + vm.expectEmit(true, true, true, true, address(feeVault)); + emit OpenChannelFeeDeposited( + address(mars), "1.0", ChannelOrder.NONE, connectionHops1, ch1.portId, totalOpenChannelFees + ); + // since this is open chann init, the proof is not used. so use an invalid one + mars.triggerChannelInitWithFee{value: totalOpenChannelFees}( + "1.0", ChannelOrder.NONE, false, connectionHops1, ch1.portId + ); + + vm.stopPrank(); + assertEq(address(feeVault).balance, startingBal + totalOpenChannelFees); + } + function test_ibc_channel_open_try() public { Ics23Proof memory proof = load_proof("/test/payload/channel_try_pending_proof.hex"); @@ -139,7 +159,7 @@ contract DispatcherIbcWithRealProofs is DispatcherIbcWithRealProofsSuite { string memory portPrefix1 = "polyibc.eth1."; opLightClient = new OptimisticLightClient(1, opProofVerifier, l1BlockProvider); - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix1); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix1, feeVault); dispatcherProxy.setClientForConnection(connectionHops0[0], opLightClient); dispatcherProxy.setClientForConnection(connectionHops0[1], opLightClient); dispatcherProxy.setClientForConnection(connectionHops1[0], opLightClient); diff --git a/test/Dispatcher/Dispatcher.t.sol b/test/Dispatcher/Dispatcher.t.sol index 38d74b8b..aa128343 100644 --- a/test/Dispatcher/Dispatcher.t.sol +++ b/test/Dispatcher/Dispatcher.t.sol @@ -103,6 +103,21 @@ abstract contract ChannelHandshakeTestSuite is ChannelHandshakeUtils { channelOpenConfirm(le, re, settings[i], true); } } + + // Should also be able to do the same with fee-enabled channels + 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]; + channelOpenInitWithFee(le, re, settings[i], true); + channelOpenTry(le, re, settings[i], true); + channelOpenAck(le, re, settings[i], true); + channelOpenConfirm(le, re, settings[i], true); + } + } } function test_openChannel_initiator_revert_unsupportedVersion() public { @@ -183,7 +198,7 @@ abstract contract ChannelHandshakeTestSuite is ChannelHandshakeUtils { contract ChannelHandshakeTest is ChannelHandshakeTestSuite { function setUp() public virtual override { - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix, feeVault); dispatcherProxy.setClientForConnection(connectionHops[0], dummyLightClient); mars = new Mars(dispatcherProxy); portId = IbcUtils.addressToPortId(portPrefix, address(mars)); @@ -208,7 +223,7 @@ contract ChannelOpenTestBaseSetup is Base { RevertingBytesMars revertingBytesMars; function setUp() public virtual override { - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix, feeVault); dispatcherProxy.setClientForConnection(connectionHops[0], dummyLightClient); ChannelHandshakeSetting memory setting = ChannelHandshakeSetting(ChannelOrder.ORDERED, feeEnabled, true, validProof); @@ -233,6 +248,7 @@ contract ChannelOpenTestBaseSetup is Base { channelOpenAck(_local, _remote, setting, true); channelOpenConfirm(_localRevertingMars, _remote, setting, true); + vm.stopPrank(); } } @@ -288,10 +304,32 @@ contract PacketSenderTestBase is ChannelOpenTestBaseSetup { function sendPacket() internal { sentPacket = genPacket(nextSendSeq); ackPacket = genAckPacket(Ibc.toStr(nextSendSeq)); - mars.greet(payloadStr, channelId, maxTimeout); + + uint256 currentSeqSend; + // Test both fee and non-fee incentivized packet sending by switching off every other nextSendSeq. + if (nextSendSeq % 2 == 0) { + currentSeqSend = _doFeeSendPacket(); + } else { + currentSeqSend = mars.greet(payloadStr, channelId, maxTimeout); + } + + assertEq(nextSendSeq, currentSeqSend); nextSendSeq += 1; } + function _doFeeSendPacket() internal returns (uint64 currentSeqSend) { + uint256 beforeBalance = address(feeVault).balance; + + vm.deal(address(this), totalSendPacketFees); + vm.expectEmit(true, true, true, true, address(dispatcherProxy)); + emit SendPacket(address(mars), channelId, payload, nextSendSeq, maxTimeout); + // Test both fee and non-fee incentivized packet sending by switching off every other nextSendSeq. + currentSeqSend = mars.greetWithFee{value: totalSendPacketFees}( + payloadStr, channelId, maxTimeout, sendPacketGasLimit, sendPacketGasPrice + ); + assertEq(address(feeVault).balance, beforeBalance + totalSendPacketFees); + } + // genPacket generates a packet for the given packet sequence function genPacket(uint64 packetSeq) internal view returns (IbcPacket memory) { return IbcPacket(src, dest, packetSeq, payload, ZERO_HEIGHT, maxTimeout); diff --git a/test/FeeVault.t.sol b/test/FeeVault.t.sol new file mode 100644 index 00000000..70fc5c18 --- /dev/null +++ b/test/FeeVault.t.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {ChannelOpenTestBaseSetup} from "./Dispatcher/Dispatcher.t.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import "forge-std/Test.sol"; + +contract FeeVaultTest is ChannelOpenTestBaseSetup { + address notOwner = vm.addr(2); + address owner; + Ownable feeVaultOwnable; // FeeVault address but from Ownable interface + uint256 feePerGreet = 600_000 * 60 gwei + 700_000 * 70 gwei; + + function setUp() public override { + super.setUp(); + + feeVaultOwnable = Ownable(address(feeVault)); + greetMarsWithFee(); + } + + // Fuzz test for always reverting if incorrect fee is sent. + function testFuzz_sendPacket_FeesAddUpToValue( + uint104 gasFee1, + uint104 gasFee2, + uint104 gasLimit1, + uint104 gasLimit2, + bool shouldRevert, + uint56 fuzz + ) public { + gasFee1 = uint104(bound(gasFee1, 1, 2 ** 104 - 1)); + gasLimit1 = uint104(bound(gasLimit1, 1, 2 ** 104 - 1)); + fuzz = uint56(bound(fuzz, 1, 2 ** 56 - 1)); + fuzz = uint56(bound(fuzz, 1, gasFee1)); + + uint256 feesToSend = uint256(gasFee1) * uint256(gasLimit1) + uint256(gasFee2) * uint256(gasLimit2); + vm.deal(address(this), feesToSend + fuzz); + + if (shouldRevert) { + // Fuzz the fees to make sure it reverts + if (fuzz % 2 == 0) { + feesToSend += uint256(fuzz); + } else { + feesToSend -= uint256(fuzz); + } + vm.expectRevert(); + } + feeVault.depositSendPacketFee{value: feesToSend}( + channelId, uint64(1), [uint256(gasFee1), uint256(gasFee2)], [uint256(gasLimit1), uint256(gasLimit2)] + ); + } + + function test_withdrawAlwaysGoesToOwner() public { + assertEq(address(feeVault).balance, feePerGreet); + uint256 startingBalance = address(this).balance; + feeVault.withdrawFeesToOwner(); + assertEq(address(this).balance, startingBalance + feePerGreet); + + greetMarsWithFee(); // send more fees to feeVault + // Non Owners can call but it should sill go to the owner (i.e. this address) + vm.prank(notOwner); + feeVault.withdrawFeesToOwner(); + assertEq(address(feeVault).balance, 0); + assertEq(address(this).balance, startingBalance + (feePerGreet * 2)); + } + + function greetMarsWithFee() internal { + vm.deal(address(mars), feePerGreet); + vm.prank(address(mars)); + vm.expectEmit(false, true, true, false, address(feeVault)); // Ignore the emitted seuqence since we don't know + // what it will be before we call sendpacket (vm.expect emit assumes the first event will always be + // chedcked, so to avoid checking second argument we pass false for the first argument) + emit SendPacketFeeDeposited( + channelId, 1, [uint256(600_000), uint256(700_000)], [uint256(60 gwei), uint256(70 gwei)] + ); + mars.greetWithFee{value: feePerGreet}( + "hello", channelId, maxTimeout, [uint256(600_000), uint256(700_000)], [uint256(60 gwei), uint256(70 gwei)] + ); + } + + // This test contract needs to have a receive function to accept funds sent from the FeeVault + // Note: our multisig should have a fallback to accept funds in general + receive() external payable {} +} diff --git a/test/VirtualChain.sol b/test/VirtualChain.sol index 04ed56cd..a5783dab 100644 --- a/test/VirtualChain.sol +++ b/test/VirtualChain.sol @@ -6,12 +6,14 @@ import "@openzeppelin/contracts/utils/Strings.sol"; import {IbcDispatcher, IbcEventsEmitter} from "../contracts/interfaces/IbcDispatcher.sol"; import {IUniversalChannelHandler} from "../contracts/interfaces/IUniversalChannelHandler.sol"; import {IDispatcher} from "../contracts/interfaces/IDispatcher.sol"; +import {IFeeVault} from "../contracts/interfaces/IFeeVault.sol"; import "../contracts/libs/Ibc.sol"; import {IbcUtils} from "../contracts/libs/IbcUtils.sol"; import {Dispatcher} from "../contracts/core/Dispatcher.sol"; import {IbcChannelReceiver, IbcPacketReceiver} from "../contracts/interfaces/IbcReceiver.sol"; import "../contracts/interfaces/IProofVerifier.sol"; import {UniversalChannelHandler} from "../contracts/core/UniversalChannelHandler.sol"; +import {FeeVault} from "../contracts/core/FeeVault.sol"; import {Mars} from "../contracts/examples/Mars.sol"; import {Earth} from "../contracts/examples/Earth.sol"; import {GeneralMiddleware} from "../contracts/base/GeneralMiddleware.sol"; @@ -35,6 +37,7 @@ struct VirtualChainData { GeneralMiddleware mw1; GeneralMiddleware mw2; string[] connectionHops; + IFeeVault feeVault; } // A test contract that keeps two types of dApps, 1. regular IBC-enabled dApp, 2. universal channel dApp @@ -42,6 +45,7 @@ contract VirtualChain is Test, IbcEventsEmitter, TestUtilsTest { IDispatcher public dispatcherProxy; Dispatcher public dispatcherImplementation; IUniversalChannelHandler public ucHandlerProxy; + IFeeVault public feeVault; GeneralMiddleware public mw1; GeneralMiddleware public mw2; @@ -60,8 +64,9 @@ contract VirtualChain is Test, IbcEventsEmitter, TestUtilsTest { // ChannelIds are not initialized until channel handshake is started constructor(uint256 seed, string memory portPrefix) { _seed = seed; + feeVault = new FeeVault(); - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix, feeVault); (ucHandlerProxy,) = deployUCHProxyAndImpl(address(dispatcherProxy)); mars = new Mars(dispatcherProxy); @@ -82,7 +87,7 @@ contract VirtualChain is Test, IbcEventsEmitter, TestUtilsTest { // return virtualChainData function getVirtualChainData() external view returns (VirtualChainData memory) { - return VirtualChainData(dispatcherProxy, ucHandlerProxy, mars, earth, mw1, mw2, connectionHops); + return VirtualChainData(dispatcherProxy, ucHandlerProxy, mars, earth, mw1, mw2, connectionHops, feeVault); } // expectedChannel returns a Channel struct with expected values diff --git a/test/universal.channel.t.sol b/test/universal.channel.t.sol index ab4a0e9a..bd42ce0c 100644 --- a/test/universal.channel.t.sol +++ b/test/universal.channel.t.sol @@ -12,6 +12,7 @@ import "../contracts/interfaces/IbcMiddleware.sol"; import "../contracts/core/OptimisticLightClient.sol"; import "./utils/Dispatcher.base.t.sol"; import "./VirtualChain.sol"; +import {IFeeVault} from "../contracts/interfaces/IFeeVault.sol"; contract UniversalChannelTest is Base { function test_channel_settings_ok() public { @@ -243,7 +244,7 @@ contract UniversalChannelPacketTest is Base, IbcMwEventsEmitter { function test_uch_new_dispatcher_set_ok() public { IUniversalChannelHandler uch = eth1.ucHandlerProxy(); vm.startPrank(address(eth1)); // Prank eth1 since that address is the owner - (IDispatcher newDispatcher,) = deployDispatcherProxyAndImpl("polyibc.new."); + (IDispatcher newDispatcher,) = deployDispatcherProxyAndImpl("polyibc.new.", feeVault); assertFalse( address(uch.dispatcher()) == address(newDispatcher), "new dispatcher in uch test not setup correctly" ); @@ -256,7 +257,7 @@ contract UniversalChannelPacketTest is Base, IbcMwEventsEmitter { IUniversalChannelHandler uch = eth1.ucHandlerProxy(); address notOwner = vm.addr(1); vm.startPrank(notOwner); - (IDispatcher newDispatcher,) = deployDispatcherProxyAndImpl("polyibc.new."); + (IDispatcher newDispatcher,) = deployDispatcherProxyAndImpl("polyibc.new.", feeVault); vm.expectRevert("Ownable: caller is not the owner"); uch.setDispatcher(newDispatcher); @@ -460,9 +461,26 @@ contract UniversalChannelPacketTest is Base, IbcMwEventsEmitter { } // Verify event emitted by Dispatcher - vm.expectEmit(true, true, true, true); - emit SendPacket(address(v1.ucHandlerProxy), channelId1, packetData, packetSeq, timeout); - v1.earth.greet(address(v2.earth), channelId1, appData, timeout); + + // Alternate test non fee & fee + if (packetSeq % 2 == 1) { + vm.expectEmit(true, true, true, true); + emit SendPacket(address(v1.ucHandlerProxy), channelId1, packetData, packetSeq, timeout); + v1.earth.greet(address(v2.earth), channelId1, appData, timeout); + } else { + uint256 beforeBalance = address(v1.feeVault).balance; + vm.deal(address(this), totalSendPacketFees); + + vm.expectEmit(true, true, true, true, address(v1.dispatcherProxy)); + emit SendPacket(address(v1.ucHandlerProxy), channelId1, packetData, packetSeq, timeout); + vm.expectEmit(true, true, true, true, address(v1.feeVault)); + emit SendPacketFeeDeposited(channelId1, packetSeq, sendPacketGasLimit, sendPacketGasPrice); + uint64 sequence = v1.earth.greetWithFee{value: totalSendPacketFees}( + address(v2.earth), channelId1, appData, timeout, sendPacketGasLimit, sendPacketGasPrice + ); + assertEq(address(v1.feeVault).balance, beforeBalance + totalSendPacketFees); + assertEq(sequence, packetSeq); + } // simulate relayer calling dispatcherProxy.recvPacket on chain B // recvPacket is an IBC packet diff --git a/test/upgradeableProxy/Dispatcher.upgrade.t.sol b/test/upgradeableProxy/Dispatcher.upgrade.t.sol index 2afe77b2..937bc687 100644 --- a/test/upgradeableProxy/Dispatcher.upgrade.t.sol +++ b/test/upgradeableProxy/Dispatcher.upgrade.t.sol @@ -24,12 +24,15 @@ import {IbcReceiver, IbcChannelReceiver} from "../../contracts/interfaces/IbcRec import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import {OptimisticLightClient} from "../../contracts/core/OptimisticLightClient.sol"; import {IProofVerifier} from "../../contracts/core/OptimisticProofVerifier.sol"; +import {IFeeVault} from "../../contracts/interfaces/IFeeVault.sol"; +import {FeeVault} from "../../contracts/core/FeeVault.sol"; import {DummyLightClient} from "../../contracts/utils/DummyLightClient.sol"; import {IDispatcher} from "../../contracts/interfaces/IDispatcher.sol"; import {UniversalChannelHandler} from "../../contracts/core/UniversalChannelHandler.sol"; import {IUniversalChannelHandler} from "../../contracts/interfaces/IUniversalChannelHandler.sol"; -import {DispatcherRc4} from "./upgrades/DispatcherRc4.sol"; +import {DispatcherRc4, IDispatcherRc4} from "./upgrades/DispatcherRc4.sol"; +import {Mars as MarsRc4, IbcDispatcher as IbcDispatcherRc4} from "./upgrades/MarsRc4.sol"; import {UniversalChannelHandlerV2} from "./upgrades/UCHV2.sol"; import {DispatcherV2Initializable} from "./upgrades/DispatcherV2Initializable.sol"; import {DispatcherV2} from "./upgrades/DispatcherV2.sol"; @@ -41,13 +44,13 @@ abstract contract UpgradeTestUtils { LocalEnd _localDummy; ChannelEnd _remoteDummy; - function upgradeDispatcher(string memory portPrefix, address dispatcherProxy) + function upgradeDispatcher(string memory portPrefix, IFeeVault feeVault, address dispatcherProxy) public returns (DispatcherV2Initializable newDispatcherImplementation) { // Upgrade dispatcherProxy for tests newDispatcherImplementation = new DispatcherV2Initializable(); - bytes memory initData = abi.encodeWithSignature("initialize(string)", portPrefix); + bytes memory initData = abi.encodeWithSignature("initialize(string,address)", portPrefix, feeVault); UUPSUpgradeable(dispatcherProxy).upgradeToAndCall(address(newDispatcherImplementation), initData); } @@ -58,12 +61,12 @@ abstract contract UpgradeTestUtils { function deployDispatcherRC4ProxyAndImpl(string memory initPortPrefix, ILightClient initLightClient) public - returns (IDispatcher proxy) + returns (IbcDispatcherRc4 proxy) { DispatcherRc4 dispatcherImplementation = new DispatcherRc4(); bytes memory initData = abi.encodeWithSelector(DispatcherRc4.initialize.selector, initPortPrefix, initLightClient); - proxy = IDispatcher(address(new ERC1967Proxy(address(dispatcherImplementation), initData))); + proxy = IbcDispatcherRc4(address(new ERC1967Proxy(address(dispatcherImplementation), initData))); } function deployUCHV2ProxyAndImpl(address dispatcherProxy) public returns (IUniversalChannelHandler proxy) { @@ -171,7 +174,7 @@ contract ChannelHandShakeUpgradeUtil is ChannelHandshakeUtils { contract DispatcherUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils { function setUp() public override { address targetMarsAddress = 0x71C95911E9a5D330f4D621842EC243EE1343292e; - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix, feeVault); deployCodeTo("contracts/examples/Mars.sol:Mars", abi.encode(address(dispatcherProxy)), targetMarsAddress); dispatcherProxy.setClientForConnection(connectionHops[0], dummyLightClient); mars = new Mars(dispatcherProxy); @@ -184,8 +187,9 @@ contract DispatcherUpgradeTest is ChannelHandShakeUpgradeUtil, UpgradeTestUtils doChannelHandshake(_local, _remote); sendPacket(_local.channelId); + IFeeVault newFeeVault = new FeeVault(); // Upgrade dispatcherProxy for tests - upgradeDispatcher("adfsafsa", address(dispatcherProxy)); + upgradeDispatcher("adfsafsa", newFeeVault, address(dispatcherProxy)); } function test_SentPacketState_Conserved() public { diff --git a/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol b/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol index 91af2580..f33bc3b5 100644 --- a/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol +++ b/test/upgradeableProxy/DispatcherRC4.upgrade.t.sol @@ -66,13 +66,16 @@ contract DispatcherRC4UpgradeTest is DispatcherRC4TestUtils, UpgradeTestUtils { 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 = IbcDispatcherRc4(address(deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient))); // we have to manually cast here because solidity is confused by having interfaces coming from seperate files + oldDummyDispatcherProxy = + IbcDispatcherRc4(address(deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient))); // we have to manually + // cast here because solidity is confused by having interfaces coming from seperate files // 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) - oldDispatcherInterface = IbcDispatcherRc4(address(deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient2))); + oldDispatcherInterface = + IbcDispatcherRc4(address(deployDispatcherRC4ProxyAndImpl(portPrefix, dummyLightClient2))); dispatcherProxy = IDispatcher(address(oldDispatcherInterface)); uch = deployUCHV2ProxyAndImpl(address(dispatcherProxy)); earth = new EarthRc4(address(uch)); @@ -101,7 +104,7 @@ contract DispatcherRC4UpgradeTest is DispatcherRC4TestUtils, UpgradeTestUtils { earth.greet(address(sendingMars), _localUch.channelId, bytes("hello sendingMars"), UINT64_MAX); // Upgrade dispatcherProxy and uch for tests - upgradeDispatcher(portPrefix, address(dispatcherProxy)); + upgradeDispatcher(portPrefix, feeVault, address(dispatcherProxy)); upgradeUch(address(uch)); dispatcherProxy.setClientForConnection(connectionHops0[0], dummyLightClient2); dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient2); @@ -258,7 +261,7 @@ contract DispatcherRC4MidwayUpgradeTest is DispatcherRC4TestUtils, UpgradeTestUt // Test that channel handshake can be finished even if done during an upgrade function test_UpgradeBetween_ChannelOpen() public { - upgradeDispatcher(portPrefix, address(dispatcherProxy)); + upgradeDispatcher(portPrefix, feeVault, address(dispatcherProxy)); dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient2); ChannelHandshakeSetting memory setting = ChannelHandshakeSetting(ChannelOrder.ORDERED, false, true, validProof); channelOpenAck(_local, _remote, setting, true); @@ -282,7 +285,7 @@ contract DispatcherRC4MidwayUpgradeTest is DispatcherRC4TestUtils, UpgradeTestUt ); // Do upgrade before finishing packet handshake - upgradeDispatcher(portPrefix, address(dispatcherProxy)); + upgradeDispatcher(portPrefix, feeVault, address(dispatcherProxy)); upgradeUch(address(uch)); dispatcherProxy.setClientForConnection(connectionHops1[0], dummyLightClient2); // earth.authorizeChannel(_localUch.channelId); diff --git a/test/upgradeableProxy/DispatcherUUPS.accessControl.t.sol b/test/upgradeableProxy/DispatcherUUPS.accessControl.t.sol index ba7736ac..07c4d53e 100644 --- a/test/upgradeableProxy/DispatcherUUPS.accessControl.t.sol +++ b/test/upgradeableProxy/DispatcherUUPS.accessControl.t.sol @@ -5,6 +5,7 @@ import "../../contracts/libs/Ibc.sol"; import {Dispatcher} from "../../contracts/core/Dispatcher.sol"; import {IbcEventsEmitter} from "../../contracts/interfaces/IbcDispatcher.sol"; import {IbcReceiver} from "../../contracts/interfaces/IbcReceiver.sol"; +import {IFeeVault} from "../../contracts/interfaces/IFeeVault.sol"; import {Mars} from "../../contracts/examples/Mars.sol"; import "../../contracts/core/OptimisticLightClient.sol"; import "../utils/Dispatcher.base.t.sol"; @@ -21,7 +22,7 @@ contract DispatcherUUPSAccessControl is Base { DispatcherV2Initializable dispatcherImplementation3; function setUp() public override { - (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix); + (dispatcherProxy, dispatcherImplementation) = deployDispatcherProxyAndImpl(portPrefix, feeVault); dispatcherProxy.setClientForConnection(connectionHops[0], dummyLightClient); dispatcherImplementation2 = new DispatcherV2(); dispatcherImplementation3 = new DispatcherV2Initializable(); @@ -35,11 +36,13 @@ contract DispatcherUUPSAccessControl is Base { } function test_Dispatcher_Allows_Upgrade_To_And_Call() public { + IFeeVault newFeeVault = new FeeVault(); assertEq(address(dispatcherImplementation), getProxyImplementation(address(dispatcherProxy), vm)); - bytes memory initData = abi.encodeWithSignature("initialize(string)", portPrefix2); + bytes memory initData = abi.encodeWithSignature("initialize(string,address)", portPrefix2, newFeeVault); UUPSUpgradeable(address(dispatcherProxy)).upgradeToAndCall(address(dispatcherImplementation3), initData); assertEq(address(dispatcherImplementation3), getProxyImplementation(address(dispatcherProxy), vm)); assertEq(dispatcherProxy.portPrefix(), portPrefix2); + assertEq(address(dispatcherProxy.feeVault()), address(newFeeVault)); } function test_Dispatcher_Prevents_Non_Owner_Updgrade() public { @@ -55,6 +58,6 @@ contract DispatcherUUPSAccessControl is Base { function test_Dispatcher_Prevents_Reinit_Attacks() public { vm.expectRevert("Initializable: contract is already initialized"); - dispatcherImplementation.initialize("IIpolyibc.eth."); + dispatcherImplementation.initialize("IIpolyibc.eth.", IFeeVault(vm.addr(1))); } } diff --git a/test/upgradeableProxy/upgrades/DispatcherV2Initializable.sol b/test/upgradeableProxy/upgrades/DispatcherV2Initializable.sol index df60ed4d..a8bed48d 100644 --- a/test/upgradeableProxy/upgrades/DispatcherV2Initializable.sol +++ b/test/upgradeableProxy/upgrades/DispatcherV2Initializable.sol @@ -19,6 +19,7 @@ pragma solidity ^0.8.9; import {DispatcherV2} from "./DispatcherV2.sol"; import {ILightClient} from "../../../contracts/interfaces/ILightClient.sol"; +import {IFeeVault} from "../../../contracts/interfaces/IFeeVault.sol"; import {IBCErrors} from "../../../contracts/libs/IbcErrors.sol"; /** @@ -29,9 +30,10 @@ import {IBCErrors} from "../../../contracts/libs/IbcErrors.sol"; * which can be relayed to a rollup module on the Polymerase chain */ contract DispatcherV2Initializable is DispatcherV2 { - function initialize(string memory initPortPrefix) public override reinitializer(2) { + function initialize(string memory initPortPrefix, IFeeVault _feeVault) public override reinitializer(2) { __Ownable_init(); portPrefix = initPortPrefix; portPrefixLen = uint32(bytes(initPortPrefix).length); + feeVault = _feeVault; } } diff --git a/test/utils/Dispatcher.base.t.sol b/test/utils/Dispatcher.base.t.sol index 788b06c9..8e23285e 100644 --- a/test/utils/Dispatcher.base.t.sol +++ b/test/utils/Dispatcher.base.t.sol @@ -14,6 +14,8 @@ import "../../contracts/utils/DummyLightClient.sol"; import "../../contracts/core/OptimisticProofVerifier.sol"; import {TestUtilsTest} from "./TestUtils.t.sol"; import {stdStorage, StdStorage} from "forge-std/Test.sol"; +import {FeeVault} from "../../contracts/core/FeeVault.sol"; +import {IFeeVault} from "../../contracts/interfaces/IFeeVault.sol"; struct LocalEnd { IbcChannelReceiver receiver; @@ -36,6 +38,16 @@ struct ChannelHandshakeSetting { contract Base is IbcEventsEmitter, ProofBase, TestUtilsTest { using stdStorage for StdStorage; + event SendPacketFeeDeposited(bytes32 channelId, uint64 sequence, uint256[2] gasLimits, uint256[2] gasPrices); + event OpenChannelFeeDeposited( + address sourceAddress, + string version, + ChannelOrder ordering, + string[] connectionHops, + string counterpartyPortId, + uint256 fees + ); + 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; @@ -45,12 +57,22 @@ contract Base is IbcEventsEmitter, ProofBase, TestUtilsTest { ILightClient opLightClient = new OptimisticLightClient(1800, opProofVerifier, l1BlockProvider); ILightClient dummyLightClient = new DummyLightClient(); + IFeeVault feeVault = new FeeVault(); IDispatcher public dispatcherProxy; Dispatcher public dispatcherImplementation; string portPrefix = "polyibc.eth."; string[] connectionHops = ["connection-1", "connection-2"]; + uint256 BASE_GAS_LIMIT = 1_000_000; + uint256 BASE_GAS_PRICE = 50 gwei; + uint256[2] public sendPacketGasLimit = [BASE_GAS_LIMIT, BASE_GAS_LIMIT]; + uint256[2] public sendPacketGasPrice = [BASE_GAS_PRICE, BASE_GAS_PRICE]; + uint256 public totalSendPacketFees = BASE_GAS_LIMIT * BASE_GAS_PRICE * 2; + + uint256 public totalOpenChannelFees = BASE_GAS_LIMIT * BASE_GAS_PRICE * 3; // The msg.value sent in a + // channelOpenInit call + // ⬇️ Utility functions for testing // getHexStr converts an address to a hex string without the leading 0x @@ -92,6 +114,46 @@ contract Base is IbcEventsEmitter, ProofBase, TestUtilsTest { vm.stopPrank(); } + /** + * @dev Step-1 of the 4-step handshake to open an IBC channel. + * @param le Local end settings for the channel. + * @param re Remote end settings for the channel. + * @param s Channel handshake settings. + * @param expPass Expected pass status of the operation. + * If expPass is false, `vm.expectRevert` should be called before this function. + */ + function channelOpenInitWithFee( + LocalEnd memory le, + ChannelEnd memory re, + ChannelHandshakeSetting memory s, + bool expPass + ) public { + uint256 beforeBalance = address(feeVault).balance; + vm.deal(address(le.receiver), totalOpenChannelFees); + + vm.startPrank(address(le.receiver)); + if (expPass) { + vm.expectEmit(true, true, true, true); + emit ChannelOpenInit( + address(le.receiver), le.versionExpected, s.ordering, s.feeEnabled, le.connectionHops, re.portId + ); + } + dispatcherProxy.channelOpenInit(le.versionCall, s.ordering, s.feeEnabled, le.connectionHops, re.portId); + if (expPass) { + vm.expectEmit(true, true, true, true, address(feeVault)); + emit OpenChannelFeeDeposited( + address(le.receiver), le.versionCall, s.ordering, connectionHops, re.portId, totalOpenChannelFees + ); + } + feeVault.depositOpenChannelFee{value: totalOpenChannelFees}( + address(le.receiver), le.versionCall, s.ordering, le.connectionHops, re.portId + ); + + assertEq(address(feeVault).balance, beforeBalance + totalOpenChannelFees); + + vm.stopPrank(); + } + /** * @dev Step-2 of the 4-step handshake to open an IBC channel. * @param le Local end settings for the channel. diff --git a/test/utils/TestUtils.t.sol b/test/utils/TestUtils.t.sol index e8fbd9e7..4a1fb04b 100644 --- a/test/utils/TestUtils.t.sol +++ b/test/utils/TestUtils.t.sol @@ -3,6 +3,7 @@ import {IDispatcher} from "../../contracts/interfaces/IDispatcher.sol"; import {IUniversalChannelHandler} from "../../contracts/interfaces/IUniversalChannelHandler.sol"; import {UniversalChannelHandler} from "../../contracts/core/UniversalChannelHandler.sol"; import {ILightClient} from "../../contracts/interfaces/ILightClient.sol"; +import {IFeeVault} from "../../contracts/interfaces/IFeeVault.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {Dispatcher} from "../../contracts/core/Dispatcher.sol"; import {Test} from "forge-std/Test.sol"; @@ -15,7 +16,7 @@ abstract contract TestUtilsTest { bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - function deployDispatcherProxyAndImpl(string memory initPortPrefix) + function deployDispatcherProxyAndImpl(string memory initPortPrefix, IFeeVault feeVault) public returns (IDispatcher proxy, Dispatcher dispatcherImplementation) { @@ -24,7 +25,7 @@ abstract contract TestUtilsTest { address( new ERC1967Proxy( address(dispatcherImplementation), - abi.encodeWithSelector(Dispatcher.initialize.selector, initPortPrefix) + abi.encodeWithSelector(Dispatcher.initialize.selector, initPortPrefix, feeVault) ) ) );