Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 1 addition & 186 deletions contracts/src/v1/Calls.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,42 +62,7 @@ library CallsV1 {
uint128 destinationChainFee,
uint128 amount
) external {
AssetsStorage.Layout storage $ = AssetsStorage.layout();

if (amount == 0) {
revert InvalidAmount();
}

TokenInfo storage info = $.tokenRegistry[token];

if (!info.isRegistered) {
revert TokenNotRegistered();
}

if (info.isNative()) {
_submitOutbound(
_sendNativeTokenOrEther(
token,
sender,
destinationChain,
destinationAddress,
destinationChainFee,
amount
)
);
} else {
_submitOutbound(
_sendForeignToken(
info.foreignID,
token,
sender,
destinationChain,
destinationAddress,
destinationChainFee,
amount
)
);
}
revert Unsupported();
}

function quoteSendTokenFee(address token, ParaID destinationChain, uint128 destinationChainFee)
Expand Down Expand Up @@ -160,54 +125,6 @@ library CallsV1 {
return costs.native + _convertToNative(pricing.exchangeRate, pricing.multiplier, amount);
}

/// @dev Outbound message can be disabled globally or on a per-channel basis.
function _ensureOutboundMessagingEnabled(Channel storage ch) internal view {
CoreStorage.Layout storage $ = CoreStorage.layout();
if ($.mode != OperatingMode.Normal || ch.mode != OperatingMode.Normal) {
revert Disabled();
}
}

// Submit an outbound message to Polkadot, after taking fees
function _submitOutbound(Ticket memory ticket) internal {
ChannelID channelID = ticket.dest.into();
Channel storage channel = Functions.ensureChannel(channelID);

// Ensure outbound messaging is allowed
_ensureOutboundMessagingEnabled(channel);

// Destination fee always in DOT
uint256 fee = _calculateFee(ticket.costs);

// Ensure the user has provided enough ether for this message to be accepted.
// This includes:
// 1. The bridging fee, which is collected in this gateway contract
// 2. The ether value being bridged over to Polkadot, which is locked into the AssetHub
// agent contract.
uint256 totalRequiredEther = fee + ticket.value;
if (msg.value < totalRequiredEther) {
revert IGatewayBase.InsufficientEther();
}
if (ticket.value > 0) {
payable(AssetsStorage.layout().assetHubAgent).safeNativeTransfer(ticket.value);
}

channel.outboundNonce = channel.outboundNonce + 1;

// Reimburse excess fee payment
uint256 excessFee = msg.value - totalRequiredEther;
if (excessFee > Functions.dustThreshold()) {
payable(msg.sender).safeNativeTransfer(excessFee);
}

// Generate a unique ID for this message
bytes32 messageID = keccak256(abi.encodePacked(channelID, channel.outboundNonce));

emit IGatewayV1.OutboundMessageAccepted(
channelID, channel.outboundNonce, messageID, ticket.payload
);
}

function _sendTokenCosts(ParaID destinationChain, uint128 destinationChainFee)
internal
view
Expand Down Expand Up @@ -237,106 +154,4 @@ library CallsV1 {
// We don't charge any extra fees beyond delivery costs
costs.native = 0;
}

function _sendNativeTokenOrEther(
address token,
address sender,
ParaID destinationChain,
MultiAddress calldata destinationAddress,
uint128 destinationChainFee,
uint128 amount
) internal returns (Ticket memory ticket) {
AssetsStorage.Layout storage $ = AssetsStorage.layout();

if (token != address(0)) {
// Lock ERC20
Functions.transferToAgent($.assetHubAgent, token, sender, amount);
ticket.value = 0;
} else {
// Track the ether to bridge to Polkadot. This will be handled
// in `Gateway._submitOutbound`.
ticket.value = amount;
}

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

// Construct a message payload
if (destinationChain == $.assetHubParaID) {
// The funds will be minted into the receiver's account on AssetHub
if (destinationAddress.isAddress32()) {
// The receiver has a 32-byte account ID
ticket.payload = SubstrateTypes.SendTokenToAssetHubAddress32(
token, destinationAddress.asAddress32(), $.assetHubReserveTransferFee, amount
);
} else {
// AssetHub does not support 20-byte account IDs
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()) {
// The receiver has a 32-byte account ID
ticket.payload = SubstrateTypes.SendTokenToAddress32(
token,
destinationChain,
destinationAddress.asAddress32(),
$.assetHubReserveTransferFee,
destinationChainFee,
amount
);
} else if (destinationAddress.isAddress20()) {
// The receiver has a 20-byte account ID
ticket.payload = SubstrateTypes.SendTokenToAddress20(
token,
destinationChain,
destinationAddress.asAddress20(),
$.assetHubReserveTransferFee,
destinationChainFee,
amount
);
} else {
revert Unsupported();
}
}

emit IGatewayV1.TokenSent(token, sender, destinationChain, destinationAddress, amount);
}

// @dev Transfer Polkadot-native tokens back to Polkadot
function _sendForeignToken(
bytes32 foreignID,
address token,
address sender,
ParaID destinationChain,
MultiAddress calldata destinationAddress,
uint128 destinationChainFee,
uint128 amount
) internal returns (Ticket memory ticket) {
AssetsStorage.Layout storage $ = AssetsStorage.layout();

Token(token).burn(sender, amount);

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

// Construct a message payload
if (destinationChain == $.assetHubParaID && destinationAddress.isAddress32()) {
// The funds will be minted into the receiver's account on AssetHub
// The receiver has a 32-byte account ID
ticket.payload = SubstrateTypes.SendForeignTokenToAssetHubAddress32(
foreignID, destinationAddress.asAddress32(), $.assetHubReserveTransferFee, amount
);
} else {
revert Unsupported();
}

emit IGatewayV1.TokenSent(token, sender, destinationChain, destinationAddress, amount);
}
}
Loading