Skip to content

Commit

Permalink
Autowrap ether
Browse files Browse the repository at this point in the history
  • Loading branch information
vgeddes committed Nov 4, 2024
1 parent 5817542 commit 4c3b2af
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 19 deletions.
50 changes: 37 additions & 13 deletions contracts/src/v2/Calls.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ library CallsV2 {
bytes[] calldata assets,
bytes calldata claimer
) external {
_sendMessage(msg.sender, xcm, assets, claimer, msg.value);
_sendMessage(msg.sender, xcm, assets, claimer);
}

// Register Ethereum-native token on AHP, using `xcmFeeAHP` of `msg.value`
Expand All @@ -83,23 +83,31 @@ library CallsV2 {
address origin,
bytes memory xcm,
bytes[] memory assets,
bytes memory claimer,
uint256 reward
bytes memory claimer
) internal {
if (assets.length > MAX_ASSETS) {
revert IGatewayBase.TooManyAssets();
}

bytes[] memory encodedAssets = new bytes[](assets.length);
uint128 etherValue = 0;
uint128 totalEtherValue = 0;

for (uint256 i = 0; i < assets.length; i++) {
encodedAssets[i] = _handleAsset(assets[i]);
(encodedAssets[i], etherValue) = _handleAsset(assets[i]);
totalEtherValue += etherValue;
}

if (totalEtherValue > msg.value) {
revert IGatewayV2.InvalidEtherValue();
}

Ticket memory ticket = Ticket({
origin: origin,
assets: encodedAssets,
xcm: xcm,
claimer: claimer,
reward: reward
reward: msg.value - totalEtherValue
});
_submitOutbound(ticket);
}
Expand All @@ -126,12 +134,11 @@ library CallsV2 {
if (xcmFee > msg.value) {
revert IGatewayV2.InvalidFee();
}
_lockEther(xcmFee);

bytes[] memory assets = new bytes[](1);
assets[0] = abi.encode(0, Functions.weth(), xcmFee);
assets[0] = abi.encode(0, xcmFee);

_sendMessage(address(this), xcm, assets, "", msg.value - xcmFee);
_sendMessage(address(this), xcm, assets, "");
}

// Submit an outbound message to Polkadot, after taking fees
Expand Down Expand Up @@ -169,13 +176,17 @@ library CallsV2 {
}
}

function _handleAsset(bytes memory asset) internal returns (bytes memory) {
function _handleAsset(bytes memory asset) internal returns (bytes memory, uint128) {
uint8 assetKind;
assembly {
assetKind := byte(31, mload(add(asset, 32)))
}
if (assetKind == 0) {
// ERC20: abi.encode(0, tokenAddress, value)
// Ether: abi.encode(0, value)
(, uint128 amount) = abi.decode(asset, (uint8, uint128));
return _handleAssetEther(amount);
} else if (assetKind == 1) {
// ERC20: abi.encode(1, tokenAddress, value)
(, address token, uint128 amount) =
abi.decode(asset, (uint8, address, uint128));
return _handleAssetERC20(token, amount);
Expand All @@ -184,9 +195,20 @@ library CallsV2 {
}
}

function _handleAssetEther(uint128 amount)
internal
returns (bytes memory, uint128)
{
_lockEther(amount);
return (
SubstrateTypes.encodeTransferNativeTokenERC20(Functions.weth(), amount),
amount
);
}

function _handleAssetERC20(address token, uint128 amount)
internal
returns (bytes memory)
returns (bytes memory, uint128)
{
AssetsStorage.Layout storage $ = AssetsStorage.layout();
TokenInfo storage info = $.tokenRegistry[token];
Expand All @@ -197,10 +219,12 @@ library CallsV2 {

if (info.foreignID == bytes32(0)) {
Functions.transferToAgent($.assetHubAgent, token, msg.sender, amount);
return SubstrateTypes.encodeTransferNativeTokenERC20(token, amount);
return (SubstrateTypes.encodeTransferNativeTokenERC20(token, amount), 0);
} else {
Token(token).burn(msg.sender, amount);
return SubstrateTypes.encodeTransferForeignTokenERC20(info.foreignID, amount);
return (
SubstrateTypes.encodeTransferForeignTokenERC20(info.foreignID, amount), 0
);
}
}
}
4 changes: 3 additions & 1 deletion contracts/src/v2/IGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {UD60x18} from "prb/math/src/UD60x18.sol";
interface IGatewayV2 {
error InvalidAsset();
error InvalidFee();
error InvalidEtherValue();

function operatingMode() external view returns (OperatingMode);

Expand Down Expand Up @@ -44,7 +45,8 @@ interface IGatewayV2 {
// * `assets` (bytes[]): Array of asset specs, constrained to maximum of eight.
//
// Supported asset specs:
// * ERC20: abi.encode(0, tokenAddress, value)
// * Ether: abi.encode(0, value)
// * ERC20: abi.encode(1, tokenAddress, value)
//
// On Asset Hub, the assets will be received into the assets holding register.
//
Expand Down
24 changes: 19 additions & 5 deletions contracts/test/GatewayV2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ contract GatewayV2Test is Test {

WETH9 public token;

address public account1;
address public account2;
address public user1;
address public user2;

// tokenID for DOT
bytes32 public dotTokenID;
Expand Down Expand Up @@ -120,14 +120,15 @@ contract GatewayV2Test is Test {

// Features

account1 = makeAddr("account1");
account2 = makeAddr("account2");
user1 = makeAddr("user1");
user2 = makeAddr("user2");

// create tokens for account 1
hoax(account1);
hoax(user1);
token.deposit{value: 500}();

// create tokens for account 2
hoax(user2);
token.deposit{value: 500}();

dotTokenID = bytes32(uint256(1));
Expand Down Expand Up @@ -226,4 +227,17 @@ contract GatewayV2Test is Test {
message, proof, makeMockProof(), relayerRewardAddress
);
}

function testSendEther() public {
bytes[] memory assets = new bytes[](1);
assets[0] = abi.encode(0, 0.5 ether);

hoax(user1, 1 ether);
IGatewayV2(payable(address(gateway))).v2_sendMessage{value: 1 ether}(
"", assets, ""
);

// Agent balance should be 0.5 + 0.5
assertEq(token.balanceOf(assetHubAgent), 1 ether);
}
}

0 comments on commit 4c3b2af

Please sign in to comment.