Skip to content

Commit

Permalink
feat: pay fee in native token (#45)
Browse files Browse the repository at this point in the history
* feat: pay fee in native token

* Fix fee amount

* EVM: fix fee logic

* Don't pass amount to `sign_claim_native_fee`

* Fix typo

* Fix typo

* Add fee validation

* Improve `claim_fee_callback`
  • Loading branch information
karim-en authored Sep 30, 2024
1 parent 33702b1 commit 1b88b4e
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 65 deletions.
56 changes: 52 additions & 4 deletions evm/bridge-token-factory/contracts/BridgeTokenFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ contract BridgeTokenFactory is
uint8 public omniBridgeChainId;

mapping(uint128 => bool) public completedTransfers;
mapping(uint128 => bool) public claimedFee;
uint128 public initTransferNonce;

bytes32 public constant PAUSABLE_ADMIN_ROLE = keccak256("PAUSABLE_ADMIN_ROLE");
Expand All @@ -61,13 +62,20 @@ contract BridgeTokenFactory is
uint8 decimals;
}

struct ClaimFeePayload {
uint128[] nonces;
uint128 amount;
address recipient;
}

event InitTransfer(
address indexed sender,
address indexed tokenAddress,
uint128 indexed nonce,
string token,
uint128 amount,
uint128 fee,
uint128 nativeFee,
string recipient
);

Expand Down Expand Up @@ -98,6 +106,7 @@ contract BridgeTokenFactory is

error InvalidSignature();
error NonceAlreadyUsed(uint256 nonce);
error InvalidFee();

function initialize(
address tokenImplementationAddress_,
Expand Down Expand Up @@ -238,28 +247,67 @@ contract BridgeTokenFactory is
string calldata token,
uint128 amount,
uint128 fee,
uint128 nativeFee,
string calldata recipient
) payable external whenNotPaused(PAUSED_INIT_TRANSFER) {
initTransferNonce += 1;
_checkWhitelistedToken(token, msg.sender);
require(_isBridgeToken[_nearToEthToken[token]], "ERR_NOT_BRIDGE_TOKEN");
if (fee >= amount) {
revert InvalidFee();
}

address tokenAddress = _nearToEthToken[token];

BridgeToken(tokenAddress).burn(msg.sender, amount + fee);
BridgeToken(tokenAddress).burn(msg.sender, amount);

uint256 extensionValue = msg.value - nativeFee;
initTransferExtension(initTransferNonce, token, amount, fee, nativeFee, recipient, msg.sender, extensionValue);

emit InitTransfer(msg.sender, tokenAddress, initTransferNonce, token , amount, fee, nativeFee, recipient);
}

function claimNativeFee(bytes calldata signatureData, ClaimFeePayload memory payload) external {
bytes memory borshEncodedNonces = Borsh.encodeUint32(uint32(payload.nonces.length));

for (uint i = 0; i < payload.nonces.length; ++i) {
uint128 nonce = payload.nonces[i];
if (claimedFee[nonce]) {
revert NonceAlreadyUsed(nonce);
}

initTransferExtension(initTransferNonce, token, amount, fee, recipient, msg.sender);
claimedFee[nonce] = true;
borshEncodedNonces = bytes.concat(
borshEncodedNonces,
Borsh.encodeUint128(nonce)
);
}

bytes memory borshEncoded = bytes.concat(
borshEncodedNonces,
Borsh.encodeUint128(payload.amount),
bytes1(omniBridgeChainId),
Borsh.encodeAddress(payload.recipient)
);
bytes32 hashed = keccak256(borshEncoded);

if (ECDSA.recover(hashed, signatureData) != nearBridgeDerivedAddress) {
revert InvalidSignature();
}

emit InitTransfer(msg.sender, tokenAddress, initTransferNonce, token , amount, fee, recipient);
(bool success,) = payload.recipient.call{value: payload.amount}("");
require(success, "Failed to send Ether.");
}

function initTransferExtension(
uint128 nonce,
string calldata token,
uint128 amount,
uint128 fee,
uint128 nativeFee,
string calldata recipient,
address sender
address sender,
uint256 value
) internal virtual {}

function pause(uint flags) external onlyRole(DEFAULT_ADMIN_ROLE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,20 @@ contract BridgeTokenFactoryWormhole is BridgeTokenFactory {
string calldata token,
uint128 amount,
uint128 fee,
uint128 nativeFee,
string calldata recipient,
address sender
address sender,
uint256 value
) internal override {
_wormhole.publishMessage{value: msg.value}(
_wormhole.publishMessage{value: value}(
wormholeNonce,
abi.encode(
MessageType.InitTransfer,
nonce,
token,
amount,
fee,
nativeFee,
recipient,
sender
),
Expand Down
Loading

0 comments on commit 1b88b4e

Please sign in to comment.