diff --git a/contracts/src/Assets.sol b/contracts/src/Assets.sol index 4c591c674a..a1ccac2ff5 100644 --- a/contracts/src/Assets.sol +++ b/contracts/src/Assets.sol @@ -23,6 +23,7 @@ library Assets { error InvalidDestination(); error TokenNotRegistered(); error Unsupported(); + error InvalidDestinationFee(); function isTokenRegistered(address token) external view returns (bool) { return AssetsStorage.layout().tokenRegistry[token].isRegistered; @@ -106,6 +107,9 @@ library Assets { revert Unsupported(); } } else { + if (destinationChainFee == 0) { + revert InvalidDestinationFee(); + } // The funds will be minted into sovereign account of the destination parachain on AssetHub, // and then reserve-transferred to the receiver's account on the destination parachain. if (destinationAddress.isAddress32()) { diff --git a/contracts/test/Gateway.t.sol b/contracts/test/Gateway.t.sol index 73a6e5fda2..604e1a9d3f 100644 --- a/contracts/test/Gateway.t.sol +++ b/contracts/test/Gateway.t.sol @@ -884,4 +884,21 @@ contract GatewayTest is Test { fee = IGateway(address(gateway)).quoteRegisterTokenFee(); assertEq(fee, 10000000000000000); } + + function testSendTokenToForeignDestWithInvalidFee() public { + // Let gateway lock up to 1 tokens + token.approve(address(gateway), 1); + + // Multilocation for recipient + ParaID destPara = ParaID.wrap(2043); + + // register token first + uint256 fee = IGateway(address(gateway)).quoteRegisterTokenFee(); + IGateway(address(gateway)).registerToken{value: fee}(address(token)); + + fee = IGateway(address(gateway)).quoteSendTokenFee(address(token), destPara, 0); + + vm.expectRevert(Assets.InvalidDestinationFee.selector); + IGateway(address(gateway)).sendToken{value: fee}(address(token), destPara, recipientAddress32, 0, 1); + } }