Skip to content

Commit

Permalink
introduce TokenGateway
Browse files Browse the repository at this point in the history
  • Loading branch information
seunlanlege committed Oct 9, 2023
1 parent daf41a7 commit a9a964f
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 163 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ jobs:
cargo +nightly test -p pallet-ismp --all-targets --all-features --locked
cargo +nightly test -p ismp-testsuite --all-targets --all-features --locked
cargo +nightly test -p ethereum-trie --all-features --locked
cd evm/forge && cargo test
- name: Clone eth-pos-devnet repository
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
[submodule "evm/lib/openzeppelin-contracts"]
path = evm/lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
[submodule "evm/lib/multi-chain-tokens"]
path = evm/lib/multi-chain-tokens
url = https://github.com/polytope-labs/multi-chain-tokens
1 change: 1 addition & 0 deletions evm/lib/multi-chain-tokens
Submodule multi-chain-tokens added at 01a46a
2 changes: 1 addition & 1 deletion evm/remappings.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ismp/=lib/ismp-solidity/src/
openzeppelin/=lib/openzeppelin-contracts/contracts/
solidity-merkle-trees/=lib/solidity-merkle-trees/src/
multichain-token/=lib/multichain-native-tokens/src/
multi-chain-tokens/=lib/multi-chain-tokens/src/
2 changes: 1 addition & 1 deletion evm/script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract DeployScript is Script {
// set the ismphost on the cross-chain governor
governor.setIsmpHost(hostAddress);
// deploy the ping module as well
// PingModule m = new PingModule{salt: salt}(hostAddress);
// PingModule m = new PingModule{salt: salt}(hostAddress);
vm.stopBroadcast();
}

Expand Down
4 changes: 3 additions & 1 deletion evm/src/EvmHost.sol
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ abstract contract EvmHost is IIsmpHost, Context {
* @param request - post dispatch request
*/
function dispatch(DispatchPost memory request) external {
uint64 timeout = request.timeout == 0 ? 0 : uint64(this.timestamp()) + uint64(Math.max(_hostParams.defaultTimeout, request.timeout));
uint64 timeout = request.timeout == 0
? 0
: uint64(this.timestamp()) + uint64(Math.max(_hostParams.defaultTimeout, request.timeout));
PostRequest memory _request = PostRequest({
source: host(),
dest: request.dest,
Expand Down
19 changes: 15 additions & 4 deletions evm/src/HandlerV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ contract HandlerV1 is IHandler, Context {
PostRequestLeaf memory leaf = request.requests[i];

require(leaf.request.dest.equals(host.host()), "IHandler: Invalid request destination");
require(leaf.request.timeoutTimestamp == 0 || leaf.request.timeoutTimestamp > host.timestamp(), "IHandler: Request timed out");
require(
leaf.request.timeoutTimestamp == 0 || leaf.request.timeoutTimestamp > host.timestamp(),
"IHandler: Request timed out"
);

bytes32 commitment = Message.hash(leaf.request);
require(!host.requestReceipts(commitment), "IHandler: Duplicate request");
Expand Down Expand Up @@ -149,7 +152,9 @@ contract HandlerV1 is IHandler, Context {

for (uint256 i = 0; i < timeoutsLength; i++) {
PostRequest memory request = message.timeouts[i];
require(request.timeoutTimestamp != 0 && state.timestamp > request.timeoutTimestamp, "Request not timed out");
require(
request.timeoutTimestamp != 0 && state.timestamp > request.timeoutTimestamp, "Request not timed out"
);

bytes32 requestCommitment = Message.hash(request);
require(host.requestCommitments(requestCommitment), "IHandler: Unknown request");
Expand Down Expand Up @@ -186,7 +191,10 @@ contract HandlerV1 is IHandler, Context {

bytes32 requestCommitment = Message.hash(request);
require(host.requestCommitments(requestCommitment), "IHandler: Unknown GET request");
require(request.timeoutTimestamp == 0 || request.timeoutTimestamp > host.timestamp(), "IHandler: GET request timed out");
require(
request.timeoutTimestamp == 0 || request.timeoutTimestamp > host.timestamp(),
"IHandler: GET request timed out"
);

StorageValue[] memory values =
MerklePatricia.ReadChildProofCheck(root, proof, request.keys, bytes.concat(requestCommitment));
Expand All @@ -209,7 +217,10 @@ contract HandlerV1 is IHandler, Context {
bytes32 requestCommitment = Message.hash(request);
require(host.requestCommitments(requestCommitment), "IHandler: Unknown request");

require(request.timeoutTimestamp != 0 && host.timestamp() > request.timeoutTimestamp, "IHandler: GET request not timed out");
require(
request.timeoutTimestamp != 0 && host.timestamp() > request.timeoutTimestamp,
"IHandler: GET request not timed out"
);
host.dispatchIncoming(request);
}
}
Expand Down
241 changes: 85 additions & 156 deletions evm/src/modules/TokenGateway.sol
Original file line number Diff line number Diff line change
@@ -1,158 +1,87 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
//
//// import "../IISMPRouter.sol";
//import "../interfaces/IISMPModule.sol";
//import "openzeppelin/utils/introspection/IERC165.sol";
//import "multichain-token/interfaces/IERC6160Ext20.sol";
//import {IERC_ACL_CORE} from "multichain-token/interfaces/IERCAclCore.sol";
//import "../interfaces/IIsmp.sol";
//import "../interfaces/IIsmpHost.sol";
//
////
//// Add supports interface for custom bride token
////
//error LengthMismatch();
//error ZeroAddress();
//error TokenNotMultiChainNative();
//error BurnerRoleMissing();
//error MinterRoleMissing();
//error AuthFailed();
//error NotDispatcher();
//
//contract TokenGateway is IIsmpModule {
// address admin;
// address host;
// bytes4 constant IERC6160Ext20ID = 0xbbb8b47e;
//
// bytes32 constant MINTER_ROLE = keccak256("MINTER ROLE");
// bytes32 constant BURNER_ROLE = keccak256("BURNER ROLE");
//
// mapping(uint256 => address) public chains;
// mapping(uint256 => address) public tokenIds;
//
// // auth modifier
// modifier auth() {
// if (msg.sender != admin) {
// revert AuthFailed();
// }
// _;
// }
//
// // restricts call to `dispatcher`
// modifier onlyDispatcher() {
// if (msg.sender != host) {
// revert NotDispatcher();
// }
// _;
// }
//
// constructor(
// address _host,
// uint256[] memory _SMids,
// address[] memory _SMaddresses,
// uint256[] memory _Tids,
// address[] memory _Taddresses
// ) {
// admin = msg.sender;
// host = _host;
// setStateMachineIds(_SMids, _SMaddresses);
// setTokenIds(_Tids, _Taddresses);
// }
//
// // sets the addresses for a given StateMachineId
// function setStateMachineIds(uint256[] memory _ids, address[] memory _addresses) public auth {
// if (_ids.length != _addresses.length) revert LengthMismatch();
// for (uint256 i = 0; i < _ids.length;) {
// address _address = _addresses[i];
// if (_address == address(0)) continue;
// chains[_ids[i]] = _addresses[i];
// unchecked {
// ++i;
// }
// }
// }
//
// // sets the Id for a bridge compatible token
// function setTokenIds(uint256[] memory _tokenIds, address[] memory _addresses) public auth {
// if (_tokenIds.length != _addresses.length) revert LengthMismatch();
// for (uint256 i = 0; i < _tokenIds.length;) {
// address _tokenAddress = _addresses[i];
// if (_tokenAddress == address(0)) revert ZeroAddress();
// if (!IERC_ACL_CORE(_tokenAddress).hasRole(BURNER_ROLE, address(this))) revert BurnerRoleMissing();
// if (!IERC_ACL_CORE(_tokenAddress).hasRole(MINTER_ROLE, address(this))) revert MinterRoleMissing();
// if (!IERC165(_tokenAddress).supportsInterface(IERC6160Ext20ID)) revert TokenNotMultiChainNative();
// tokenIds[_tokenIds[i]] = _tokenAddress;
// unchecked {
// ++i;
// }
// }
// }
//
// // The Gateway contract has to have the roles `MINTER` and `BURNER`.
// function send(
// bytes memory stateMachine,
// uint256 tokenId,
// uint256 amount,
// address to,
// bytes memory module,
// uint64 timestamp,
// uint64 gasLimit
// ) public {
// // USDC -> HyperUSDC(ERC6160)
// address tokenAddress = tokenIds[tokenId];
// // check permision at set token.
// IERC6160Ext20(tokenAddress).burn(msg.sender, amount, "");
// bytes memory data = abi.encodePacked(to, amount, tokenId);
// bytes memory source = IIsmpHost(host).host();
// DispatchPost memory postRequest = DispatchPost({
// destChain: stateMachine,
// from: source,
// to: module,
// body: data,
// timeoutTimestamp: timestamp,
// gaslimit: gasLimit
// });
// IIsmp(host).dispatch(postRequest);
// }
//
// function onAccept(PostRequest memory request) public onlyDispatcher {
// (address to, uint256 amount, uint256 tokenId) = _decodePackedData(request.body);
// address tokenAddress = tokenIds[tokenId];
//
// IERC6160Ext20(tokenAddress).mint(to, amount, "");
// }
//
// function onPostResponse(PostResponse memory response) public view onlyDispatcher {
// revert("Token gateway doesn't emit responses");
// }
//
// function onPostTimeout(PostRequest memory request) public onlyDispatcher {
// (address to, uint256 amount, uint256 tokenId) = _decodePackedData(request.body);
// address tokenAddress = tokenIds[tokenId];
//
// if (tokenAddress == address(0)) revert ZeroAddress();
//
// IERC6160Ext20(tokenAddress).mint(to, amount, "");
// }
//
// function onGetResponse(GetResponse memory response) public view onlyDispatcher {
// revert("Not implemented");
// }
//
// function onGetTimeout(GetRequest memory request) public view onlyDispatcher {
// revert("Not implemented");
// }
//
// function _decodePackedData(bytes memory data)
// internal
// pure
// returns (address to_, uint256 amount_, uint256 tokenId_)
// {
// assembly {
// to_ := div(mload(add(data, 32)), 0x1000000000000000000000000) // hex slicing to get first 20-bytes.
// amount_ := mload(add(data, 52))
// tokenId_ := mload(add(data, 84))
// }
// }
//}

import "ismp/interfaces/IIsmpModule.sol";
import "ismp/interfaces/IIsmp.sol";
import "multi-chain-tokens/interfaces/IERC6160Ext20.sol";

error ZeroAddress();

contract TokenGateway is IIsmpModule {
address private host;

mapping(uint256 => address) public chains;
mapping(uint256 => address) public tokenIds;

// restricts call to `dispatcher`
modifier onlyIsmpHost() {
if (msg.sender != host) {
revert("Unauthorized call");
}
_;
}

constructor(address _host) {
host = _host;
}

// The Gateway contract has to have the roles `MINTER` and `BURNER`.
function send(
uint256 amount,
address to,
bytes memory dest,
address tokenContract,
address gateway,
uint64 gasLimit
) public {
address from = msg.sender;
IERC6160Ext20(tokenContract).burn(from, amount, "");
bytes memory data = abi.encodePacked(from, to, amount, tokenContract);
DispatchPost memory postRequest = DispatchPost({
dest: dest,
to: abi.encodePacked(gateway),
body: data,
timeout: 60 * 60, // seconds
gaslimit: gasLimit
});
IIsmp(host).dispatch(postRequest);
}

function onAccept(PostRequest memory request) public onlyIsmpHost {
(address _from, address to, uint256 amount, address tokenContract) = _decodePackedData(request.body);

IERC6160Ext20(tokenContract).mint(to, amount, "");
}

function onPostTimeout(PostRequest memory request) public onlyIsmpHost {
(address from, address _to, uint256 amount, address tokenContract) = _decodePackedData(request.body);

IERC6160Ext20(tokenContract).mint(from, amount, "");
}

function onPostResponse(PostResponse memory response) public view onlyIsmpHost {
revert("Token gateway doesn't emit responses");
}

function onGetResponse(GetResponse memory response) public view onlyIsmpHost {
revert("Token gateway doesn't emit Get Requests");
}

function onGetTimeout(GetRequest memory request) public view onlyIsmpHost {
revert("Token gateway doesn't emit Get Requests");
}

function _decodePackedData(bytes memory data)
internal
pure
returns (address from_, address to_, uint256 amount_, address tokenContract_)
{
// todo:
assembly {
from_ := div(mload(add(data, 32)), 0x1000000000000000000000000) // hex slicing to get first 20-bytes.
to_ := div(mload(add(data, 32)), 0x1000000000000000000000000) // hex slicing to get first 20-bytes.
amount_ := mload(add(data, 52))
tokenContract_ := mload(add(data, 84))
}
}
}

0 comments on commit a9a964f

Please sign in to comment.