Skip to content

Commit

Permalink
- Introduced the use of OptionsLib for decoding transaction options w…
Browse files Browse the repository at this point in the history
…ithin the InterchainClientV1 contract.

- Enabled dynamic gas limits for appReceive calls based on options specified in incoming interchain transactions.
  • Loading branch information
aureliusbtc committed Feb 17, 2024
1 parent 733e92d commit 16e0850
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ import {IInterchainClientV1} from "./interfaces/IInterchainClientV1.sol";

import {TypeCasts} from "./libs/TypeCasts.sol";

import { OptionsLib } from "./libs/Options.sol";

/**
* @title InterchainClientV1
* @dev Implements the operations of the Interchain Execution Layer.
*/
contract InterchainClientV1 is Ownable, IInterchainClientV1 {
using OptionsLib for bytes;

uint64 public clientNonce;
address public interchainDB;
mapping(bytes32 => bool) public executedTransactions;
Expand Down Expand Up @@ -237,7 +241,10 @@ contract InterchainClientV1 is Ownable, IInterchainClientV1 {
require(isExecutable(transaction), "Transaction is not executable");
InterchainTransaction memory icTx = abi.decode(transaction, (InterchainTransaction));
executedTransactions[icTx.transactionId] = true;
IInterchainApp(TypeCasts.bytes32ToAddress(icTx.dstReceiver)).appReceive();

OptionsLib.Options memory decodedOptions = icTx.options.decodeOptions();

IInterchainApp(TypeCasts.bytes32ToAddress(icTx.dstReceiver)).appReceive{gas: decodedOptions.gasLimit}();
emit InterchainTransactionExecuted(
icTx.srcSender,
icTx.srcChainId,
Expand Down
20 changes: 20 additions & 0 deletions packages/contracts-communication/contracts/libs/Options.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library OptionsLib {
struct Options {
uint8 version;
uint256 gasLimit;
// uint256 msgValue;
uint256 gasAirdrop;
}

function encodeOptions(Options memory options) internal pure returns (bytes memory) {
return abi.encode(options.version, options.gasLimit, options.gasAirdrop);
}

function decodeOptions(bytes memory data) internal pure returns (Options memory) {
(uint8 version, uint256 gasLimit, uint256 gasAirdrop) = abi.decode(data, (uint8, uint256, uint256));
return Options(version, gasLimit, gasAirdrop);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ import {InterchainEntry} from "../contracts/libs/InterchainEntry.sol";

import {TypeCasts} from "../contracts/libs/TypeCasts.sol";

import {OptionsLib} from "../contracts/libs/Options.sol";

contract InterchainClientV1Test is Test {
InterchainClientV1 icClient;
InterchainDB icDB;
SynapseModule synapseModule;
InterchainAppMock icApp;
InterchainModuleMock icModule;

// Use default options of V1, 200k gas limit, 0 gas airdrop
bytes options = OptionsLib.encodeOptions(OptionsLib.Options(1, 200000, 0));

uint256 public constant SRC_CHAIN_ID = 1337;
uint256 public constant DST_CHAIN_ID = 7331;

Expand Down Expand Up @@ -50,14 +55,12 @@ contract InterchainClientV1Test is Test {
TypeCasts.addressToBytes32(msg.sender), block.chainid, receiver, DST_CHAIN_ID, message, nonce
)
);
bytes memory options = "";
icClient.interchainSend{value: 1}(receiver, DST_CHAIN_ID, message, options, srcModules);
}

function test_interchainReceive() public {
bytes32 dstReceiver = TypeCasts.addressToBytes32(address(icApp));
bytes memory message = "Hello World";
bytes memory options = "";
bytes32 srcSender = TypeCasts.addressToBytes32(makeAddr("Sender"));
vm.prank(contractOwner);
icClient.setLinkedClient(SRC_CHAIN_ID, srcSender);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {OptionsLib} from "../../contracts/libs/Options.sol";

contract OptionsLibHarness {
function encodeOptions(
uint8 version,
uint256 gasLimit,
// uint256 msgValue,
uint256 gasAirdrop
)
external
pure
returns (bytes memory)
{
OptionsLib.Options memory options = OptionsLib.Options(version, gasLimit, gasAirdrop);
return OptionsLib.encodeOptions(options);
}

function decodeOptions(bytes calldata data) external pure returns (uint8, uint256, uint256) {
OptionsLib.Options memory options = OptionsLib.decodeOptions(data);
return (options.version, options.gasLimit, options.gasAirdrop);
}
}
37 changes: 37 additions & 0 deletions packages/contracts-communication/test/libs/OptionsLib.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
import {Test} from "forge-std/Test.sol";

import { OptionsLib, OptionsLibHarness } from "../harnesses/OptionsLibHarness.sol";

contract OptionsLibTest is Test {
OptionsLibHarness public libHarness;

function setUp() public {
libHarness = new OptionsLibHarness();
}

function test_encodeOptions() public {
uint8 version = 1;
// 200k gas limit
uint256 gasLimit = 200000;
// 100k wei
uint256 gasAirdrop = 100000;
bytes memory expected = abi.encode(version, gasLimit, gasAirdrop);
bytes memory actual = libHarness.encodeOptions(version, gasLimit, gasAirdrop);
assertEq(actual, expected);
}

function test_decodeOptions() public {
uint8 version = 1;
// 200k gas limit
uint256 gasLimit = 200000;
// 100k wei
uint256 gasAirdrop = 100000;
bytes memory data = abi.encode(version, gasLimit, gasAirdrop);
(uint8 actualVersion, uint256 actualGasLimit, uint256 actualGasAirdrop) = libHarness.decodeOptions(data);
assertEq(actualVersion, version);
assertEq(actualGasLimit, gasLimit);
assertEq(actualGasAirdrop, gasAirdrop);
}
}

0 comments on commit 16e0850

Please sign in to comment.