Skip to content

Commit

Permalink
make max fee immutable
Browse files Browse the repository at this point in the history
  • Loading branch information
alistair-singh committed Apr 12, 2024
1 parent 8d85828 commit c0d9b6b
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 34 deletions.
22 changes: 12 additions & 10 deletions contracts/src/Assets.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,22 @@ library Assets {
IERC20(token).safeTransferFrom(sender, agent, amount);
}

function sendTokenCosts(address token, ParaID destinationChain, uint128 destinationChainFee)
external
view
returns (Costs memory costs)
{
function sendTokenCosts(
address token,
ParaID destinationChain,
uint128 destinationChainFee,
uint128 maxDestinationChainFee
) external view returns (Costs memory costs) {
AssetsStorage.Layout storage $ = AssetsStorage.layout();
TokenInfo storage info = $.tokenRegistry[token];
if (!info.isRegistered) {
revert TokenNotRegistered();
}

return _sendTokenCosts(destinationChain, destinationChainFee);
return _sendTokenCosts(destinationChain, destinationChainFee, maxDestinationChainFee);
}

function _sendTokenCosts(ParaID destinationChain, uint128 destinationChainFee)
function _sendTokenCosts(ParaID destinationChain, uint128 destinationChainFee, uint128 maxDestinationChainFee)
internal
view
returns (Costs memory costs)
Expand All @@ -66,7 +67,7 @@ library Assets {
costs.foreign = $.assetHubReserveTransferFee;
} else {
// Destination fee cannot be zero. MultiAssets are not allowed to be zero in xcm v4.
if (destinationChainFee == 0 || destinationChainFee > $.destinationMaxTransferFee) {
if (destinationChainFee == 0 || destinationChainFee > maxDestinationChainFee) {
revert InvalidDestinationFee();
}

Expand All @@ -84,7 +85,8 @@ library Assets {
ParaID destinationChain,
MultiAddress calldata destinationAddress,
uint128 destinationChainFee,
uint128 amount
uint128 amount,
uint128 maxDestinationChainFee
) external returns (Ticket memory ticket) {
AssetsStorage.Layout storage $ = AssetsStorage.layout();

Expand All @@ -97,7 +99,7 @@ library Assets {
_transferToAgent($.assetHubAgent, token, sender, amount);

ticket.dest = $.assetHubParaID;
ticket.costs = _sendTokenCosts(destinationChain, destinationChainFee);
ticket.costs = _sendTokenCosts(destinationChain, destinationChainFee, maxDestinationChainFee);

// Construct a message payload
if (destinationChain == $.assetHubParaID) {
Expand Down
10 changes: 9 additions & 1 deletion contracts/src/DeployGatewayLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@ contract DeployGatewayLogic is Script {
bytes32 bridgeHubAgentID = vm.envBytes32("BRIDGE_HUB_AGENT_ID");

uint8 foreignTokenDecimals = uint8(vm.envUint("FOREIGN_TOKEN_DECIMALS"));
uint128 destinationMaxTransferFee = uint128(vm.envUint("RESERVE_TRANSFER_MAX_DESTINATION_FEE"));

AgentExecutor executor = new AgentExecutor();
new Gateway(address(beefyClient), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals);
new Gateway(
address(beefyClient),
address(executor),
bridgeHubParaID,
bridgeHubAgentID,
foreignTokenDecimals,
destinationMaxTransferFee
);

vm.stopBroadcast();
}
Expand Down
9 changes: 7 additions & 2 deletions contracts/src/DeployScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,16 @@ contract DeployScript is Script {
bytes32 assetHubAgentID = vm.envBytes32("ASSET_HUB_AGENT_ID");

uint8 foreignTokenDecimals = uint8(vm.envUint("FOREIGN_TOKEN_DECIMALS"));
uint128 destinationMaxTransferFee = uint128(vm.envUint("RESERVE_TRANSFER_MAX_DESTINATION_FEE"));

AgentExecutor executor = new AgentExecutor();
Gateway gatewayLogic = new Gateway(
address(beefyClient), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals
address(beefyClient),
address(executor),
bridgeHubParaID,
bridgeHubAgentID,
foreignTokenDecimals,
destinationMaxTransferFee
);

bool rejectOutboundMessages = vm.envBool("REJECT_OUTBOUND_MESSAGES");
Expand All @@ -80,7 +86,6 @@ contract DeployScript is Script {
assetHubAgentID: assetHubAgentID,
assetHubCreateAssetFee: uint128(vm.envUint("CREATE_ASSET_FEE")),
assetHubReserveTransferFee: uint128(vm.envUint("RESERVE_TRANSFER_FEE")),
destinationMaxTransferFee: uint128(vm.envUint("RESERVE_TRANSFER_MAX_DESTINATION_FEE")),
exchangeRate: ud60x18(vm.envUint("EXCHANGE_RATE")),
multiplier: ud60x18(vm.envUint("FEE_MULTIPLIER"))
});
Expand Down
22 changes: 17 additions & 5 deletions contracts/src/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ contract Gateway is IGateway, IInitializable {
// 2. Calling implementation function
uint256 DISPATCH_OVERHEAD_GAS = 10_000;

// The maximum fee that can be sent to a destination parachain to pay for execution (DOT)
uint128 internal immutable MAX_DESTINATION_TRANSFER_FEE;

uint8 internal immutable FOREIGN_TOKEN_DECIMALS;

error InvalidProof();
Expand Down Expand Up @@ -101,7 +104,8 @@ contract Gateway is IGateway, IInitializable {
address agentExecutor,
ParaID bridgeHubParaID,
bytes32 bridgeHubAgentID,
uint8 foreignTokenDecimals
uint8 foreignTokenDecimals,
uint128 destinationMaxTransferFee
) {
if (bridgeHubParaID == ParaID.wrap(0) || bridgeHubAgentID == 0) {
revert InvalidConstructorParams();
Expand All @@ -113,6 +117,7 @@ contract Gateway is IGateway, IInitializable {
BRIDGE_HUB_PARA_ID = bridgeHubParaID;
BRIDGE_HUB_AGENT_ID = bridgeHubAgentID;
FOREIGN_TOKEN_DECIMALS = foreignTokenDecimals;
MAX_DESTINATION_TRANSFER_FEE = destinationMaxTransferFee;
}

/// @dev Submit a message from Polkadot for verification and dispatch
Expand Down Expand Up @@ -417,7 +422,8 @@ contract Gateway is IGateway, IInitializable {
view
returns (uint256)
{
return _calculateFee(Assets.sendTokenCosts(token, destinationChain, destinationFee));
return
_calculateFee(Assets.sendTokenCosts(token, destinationChain, destinationFee, MAX_DESTINATION_TRANSFER_FEE));
}

// Transfer ERC20 tokens to a Polkadot parachain
Expand All @@ -429,7 +435,15 @@ contract Gateway is IGateway, IInitializable {
uint128 amount
) external payable {
_submitOutbound(
Assets.sendToken(token, msg.sender, destinationChain, destinationAddress, destinationFee, amount)
Assets.sendToken(
token,
msg.sender,
destinationChain,
destinationAddress,
destinationFee,
amount,
MAX_DESTINATION_TRANSFER_FEE
)
);
}

Expand Down Expand Up @@ -571,8 +585,6 @@ contract Gateway is IGateway, IInitializable {
uint128 assetHubCreateAssetFee;
/// @dev The extra fee charged for sending tokens (DOT)
uint128 assetHubReserveTransferFee;
/// @dev The maximum fee that can be sent to a destination parachain to pay for execution (DOT)
uint128 destinationMaxTransferFee;
/// @dev extra fee to discourage spamming
uint256 registerTokenFee;
/// @dev Fee multiplier
Expand Down
2 changes: 0 additions & 2 deletions contracts/src/storage/AssetsStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ library AssetsStorage {
uint128 assetHubReserveTransferFee;
// Extra fee for registering a token, to discourage spamming (Ether)
uint256 registerTokenFee;
/// The maximum fee that can be sent to a destination chain during a reserve transfer (DOT)
uint128 destinationMaxTransferFee;
}

bytes32 internal constant SLOT = keccak256("org.snowbridge.storage.assets");
Expand Down
14 changes: 12 additions & 2 deletions contracts/src/upgrades/rococo/GatewayV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,18 @@ contract GatewayV2 is Gateway {
address agentExecutor,
ParaID bridgeHubParaID,
bytes32 bridgeHubAgentID,
uint8 foreignTokenDecimals
) Gateway(beefyClient, agentExecutor, bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals) {}
uint8 foreignTokenDecimals,
uint128 destinationMaxTransferFee
)
Gateway(
beefyClient,
agentExecutor,
bridgeHubParaID,
bridgeHubAgentID,
foreignTokenDecimals,
destinationMaxTransferFee
)
{}

function initialize(bytes memory data) external override {
// Prevent initialization of storage in implementation contract
Expand Down
36 changes: 26 additions & 10 deletions contracts/test/Gateway.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ contract GatewayTest is Test {
uint128 public registerTokenFee = 0;
uint128 public sendTokenFee = 1e10;
uint128 public createTokenFee = 1e10;
uint128 public maxDestinationFee = 1e11;
uint128 public destinationMaxTransferFee = 1e11;

MultiAddress public recipientAddress32;
MultiAddress public recipientAddress20;
Expand All @@ -95,8 +95,14 @@ contract GatewayTest is Test {

function setUp() public {
AgentExecutor executor = new AgentExecutor();
gatewayLogic =
new GatewayMock(address(0), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals);
gatewayLogic = new GatewayMock(
address(0),
address(executor),
bridgeHubParaID,
bridgeHubAgentID,
foreignTokenDecimals,
destinationMaxTransferFee
);
Gateway.Config memory config = Gateway.Config({
mode: OperatingMode.Normal,
deliveryCost: outboundFee,
Expand All @@ -105,7 +111,6 @@ contract GatewayTest is Test {
assetHubAgentID: assetHubAgentID,
assetHubCreateAssetFee: createTokenFee,
assetHubReserveTransferFee: sendTokenFee,
destinationMaxTransferFee: maxDestinationFee,
exchangeRate: exchangeRate,
multiplier: multiplier
});
Expand Down Expand Up @@ -490,8 +495,14 @@ contract GatewayTest is Test {
function testUpgradeInitializerRunsOnlyOnce() public {
// Upgrade to this current logic contract
AgentExecutor executor = new AgentExecutor();
GatewayMock currentLogic =
new GatewayMock(address(0), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals);
GatewayMock currentLogic = new GatewayMock(
address(0),
address(executor),
bridgeHubParaID,
bridgeHubAgentID,
foreignTokenDecimals,
destinationMaxTransferFee
);

Gateway.Config memory config = Gateway.Config({
mode: OperatingMode.Normal,
Expand All @@ -501,7 +512,6 @@ contract GatewayTest is Test {
assetHubAgentID: assetHubAgentID,
assetHubCreateAssetFee: createTokenFee,
assetHubReserveTransferFee: sendTokenFee,
destinationMaxTransferFee: maxDestinationFee,
exchangeRate: exchangeRate,
multiplier: multiplier
});
Expand Down Expand Up @@ -529,8 +539,14 @@ contract GatewayTest is Test {

// Upgrade to this current logic contract
AgentExecutor executor = new AgentExecutor();
GatewayMock currentLogic =
new GatewayMock(address(0), address(executor), bridgeHubParaID, bridgeHubAgentID, foreignTokenDecimals);
GatewayMock currentLogic = new GatewayMock(
address(0),
address(executor),
bridgeHubParaID,
bridgeHubAgentID,
foreignTokenDecimals,
destinationMaxTransferFee
);

bytes memory initParams; // empty
UpgradeParams memory params = UpgradeParams({
Expand Down Expand Up @@ -925,7 +941,7 @@ contract GatewayTest is Test {
uint256 fee = IGateway(address(gateway)).quoteRegisterTokenFee();
IGateway(address(gateway)).registerToken{value: fee}(address(token));

uint128 largeFee = maxDestinationFee + 1; // greater than 10 DOT, 10 decimal places
uint128 largeFee = destinationMaxTransferFee + 1; // greater than 10 DOT, 10 decimal places

vm.expectRevert(Assets.InvalidDestinationFee.selector);
fee = IGateway(address(gateway)).quoteSendTokenFee(address(token), destPara, largeFee);
Expand Down
14 changes: 12 additions & 2 deletions contracts/test/mocks/GatewayMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,18 @@ contract GatewayMock is Gateway {
address agentExecutor,
ParaID bridgeHubParaID,
bytes32 bridgeHubHubAgentID,
uint8 foreignTokenDecimals
) Gateway(beefyClient, agentExecutor, bridgeHubParaID, bridgeHubHubAgentID, foreignTokenDecimals) {}
uint8 foreignTokenDecimals,
uint128 destinationMaxTransferFee
)
Gateway(
beefyClient,
agentExecutor,
bridgeHubParaID,
bridgeHubHubAgentID,
foreignTokenDecimals,
destinationMaxTransferFee
)
{}

function agentExecutePublic(bytes calldata params) external {
this.agentExecute(params);
Expand Down

0 comments on commit c0d9b6b

Please sign in to comment.