Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contracts/communication update client interface #2070

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 32 additions & 17 deletions packages/contracts-communication/contracts/InterchainClientV1.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IInterchainDB} from "./interfaces/IInterchainDB.sol";

import {IExecutionFees} from "./interfaces/IExecutionFees.sol";
import {IExecutionService} from "./interfaces/IExecutionService.sol";
import {IInterchainApp} from "./interfaces/IInterchainApp.sol";

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

import {IInterchainClientV1} from "./interfaces/IInterchainClientV1.sol";
import {IInterchainDB} from "./interfaces/IInterchainDB.sol";

import {InterchainEntry} from "./libs/InterchainEntry.sol";
import {OptionsLib, OptionsV1} from "./libs/Options.sol";
import {TypeCasts} from "./libs/TypeCasts.sol";

import {OptionsLib, OptionsV1} from "./libs/Options.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title InterchainClientV1
Expand All @@ -22,24 +22,29 @@ contract InterchainClientV1 is Ownable, IInterchainClientV1 {

uint64 public clientNonce;
address public interchainDB;
address public executionFees;
mapping(bytes32 => bool) public executedTransactions;

// Chain ID => Bytes32 Address of src clients
mapping(uint256 => bytes32) public linkedClients;

// TODO: Add permissioning
constructor() Ownable(msg.sender) {}

// @inheritdoc IInterchainClientV1
function setLinkedClient(uint256 chainId, bytes32 client) public onlyOwner {
linkedClients[chainId] = client;
function setExecutionFees(address executionFees_) public onlyOwner {
executionFees = executionFees_;
}

constructor() Ownable(msg.sender) {}

// @inheritdoc IInterchainClientV1
function setInterchainDB(address _interchainDB) public onlyOwner {
interchainDB = _interchainDB;
}

// @inheritdoc IInterchainClientV1
function setLinkedClient(uint256 chainId, bytes32 client) public onlyOwner {
linkedClients[chainId] = client;
}

/**
* @notice Emitted when an interchain transaction is sent.
*/
Expand Down Expand Up @@ -103,16 +108,19 @@ contract InterchainClientV1 is Ownable, IInterchainClientV1 {
// TODO: Calculate Gas Pricing per module and charge fees
// @inheritdoc IInterchainClientV1
function interchainSend(
bytes32 receiver,
uint256 dstChainId,
bytes32 receiver,
address srcExecutionService,
bytes calldata message,
bytes calldata options,
address[] calldata srcModules
)
public
payable
{
uint256 totalModuleFees = msg.value;
uint256 verificationFees = IInterchainDB(interchainDB).getInterchainFee(dstChainId, srcModules);
// TODO: should check msg.value >= totalModuleFees
uint256 executionFee = msg.value - verificationFees;

InterchainTransaction memory icTx = InterchainTransaction({
srcSender: TypeCasts.addressToBytes32(msg.sender),
Expand All @@ -131,11 +139,18 @@ contract InterchainClientV1 is Ownable, IInterchainClientV1 {
);
icTx.transactionId = transactionId;

uint256 dbWriterNonce = IInterchainDB(interchainDB).writeEntryWithVerification{value: totalModuleFees}(
icTx.dbWriterNonce = IInterchainDB(interchainDB).writeEntryWithVerification{value: verificationFees}(
icTx.dstChainId, icTx.transactionId, srcModules
);
icTx.dbWriterNonce = dbWriterNonce;

IExecutionService(srcExecutionService).requestExecution({
dstChainId: dstChainId,
// TODO: this should be encodedTx.length
txPayloadSize: message.length,
transactionId: transactionId,
executionFee: executionFee,
options: options
});
IExecutionFees(executionFees).addExecutionFee{value: executionFee}(dstChainId, transactionId);
emit InterchainTransactionSent(
icTx.srcSender,
icTx.srcChainId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IExecutor {
interface IExecutionService {
/// @notice Request the execution of an Interchain Transaction on a remote chain.
/// Note: the off-chain actor needs to fetch the transaction payload from the InterchainClient
/// event with the same transactionId, then execute the transaction on the remote chain:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
pragma solidity ^0.8.0;

interface IInterchainClientV1 {
/**
* @notice Sets the address of the ExecutionFees contract.
* @dev Only callable by the contract owner or an authorized account.
* @param executionFees_ The address of the ExecutionFees contract.
*/
function setExecutionFees(address executionFees_) external;

/**
* @notice Sets the linked client for a specific chain ID.
* @dev Stores the address of the linked client in a mapping with the chain ID as the key.
Expand All @@ -19,16 +26,22 @@ interface IInterchainClientV1 {

/**
* @notice Sends a message to another chain via the Interchain Communication Protocol.
* @dev Charges a fee for the message, which is payable upon calling this function.
* @param receiver The address of the receiver on the destination chain.
* @dev Charges a fee for the message, which is payable upon calling this function:
* - Verification fees: paid to every module that verifies the message.
* - Execution fee: paid to the executor that executes the message.
* Note: while a specific execution service is specified to request the execution of the message,
* any executor is able to execute the message on destination chain, earning the execution fee.
* @param dstChainId The chain ID of the destination chain.
* @param receiver The address of the receiver on the destination chain.
* @param srcExecutionService The address of the execution service to use for the message.
* @param message The message being sent.
* @param options Execution options for the message sent, encoded as bytes, currently primarily gas limit + native gas drop.
* @param srcModules The source modules involved in the message sending.
*/
function interchainSend(
bytes32 receiver,
uint256 dstChainId,
bytes32 receiver,
address srcExecutionService,
bytes calldata message,
bytes calldata options,
address[] calldata srcModules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ import {TypeCasts} from "../contracts/libs/TypeCasts.sol";

import {InterchainClientV1Harness} from "./harnesses/InterchainClientV1Harness.sol";

import {ExecutionFeesMock} from "./mocks/ExecutionFeesMock.sol";
import {ExecutionServiceMock} from "./mocks/ExecutionServiceMock.sol";
import {InterchainAppMock} from "./mocks/InterchainAppMock.sol";
import {InterchainModuleMock} from "./mocks/InterchainModuleMock.sol";

import {Test} from "forge-std/Test.sol";

contract InterchainClientV1Test is Test {
ExecutionFeesMock executionFees;
ExecutionServiceMock executionService;

InterchainClientV1Harness icClient;
InterchainDB icDB;
InterchainAppMock icApp;
Expand All @@ -31,9 +36,12 @@ contract InterchainClientV1Test is Test {

function setUp() public {
vm.startPrank(contractOwner);
executionFees = new ExecutionFeesMock();
executionService = new ExecutionServiceMock();
icClient = new InterchainClientV1Harness();
icDB = new InterchainDB();
icClient.setInterchainDB(address(icDB));
icClient.setExecutionFees(address(executionFees));

icModule = new InterchainModuleMock();
icApp = new InterchainAppMock();
Expand Down Expand Up @@ -110,7 +118,9 @@ contract InterchainClientV1Test is Test {
bytes32 transactionID = keccak256(
abi.encode(TypeCasts.addressToBytes32(msg.sender), block.chainid, receiver, DST_CHAIN_ID, message, nonce)
);
icClient.interchainSend{value: totalModuleFees}(receiver, DST_CHAIN_ID, message, options, srcModules);
icClient.interchainSend{value: totalModuleFees}(
DST_CHAIN_ID, receiver, address(executionService), message, options, srcModules
);
// TODO: should check the transaction ID?
transactionID;
}
Expand Down
16 changes: 16 additions & 0 deletions packages/contracts-communication/test/mocks/ExecutionFeesMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {IExecutionFees} from "../../contracts/interfaces/IExecutionFees.sol";

contract ExecutionFeesMock is IExecutionFees {
function addExecutionFee(uint256 dstChainId, bytes32 transactionId) external payable {}

function recordExecutor(uint256 dstChainId, bytes32 transactionId, address executor) external {}

function claimExecutionFees() external {}

function getAccumulatedRewards(address executor) external view returns (uint256 accumulated) {}

function getUnclaimedRewards(address executor) external view returns (uint256 unclaimed) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {IExecutionService} from "../../contracts/interfaces/IExecutionService.sol";

contract ExecutionServiceMock is IExecutionService {
function requestExecution(
uint256 dstChainId,
uint256 txPayloadSize,
bytes32 transactionId,
uint256 executionFee,
bytes memory options
)
external
{}

function getExecutionFee(
uint256 dstChainId,
uint256 txPayloadSize,
bytes memory options
)
external
view
returns (uint256)
{}
}
Loading