diff --git a/contracts/scripts/DeployLocal.sol b/contracts/scripts/DeployLocal.sol index 441ab9926c..da06bd9fcc 100644 --- a/contracts/scripts/DeployLocal.sol +++ b/contracts/scripts/DeployLocal.sol @@ -96,15 +96,11 @@ contract DeployLocal is Script { // Deploy WETH for testing new WETH9(); - // Fund the sovereign account for the BridgeHub parachain. Used to reward relayers + // Fund the gateway proxy contract. Used to reward relayers // of messages originating from BridgeHub - uint256 initialDeposit = vm.envUint("BRIDGE_HUB_INITIAL_DEPOSIT"); + uint256 initialDeposit = vm.envUint("GATEWAY_PROXY_INITIAL_DEPOSIT"); - address bridgeHubAgent = IGateway(address(gateway)).agentOf(bridgeHubAgentID); - address assetHubAgent = IGateway(address(gateway)).agentOf(assetHubAgentID); - - payable(bridgeHubAgent).safeNativeTransfer(initialDeposit); - payable(assetHubAgent).safeNativeTransfer(initialDeposit); + payable(gateway).safeNativeTransfer(initialDeposit); // Deploy MockGatewayV2 for testing new MockGatewayV2(); diff --git a/contracts/scripts/FundAgent.sol b/contracts/scripts/FundGateway.sol similarity index 66% rename from contracts/scripts/FundAgent.sol rename to contracts/scripts/FundGateway.sol index 37eedceb6b..6b67bc4484 100644 --- a/contracts/scripts/FundAgent.sol +++ b/contracts/scripts/FundGateway.sol @@ -15,7 +15,7 @@ import {ParaID} from "../src/Types.sol"; import {SafeNativeTransfer} from "../src/utils/SafeTransfer.sol"; import {stdJson} from "forge-std/StdJson.sol"; -contract FundAgent is Script { +contract FundGateway is Script { using SafeNativeTransfer for address payable; using stdJson for string; @@ -26,17 +26,10 @@ contract FundAgent is Script { address deployer = vm.rememberKey(privateKey); vm.startBroadcast(deployer); - uint256 initialDeposit = vm.envUint("BRIDGE_HUB_INITIAL_DEPOSIT"); + uint256 initialDeposit = vm.envUint("GATEWAY_PROXY_INITIAL_DEPOSIT"); address gatewayAddress = vm.envAddress("GATEWAY_PROXY_CONTRACT"); - bytes32 bridgeHubAgentID = vm.envBytes32("BRIDGE_HUB_AGENT_ID"); - bytes32 assetHubAgentID = vm.envBytes32("ASSET_HUB_AGENT_ID"); - - address bridgeHubAgent = IGateway(gatewayAddress).agentOf(bridgeHubAgentID); - address assetHubAgent = IGateway(gatewayAddress).agentOf(assetHubAgentID); - - payable(bridgeHubAgent).safeNativeTransfer(initialDeposit); - payable(assetHubAgent).safeNativeTransfer(initialDeposit); + payable(gatewayAddress).safeNativeTransfer(initialDeposit); vm.stopBroadcast(); } diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index 11fa5c12c9..ab3c81700d 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -13,6 +13,7 @@ import {CoreStorage} from "./storage/CoreStorage.sol"; import {SubstrateTypes} from "./SubstrateTypes.sol"; import {ParaID, MultiAddress, Ticket, Costs} from "./Types.sol"; import {Address} from "./utils/Address.sol"; +import {SafeNativeTransfer} from "./utils/SafeTransfer.sol"; import {AgentExecutor} from "./AgentExecutor.sol"; import {Agent} from "./Agent.sol"; import {Call} from "./utils/Call.sol"; @@ -21,6 +22,7 @@ import {Token} from "./Token.sol"; /// @title Library for implementing Ethereum->Polkadot ERC20 transfers. library Assets { using Address for address; + using SafeNativeTransfer for address payable; using SafeTokenTransferFrom for IERC20; /* Errors */ @@ -110,15 +112,17 @@ library Assets { TokenInfo storage info = $.tokenRegistry[token]; - if (!info.isRegistered) { - revert TokenNotRegistered(); - } - if (info.foreignID == bytes32(0)) { + if (!info.isRegistered && token != address(0)) { + revert TokenNotRegistered(); + } return _sendNativeToken( token, sender, destinationChain, destinationAddress, destinationChainFee, maxDestinationChainFee, amount ); } else { + if (!info.isRegistered) { + revert TokenNotRegistered(); + } return _sendForeignToken( info.foreignID, token, @@ -144,7 +148,18 @@ library Assets { AssetsStorage.Layout storage $ = AssetsStorage.layout(); // Lock the funds into AssetHub's agent contract - _transferToAgent($.assetHubAgent, token, sender, amount); + if (token != address(0)) { + // ERC20 + _transferToAgent($.assetHubAgent, token, sender, amount); + ticket.etherAmount = 0; + } else { + // Native ETH + if (msg.value < amount) { + revert TokenAmountTooLow(); + } + payable($.assetHubAgent).safeNativeTransfer(amount); + ticket.etherAmount = amount; + } ticket.dest = $.assetHubParaID; ticket.costs = _sendTokenCosts(destinationChain, destinationChainFee, maxDestinationChainFee); @@ -211,6 +226,7 @@ library Assets { ticket.dest = $.assetHubParaID; ticket.costs = _sendTokenCosts(destinationChain, destinationChainFee, maxDestinationChainFee); + ticket.etherAmount = 0; // Construct a message payload if (destinationChain == $.assetHubParaID && destinationAddress.isAddress32()) { @@ -262,6 +278,7 @@ library Assets { ticket.dest = $.assetHubParaID; ticket.costs = _registerTokenCosts(); ticket.payload = SubstrateTypes.RegisterToken(token, $.assetHubCreateAssetFee); + ticket.etherAmount = 0; emit IGateway.TokenRegistrationSent(token); } diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 685627fe34..b0c234e883 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -99,6 +99,7 @@ contract Gateway is IGateway, IInitializable, IUpgradable { error InvalidAgentExecutionPayload(); error InvalidConstructorParams(); error TokenNotRegistered(); + error TokenAmountTooLow(); // Message handlers can only be dispatched by the gateway itself modifier onlySelf() { @@ -240,11 +241,11 @@ contract Gateway is IGateway, IInitializable, IUpgradable { // Add the reward to the refund amount. If the sum is more than the funds available // in the channel agent, then reduce the total amount - uint256 amount = Math.min(refund + message.reward, address(channel.agent).balance); + uint256 amount = Math.min(refund + message.reward, address(this).balance); - // Do the payment if there funds available in the agent + // Do the payment if there funds available in the gateway if (amount > _dustThreshold()) { - _transferNativeFromAgent(channel.agent, payable(msg.sender), amount); + payable(msg.sender).safeNativeTransfer(amount); } emit IGateway.InboundMessageDispatched(message.channelID, message.nonce, message.id, success); @@ -530,18 +531,17 @@ contract Gateway is IGateway, IInitializable, IUpgradable { uint256 fee = _calculateFee(ticket.costs); // Ensure the user has enough funds for this message to be accepted - if (msg.value < fee) { + uint256 totalEther = fee + ticket.etherAmount; + if (msg.value < totalEther) { revert FeePaymentToLow(); } channel.outboundNonce = channel.outboundNonce + 1; - // Deposit total fee into agent's contract - payable(channel.agent).safeNativeTransfer(fee); - + // The fee is already collected into the gateway contract // Reimburse excess fee payment - if (msg.value > fee) { - payable(msg.sender).safeNativeTransfer(msg.value - fee); + if (msg.value > totalEther) { + payable(msg.sender).safeNativeTransfer(msg.value - totalEther); } // Generate a unique ID for this message diff --git a/contracts/src/Types.sol b/contracts/src/Types.sol index 02e8bd0acc..d757d2b7d0 100644 --- a/contracts/src/Types.sol +++ b/contracts/src/Types.sol @@ -107,6 +107,7 @@ struct Ticket { ParaID dest; Costs costs; bytes payload; + uint128 etherAmount; } struct TokenInfo { diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 96705c5c9f..d3abd56545 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -986,7 +986,7 @@ contract GatewayTest is Test { vm.expectRevert(Assets.TokenNotRegistered.selector); - IGateway(address(gateway)).sendToken{value: 0.1 ether}(address(0x0), destPara, recipientAddress32, 1, 1); + IGateway(address(gateway)).sendToken{value: 0.1 ether}(address(0x1), destPara, recipientAddress32, 1, 1); } function testSendTokenFromNotMintedAccountWillFail() public { diff --git a/web/packages/test/scripts/fund-agent.sh b/web/packages/test/scripts/fund-gateway.sh similarity index 63% rename from web/packages/test/scripts/fund-agent.sh rename to web/packages/test/scripts/fund-gateway.sh index e094e9c483..453864f49a 100755 --- a/web/packages/test/scripts/fund-agent.sh +++ b/web/packages/test/scripts/fund-gateway.sh @@ -3,19 +3,19 @@ set -eu source scripts/set-env.sh -fund_agent() { +fund_gateway() { pushd "$contract_dir" forge script \ --rpc-url $eth_endpoint_http \ --broadcast \ -vvv \ - scripts/FundAgent.sol:FundAgent + scripts/FundGateway.sol:FundGateway popd - echo "Fund agent success!" + echo "Fund gateway success!" } if [ -z "${from_start_services:-}" ]; then - echo "Funding agent" - fund_agent + echo "Funding gateway" + fund_gateway fi diff --git a/web/packages/test/scripts/set-env.sh b/web/packages/test/scripts/set-env.sh index 1ab1d6c278..2e6ff5f8c7 100755 --- a/web/packages/test/scripts/set-env.sh +++ b/web/packages/test/scripts/set-env.sh @@ -110,7 +110,7 @@ export LOCAL_REWARD="${LOCAL_REWARD:-1000000000000}" export REMOTE_REWARD="${REMOTE_REWARD:-1000000000000000}" ## Vault -export BRIDGE_HUB_INITIAL_DEPOSIT="${ETH_BRIDGE_HUB_INITIAL_DEPOSIT:-10000000000000000000}" +export GATEWAY_PROXY_INITIAL_DEPOSIT="${GATEWAY_PROXY_INITIAL_DEPOSIT:-10000000000000000000}" export GATEWAY_STORAGE_KEY="${GATEWAY_STORAGE_KEY:-0xaed97c7854d601808b98ae43079dafb3}" export GATEWAY_PROXY_CONTRACT="${GATEWAY_PROXY_CONTRACT:-0x87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d}"