Skip to content

Commit

Permalink
UPDATE: made modifications to TokenGateway (#149)
Browse files Browse the repository at this point in the history
Co-authored-by: Seun Lanlege <[email protected]>
  • Loading branch information
casweeney and seunlanlege authored Apr 3, 2024
1 parent 21c42e0 commit d42ff19
Show file tree
Hide file tree
Showing 21 changed files with 96 additions and 100 deletions.
4 changes: 2 additions & 2 deletions evm/integration-tests/src/tests/beefy_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ async fn beefy_consensus_client_test() -> Result<(), anyhow::Error> {
"Skipping outdated commitment \n Received signed commitmment with validator_set_id: {:?}\n Current authority set id: {:#?}\n Next authority set id: {:?}\n",
signed_commitment.commitment.validator_set_id, consensus_state.current_authority_set.id, consensus_state.current_authority_set.id
);
continue
continue;
},
_ => {},
};
Expand All @@ -147,7 +147,7 @@ async fn beefy_consensus_client_test() -> Result<(), anyhow::Error> {
if consensus_proof.relay.signed_commitment.commitment.block_number ==
consensus_state.latest_height
{
continue
continue;
}

let (new_state, intermediates) = contract
Expand Down
2 changes: 1 addition & 1 deletion evm/lib/ismp-solidity
7 changes: 1 addition & 6 deletions evm/script/DeployGateway.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,7 @@ contract DeployScript is Script {
feeToken.grantRole(BURNER_ROLE, address(gateway));

Asset[] memory assets = new Asset[](1);
assets[0] = Asset({
localIdentifier: keccak256("USD.h"),
foreignIdentifier: keccak256("USD.h"),
erc20: address(0),
erc6160: address(feeToken)
});
assets[0] = Asset({identifier: keccak256("USD.h"), erc20: address(0), erc6160: address(feeToken)});

gateway.init(
InitParams({
Expand Down
7 changes: 1 addition & 6 deletions evm/script/DeployIsmp.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,7 @@ contract DeployScript is Script {
feeToken.grantRole(MINTER_ROLE, address(faucet));

Asset[] memory assets = new Asset[](1);
assets[0] = Asset({
localIdentifier: keccak256("USD.h"),
foreignIdentifier: keccak256("USD.h"),
erc20: address(0),
erc6160: address(feeToken)
});
assets[0] = Asset({identifier: keccak256("USD.h"), erc20: address(0), erc6160: address(feeToken)});

// initialize gateway
gateway.init(
Expand Down
40 changes: 21 additions & 19 deletions evm/src/hosts/EvmHost.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct HostParams {
uint256 defaultTimeout;
// base fee for GET requests
uint256 baseGetRequestFee;
// cost of cross-chain requests in $DAI per byte
// cost of cross-chain requests in the fee token per byte
uint256 perByteFee;
// The fee token contract. This will typically be DAI.
// but we allow it to be configurable to prevent future regrets.
Expand Down Expand Up @@ -194,9 +194,9 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
function chainId() public virtual returns (uint256);

/**
* @return the address of the DAI ERC-20 contract on this state machine
* @return the address of the fee token ERC-20 contract on this state machine
*/
function dai() public view returns (address) {
function feeToken() public view returns (address) {
return _hostParams.feeTokenAddress;
}

Expand Down Expand Up @@ -353,7 +353,7 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
* @param params, the parameters for withdrawal
*/
function withdraw(WithdrawParams memory params) external onlyManager {
require(IERC20(dai()).transfer(params.beneficiary, params.amount), "Host has an insufficient balance");
require(IERC20(feeToken()).transfer(params.beneficiary, params.amount), "Host has an insufficient balance");
}

/**
Expand Down Expand Up @@ -472,7 +472,7 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
}

// Charge the originating user/application
require(IERC20(dai()).transferFrom(meta.sender, address(this), fee), "Origin has insufficient funds");
require(IERC20(feeToken()).transferFrom(meta.sender, address(this), fee), "Origin has insufficient funds");

address origin = _bytesToAddress(response.request.from);
(bool success,) = address(origin).call(abi.encodeWithSelector(IIsmpModule.onGetResponse.selector, response));
Expand All @@ -482,7 +482,7 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
// don't commit the full response object because, it's unused.
_responseReceipts[commitment] = ResponseReceipt({relayer: tx.origin, responseCommitment: bytes32(0)});
if (meta.fee > 0) {
require(IERC20(dai()).transfer(tx.origin, meta.fee), "EvmHost has insufficient funds");
require(IERC20(feeToken()).transfer(tx.origin, meta.fee), "EvmHost has insufficient funds");
}
emit PostResponseHandled({commitment: commitment, relayer: tx.origin});
}
Expand All @@ -504,7 +504,7 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
delete _requestCommitments[commitment];

// refund relayer fee
IERC20(dai()).transfer(meta.sender, meta.fee);
IERC20(feeToken()).transfer(meta.sender, meta.fee);
}
}

Expand All @@ -525,7 +525,7 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
delete _requestCommitments[commitment];

// refund relayer fee
IERC20(dai()).transfer(meta.sender, meta.fee);
IERC20(feeToken()).transfer(meta.sender, meta.fee);
}
}

Expand All @@ -547,17 +547,17 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
delete _responded[response.request.hash()];

// refund relayer fee
IERC20(dai()).transfer(meta.sender, meta.fee);
IERC20(feeToken()).transfer(meta.sender, meta.fee);
}
}

/**
* @dev Dispatch a POST request to the hyperbridge
* @param post - post request
*/
function dispatch(DispatchPost memory post) external {
function dispatch(DispatchPost memory post) external returns (bytes32 commitment) {
uint256 fee = (_hostParams.perByteFee * post.body.length) + post.fee;
require(IERC20(dai()).transferFrom(post.payer, address(this), fee), "Payer has insufficient funds");
require(IERC20(feeToken()).transferFrom(post.payer, address(this), fee), "Payer has insufficient funds");

// adjust the timeout
uint64 timeout = post.timeout == 0
Expand All @@ -575,8 +575,8 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
});

// make the commitment
_requestCommitments[request.hash()] = FeeMetadata({sender: post.payer, fee: post.fee});

bytes32 commitment = request.hash();
_requestCommitments[commitment] = FeeMetadata({sender: post.payer, fee: post.fee});
emit PostRequestEvent(
request.source,
request.dest,
Expand All @@ -594,9 +594,9 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
* @dev Dispatch a get request to the hyperbridge
* @param get - get request
*/
function dispatch(DispatchGet memory get) external {
function dispatch(DispatchGet memory get) external returns (bytes32 commitment) {
uint256 fee = _hostParams.baseGetRequestFee + get.fee;
require(IERC20(dai()).transferFrom(get.payer, address(this), fee), "Payer has insufficient funds");
require(IERC20(feeToken()).transferFrom(get.payer, address(this), fee), "Payer has insufficient funds");

// adjust the timeout
uint64 timeout =
Expand All @@ -614,7 +614,8 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
});

// make the commitment
_requestCommitments[request.hash()] = FeeMetadata({sender: get.payer, fee: get.fee});
bytes32 commitment = request.hash();
_requestCommitments[commitment] = FeeMetadata({sender: get.payer, fee: get.fee});
emit GetRequestEvent(
request.source,
request.dest,
Expand All @@ -632,7 +633,7 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
* @dev Dispatch a response to the hyperbridge
* @param post - post response
*/
function dispatch(DispatchPostResponse memory post) external {
function dispatch(DispatchPostResponse memory post) external returns (bytes32 commitment) {
bytes32 receipt = post.request.hash();

// known request?
Expand All @@ -645,7 +646,7 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
require(!_responded[receipt], "EvmHost: Duplicate Response");

uint256 fee = (_hostParams.perByteFee * post.response.length) + post.fee;
require(IERC20(dai()).transferFrom(post.payer, address(this), fee), "Payer has insufficient funds");
require(IERC20(feeToken()).transferFrom(post.payer, address(this), fee), "Payer has insufficient funds");

// adjust the timeout
uint64 timeout = post.timeout == 0
Expand All @@ -657,8 +658,9 @@ abstract contract EvmHost is IIsmpHost, IHostManager, Context {
timeoutTimestamp: timeout,
gaslimit: post.gaslimit
});
bytes32 commitment = response.hash();
FeeMetadata memory meta = FeeMetadata({fee: post.fee, sender: post.payer});
_responseCommitments[response.hash()] = meta;
_responseCommitments[commitment] = meta;
_responded[receipt] = true;

emit PostResponseEvent(
Expand Down
49 changes: 28 additions & 21 deletions evm/src/modules/TokenGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct TeleportParams {
// Relayer fee
uint256 fee;
// The token identifier
bytes32 tokenId;
bytes32 assetId;
// Redeem Erc20 on the destination?
bool redeem;
// recipient address
Expand All @@ -34,7 +34,7 @@ struct Body {
// amount to be sent
uint256 amount;
// The token identifier
bytes32 tokenId;
bytes32 assetId;
// flag to redeem the erc20 asset on the destination
bool redeem;
// sender address
Expand Down Expand Up @@ -63,10 +63,8 @@ struct Asset {
address erc20;
/// ERC6160 token contract address for the asset
address erc6160;
/// Asset's local identifier
bytes32 localIdentifier;
/// Asset's foreign identifier
bytes32 foreignIdentifier;
/// Asset's identifier
bytes32 identifier;
}

enum OnAcceptActions
Expand All @@ -93,6 +91,8 @@ uint256 constant BODY_BYTES_SIZE = 161;
/// The TokenGateway allows users send either ERC20 or ERC6160 tokens
/// using Hyperbridge as a message-passing layer.
contract TokenGateway is BaseIsmpModule {
event LiquidityProvided(address relayer, uint256 amount);

using Bytes for bytes;

/// StateMachine identifier for hyperbridge
Expand All @@ -112,11 +112,10 @@ contract TokenGateway is BaseIsmpModule {
mapping(bytes32 => address) private _erc6160s;
// mapping of token identifier to erc20 contracts
mapping(bytes32 => address) private _erc20s;
// foreign to local asset identifier mapping
mapping(bytes32 => bytes32) private _assets;

// User has received some assets, source chain & nonce
event AssetReceived(bytes source, uint256 nonce);
event Teleport(address from, address to, uint256 amount, bool redeem, bytes32 requestCommitment);

// restricts call to `IIsmpHost`
modifier onlyIsmpHost() {
Expand Down Expand Up @@ -158,9 +157,9 @@ contract TokenGateway is BaseIsmpModule {
require(params.feeToken != address(0), "Fee token not selected");

address from = msg.sender;
address erc20 = _erc20s[params.tokenId];
address erc6160 = _erc6160s[params.tokenId];
address feeToken = IIsmpHost(_host).dai();
address erc20 = _erc20s[params.assetId];
address erc6160 = _erc6160s[params.assetId];
address feeToken = IIsmpHost(_host).feeToken();

if (erc20 != address(0) && !params.redeem) {
require(IERC20(erc20).transferFrom(from, address(this), params.amount), "Insufficient user balance");
Expand All @@ -181,7 +180,7 @@ contract TokenGateway is BaseIsmpModule {
}

bytes memory data = abi.encode(
Body({from: from, to: params.to, amount: params.amount, tokenId: params.tokenId, redeem: params.redeem})
Body({from: from, to: params.to, amount: params.amount, assetId: params.assetId, redeem: params.redeem})
);

DispatchPost memory request = DispatchPost({
Expand All @@ -196,7 +195,15 @@ contract TokenGateway is BaseIsmpModule {
});

// Your money is now on its way
IDispatcher(_host).dispatch(request);
bytes32 commitment = IDispatcher(_host).dispatch(request);

emit Teleport({
from: from,
to: params.to,
amount: params.amount,
redeem: params.redeem,
requestCommitment: commitment
});
}

function onAccept(PostRequest calldata request) external override onlyIsmpHost {
Expand All @@ -215,8 +222,8 @@ contract TokenGateway is BaseIsmpModule {
// The money could not be sent, this would allow users to get their money back.
Body memory body = abi.decode(request.body[1:], (Body));

address erc20 = _erc20s[body.tokenId];
address erc6160 = _erc6160s[body.tokenId];
address erc20 = _erc20s[body.assetId];
address erc6160 = _erc6160s[body.assetId];

if (erc20 != address(0) && !body.redeem) {
require(IERC20(erc20).transfer(body.from, body.amount), "Gateway: Insufficient Balance");
Expand All @@ -232,9 +239,8 @@ contract TokenGateway is BaseIsmpModule {
require(request.from.equals(abi.encodePacked(address(this))), "Unauthorized request");
Body memory body = abi.decode(request.body[1:], (Body));

bytes32 localAsset = _assets[body.tokenId];
address erc20 = _erc20s[localAsset];
address erc6160 = _erc6160s[localAsset];
address erc20 = _erc20s[body.assetId];
address erc6160 = _erc6160s[body.assetId];

if (erc20 != address(0) && body.redeem) {
// a relayer/user is redeeming the native asset
Expand All @@ -253,6 +259,8 @@ contract TokenGateway is BaseIsmpModule {
"Gateway: Insufficient relayer balance"
);

emit LiquidityProvided(tx.origin, _amountToTransfer);

// hand the relayer the erc6160, so they can redeem on the source chain
IERC6160Ext20(erc6160).mint(tx.origin, body.amount, "");
} else if (erc6160 != address(0)) {
Expand Down Expand Up @@ -322,9 +330,8 @@ contract TokenGateway is BaseIsmpModule {
for (uint256 i = 0; i < length; i++) {
Asset memory asset = assets[i];

_erc20s[asset.localIdentifier] = asset.erc20;
_erc6160s[asset.localIdentifier] = asset.erc6160;
_assets[asset.foreignIdentifier] = asset.localIdentifier;
_erc20s[asset.identifier] = asset.erc20;
_erc6160s[asset.identifier] = asset.erc6160;
}
}
}
7 changes: 1 addition & 6 deletions evm/test/BaseTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,7 @@ contract BaseTest is Test {
manager.setIsmpHost(address(host));
gateway = new TokenGateway(address(this));
Asset[] memory assets = new Asset[](1);
assets[0] = Asset({
localIdentifier: keccak256("USD.h"),
foreignIdentifier: keccak256("USD.h"),
erc20: address(0),
erc6160: address(feeToken)
});
assets[0] = Asset({identifier: keccak256("USD.h"), erc20: address(0), erc6160: address(feeToken)});

gateway.init(
InitParams({
Expand Down
Loading

0 comments on commit d42ff19

Please sign in to comment.