Skip to content

Commit

Permalink
feat: Add approval fee (#1355)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcgcyx authored Jan 22, 2024
1 parent 8af7145 commit ed8730d
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 11 deletions.
4 changes: 4 additions & 0 deletions packages/checkout/sdk/src/gasEstimate/bridgeGasEstimate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import {
BridgeFeeResponse,
TokenBridge,
} from '@imtbl/bridge-sdk';
import { BigNumber } from 'ethers';
import { CheckoutConfiguration, getL1ChainId } from '../config';
import { ChainId } from '../types';
import { NATIVE } from '../env/constants';

export async function getBridgeFeeEstimate(
tokenBridge: TokenBridge,
Expand All @@ -21,5 +23,7 @@ export async function getBridgeFeeEstimate(
gasMultiplier: 1.1,
sourceChainId: fromChainId.toString(),
destinationChainId: toChainId.toString(),
token: NATIVE.toUpperCase(),
amount: BigNumber.from(0),
});
}
1 change: 1 addition & 0 deletions packages/checkout/sdk/src/gasEstimate/gasEstimator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ describe('gasServiceEstimator', () => {
gasEstimateType: GasEstimateType.BRIDGE_TO_L2,
fees: {
sourceChainGas: BigNumber.from(0),
approvalFee: BigNumber.from(0),
bridgeFee: BigNumber.from(0),
imtblFee: BigNumber.from(0),
totalFees: BigNumber.from(0),
Expand Down
1 change: 1 addition & 0 deletions packages/checkout/sdk/src/gasEstimate/gasEstimator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ async function bridgeToL2GasEstimator(
gasEstimateType: GasEstimateType.BRIDGE_TO_L2,
fees: {
sourceChainGas: BigNumber.from(0),
approvalFee: BigNumber.from(0),
bridgeFee: BigNumber.from(0),
imtblFee: BigNumber.from(0),
totalFees: BigNumber.from(0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ export function BridgeForm(props: BridgeFormProps) {
gasMultiplier: 1.1,
sourceChainId: from?.network.toString() ?? '',
destinationChainId: to?.network.toString() ?? '',
token: NATIVE.toUpperCase(),
amount: BigNumber.from(0),
});

const gasEstimateResult = {
Expand Down
6 changes: 4 additions & 2 deletions packages/internal/bridge/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ export type {
FungibleToken,
FeeData,
BridgeFeeRequest,
DepositFeeRequest,
WithdrawFeeRequest,
DepositNativeFeeRequest,
DepositERC20FeeRequest,
WithdrawNativeFeeRequest,
WithdrawERC20FeeRequest,
FinaliseFeeRequest,
BridgeFeeResponse,
CalculateBridgeFeeResponse,
Expand Down
24 changes: 23 additions & 1 deletion packages/internal/bridge/sdk/src/tokenBridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ describe('Token Bridge', () => {
const originalCalculateBridgeFee = TokenBridge.prototype['calculateBridgeFee'];

const sourceChainGas:ethers.BigNumber = ethers.utils.parseUnits('0.000001', 18);
const approavalGas:ethers.BigNumber = ethers.utils.parseUnits('0.000001', 18);
const destinationChainGas:ethers.BigNumber = ethers.utils.parseUnits('0.000001', 18);
const validatorFee:ethers.BigNumber = ethers.utils.parseUnits('0.0001', 18);
const bridgeFee:ethers.BigNumber = destinationChainGas.add(validatorFee);
Expand Down Expand Up @@ -574,7 +575,7 @@ describe('Token Bridge', () => {
TokenBridge.prototype['getGasEstimates'] = originalGetGasEstimates;
TokenBridge.prototype['calculateBridgeFee'] = originalCalculateBridgeFee;
});
it('returns the deposit fees', async () => {
it('returns the deposit fees for native tokens', async () => {
expect.assertions(5);
const result = await tokenBridge.getFee(
{
Expand All @@ -591,6 +592,27 @@ describe('Token Bridge', () => {
expect(result.imtblFee).toStrictEqual(imtblFee);
expect(result.totalFees).toStrictEqual(totalFees);
});

it('returns the deposit fees for ERC20 tokens', async () => {
expect.assertions(6);
const result = await tokenBridge.getFee(
{
action: BridgeFeeActions.DEPOSIT,
gasMultiplier: 1.1,
sourceChainId: ETH_SEPOLIA_TO_ZKEVM_DEVNET.rootChainID,
destinationChainId: ETH_SEPOLIA_TO_ZKEVM_DEVNET.childChainID,
token: '0x40b87d235A5B010a20A241F15797C9debf1ecd01',
amount: ethers.BigNumber.from(1000),
},
);

expect(result).not.toBeNull();
expect(result.sourceChainGas).toStrictEqual(sourceChainGas);
expect(result.approvalFee).toStrictEqual(approavalGas);
expect(result.bridgeFee).toStrictEqual(bridgeFee);
expect(result.imtblFee).toStrictEqual(imtblFee);
expect(result.totalFees).toStrictEqual(totalFees.add(approavalGas));
});
});

describe('getTransactionStatus', () => {
Expand Down
13 changes: 12 additions & 1 deletion packages/internal/bridge/sdk/src/tokenBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,17 @@ export class TokenBridge {
}

let sourceChainGas: ethers.BigNumber = ethers.BigNumber.from(0);
let approvalFee: ethers.BigNumber = ethers.BigNumber.from(0);
let bridgeFee: ethers.BigNumber = ethers.BigNumber.from(0);
const imtblFee: ethers.BigNumber = ethers.BigNumber.from(0);

if ('token' in req && req.token !== 'NATIVE') {
approvalFee = await this.getGasEstimates(
this.config.rootProvider,
BridgeMethodsGasLimit.APPROVE_TOKEN,
);
}

if (req.action === BridgeFeeActions.FINALISE_WITHDRAWAL) {
sourceChainGas = await this.getGasEstimates(
this.config.rootProvider,
Expand All @@ -166,10 +174,11 @@ export class TokenBridge {
bridgeFee = feeResult.bridgeFee;
}

const totalFees: ethers.BigNumber = sourceChainGas.add(bridgeFee).add(imtblFee);
const totalFees: ethers.BigNumber = sourceChainGas.add(approvalFee).add(bridgeFee).add(imtblFee);

return {
sourceChainGas,
approvalFee,
bridgeFee,
imtblFee, // no network fee charged currently
totalFees,
Expand Down Expand Up @@ -498,6 +507,8 @@ export class TokenBridge {
gasMultiplier,
sourceChainId,
destinationChainId,
token,
amount,
});

const canReceive:boolean = await this.checkReceiver(provider, recipient);
Expand Down
56 changes: 49 additions & 7 deletions packages/internal/bridge/sdk/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export enum BridgeMethodsGasLimit { // @TODO test methods on chain and put corre
MAP_TOKEN_SOURCE = 200000,
MAP_TOKEN_DESTINATION = 200000,
FINALISE_WITHDRAWAL = 200000,
APPROVE_TOKEN = 55000,
}

export interface FeeData {
Expand All @@ -123,38 +124,76 @@ export interface FeeData {
* @dev Union type of DepositFeeRequest|WithdrawFeeRequest|FinaliseFeeRequest|MapTokenFeeRequest
* ensures the correct params are supplied when trying to calculate the fees
*/
export type BridgeFeeRequest = DepositFeeRequest
| WithdrawFeeRequest
export type BridgeFeeRequest = DepositNativeFeeRequest
| DepositERC20FeeRequest
| WithdrawNativeFeeRequest
| WithdrawERC20FeeRequest
| FinaliseFeeRequest;

/**
* @typedef {Object} DepositFeeRequest
* @typedef {Object} DepositNativeFeeRequest
* @property {BridgeFeeActions} method - The method for which the bridge fee is being requested.
* @property {number} gasMultiplier - How much buffer to add to the gas fee.
* @property {string} sourceChainId - The chain ID of the source chain.
* @property {string} destinationChainId - The chain ID of the destination chain.
*/
export interface DepositFeeRequest {
export interface DepositNativeFeeRequest {
action: BridgeFeeActions.DEPOSIT,
gasMultiplier: number;
sourceChainId: string;
destinationChainId: string;
}

/**
* @typedef {Object} WithdrawFeeRequest
* @typedef {Object} DepositERC20FeeRequest
* @property {BridgeFeeActions} method - The method for which the bridge fee is being requested.
* @property {number} gasMultiplier - How much buffer to add to the gas fee.
* @property {string} sourceChainId - The chain ID of the source chain.
* @property {string} destinationChainId - The chain ID of the destination chain.
* @property {FungibleToken} token - The token to be deposited.
* @property {ethers.BigNumber} amount - The amount to be deposited.
*/
export interface DepositERC20FeeRequest {
action: BridgeFeeActions.DEPOSIT,
gasMultiplier: number;
sourceChainId: string;
destinationChainId: string;
token: FungibleToken;
amount: ethers.BigNumber;
}

/**
* @typedef {Object} WithdrawNativeFeeRequest
* @property {BridgeFeeActions} method - The method for which the bridge fee is being requested.
* @property {number} gasMultiplier - How much buffer to add to the gas fee.
* @property {string} sourceChainId - The chain ID of the source chain.
* @property {string} destinationChainId - The chain ID of the destination chain.
*/
export interface WithdrawFeeRequest {
export interface WithdrawNativeFeeRequest {
action: BridgeFeeActions.WITHDRAW,
gasMultiplier: number;
sourceChainId: string;
destinationChainId: string;
}

/**
* @typedef {Object} WithdrawERC20FeeRequest
* @property {BridgeFeeActions} method - The method for which the bridge fee is being requested.
* @property {number} gasMultiplier - How much buffer to add to the gas fee.
* @property {string} sourceChainId - The chain ID of the source chain.
* @property {string} destinationChainId - The chain ID of the destination chain.
* @property {FungibleToken} token - The token to be withdrawn.
* @property {ethers.BigNumber} amount - The amount to be withdrawn.
*/
export interface WithdrawERC20FeeRequest {
action: BridgeFeeActions.WITHDRAW,
gasMultiplier: number;
sourceChainId: string;
destinationChainId: string;
token: FungibleToken;
amount: ethers.BigNumber;
}

/**
* @typedef {Object} FinaliseFeeRequest
* @property {BridgeFeeActions} method - The method for which the bridge fee is being requested.
Expand All @@ -169,17 +208,20 @@ export interface FinaliseFeeRequest {
* @typedef {Object} BridgeFeeResponse
* @property {ethers.BigNumber} sourceChainGas - Gas cost to send tokens to the bridge contract on the source chain.
* - priced in the source chain's native token.
* @property {ethers.BigNumber} approvalFee - Gas cost to approve bridge contract to spend tokens on the source chain.
* - priced in the source chain's native token.
* @property {ethers.BigNumber} bridgeFee - destinationChainGas + validatorFee.
* This will be added to the tx.value of the bridge transaction and forwarded to the Axelar Gas Service contract.
* - priced in the source chain's native token.
* @property {ethers.BigNumber} imtblFee - The fee charged by Immutable to facilitate the bridge.
* - priced in the source chain's native token.
* @property {ethers.BigNumber} totalFees - The total fees the user will be charged which is;
* sourceChainGas + bridgeFee + imtblFee.
* sourceChainGas + approvalFee + bridgeFee + imtblFee.
* - priced in the source chain's native token.
*/
export interface BridgeFeeResponse {
sourceChainGas: ethers.BigNumber,
approvalFee: ethers.BigNumber,
bridgeFee: ethers.BigNumber,
imtblFee: ethers.BigNumber,
totalFees: ethers.BigNumber,
Expand Down

0 comments on commit ed8730d

Please sign in to comment.