Skip to content

Commit

Permalink
fetch recommended fee from relayer
Browse files Browse the repository at this point in the history
  • Loading branch information
KorbinianK committed Apr 11, 2024
1 parent c5eb3f6 commit dc97190
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 52 deletions.
5 changes: 1 addition & 4 deletions packages/bridge-ui/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,4 @@ export CONFIGURED_RELAYER=
export CONFIGURED_EVENT_INDEXER=

# Show the slow L1 bridging warning
export PUBLIC_SLOW_L1_BRIDGING_WARNING=false

# L2 processing fee multiplier
export PUBLIC_L2_PROCESSING_FEE_MULTIPLIER=10
export PUBLIC_SLOW_L1_BRIDGING_WARNING=false
79 changes: 39 additions & 40 deletions packages/bridge-ui/src/libs/fee/recommendProcessingFee.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { getPublicClient } from '@wagmi/core';

import { recommendProcessingFeeConfig } from '$config';
import { PUBLIC_L2_PROCESSING_FEE_MULTIPLIER } from '$env/static/public';
import { isL2Chain } from '$libs/chain';
import { NoCanonicalInfoFoundError } from '$libs/error';
import { relayerApiServices } from '$libs/relayer';
import { FeeTypes } from '$libs/relayer/types';
import { type Token, TokenType } from '$libs/token';
import { getTokenAddresses } from '$libs/token/getTokenAddresses';
import { getLogger } from '$libs/util/logger';
import { config } from '$libs/wagmi';

const log = getLogger('libs:recommendedProcessingFee');

Expand All @@ -17,16 +13,6 @@ type RecommendProcessingFeeArgs = {
srcChainId?: number;
};

const {
ethGasLimit,
erc20NotDeployedGasLimit,
erc20DeployedGasLimit,
erc1155DeployedGasLimit,
erc1155NotDeployedGasLimit,
erc721DeployedGasLimit,
erc721NotDeployedGasLimit,
} = recommendProcessingFeeConfig;

export async function recommendProcessingFee({
token,
destChainId,
Expand All @@ -35,24 +21,8 @@ export async function recommendProcessingFee({
if (!srcChainId) {
return 0n;
}
const destPublicClient = getPublicClient(config, { chainId: destChainId });

if (!destPublicClient) throw new Error('Could not get public client');

// getGasPrice will return gasPrice as 3000000001, rather than 3000000000
const gasPrice = await destPublicClient.getGasPrice();

let multiplier = 1;

//TODO: temporary increase multiplier for L2 chains until we have a better solution via the relayer
// figure out if it is L2-L1
if (isL2Chain(srcChainId)) {
multiplier = parseInt(PUBLIC_L2_PROCESSING_FEE_MULTIPLIER);
}

// The gas limit for processMessage call for ETH is about ~800k.
// To make it enticing, we say 900k
let gasLimit = ethGasLimit;
let fee;

if (token.type !== TokenType.ETH) {
const tokenInfo = await getTokenAddresses({ token, srcChainId, destChainId });
Expand All @@ -68,29 +38,58 @@ export async function recommendProcessingFee({
}
if (token.type === TokenType.ERC20) {
if (isTokenAlreadyDeployed) {
gasLimit = erc20DeployedGasLimit;
log(`token ${token.symbol} is already deployed on chain ${destChainId}`);

fee = await relayerApiServices[0].recommendedProcessingFees({
typeFilter: FeeTypes.Erc20Deployed,
destChainIDFilter: destChainId,
});
} else {
gasLimit = erc20NotDeployedGasLimit;
fee = await relayerApiServices[0].recommendedProcessingFees({
typeFilter: FeeTypes.Erc20NotDeployed,
destChainIDFilter: destChainId,
});
log(`token ${token.symbol} is not deployed on chain ${destChainId}`);
}
} else if (token.type === TokenType.ERC721) {
if (isTokenAlreadyDeployed) {
gasLimit = erc721DeployedGasLimit;
log(`token ${token.symbol} is already deployed on chain ${destChainId}`);
fee = await relayerApiServices[0].recommendedProcessingFees({
typeFilter: FeeTypes.Erc721Deployed,
destChainIDFilter: destChainId,
});
} else {
gasLimit = erc721NotDeployedGasLimit;
log(`token ${token.symbol} is not deployed on chain ${destChainId}`);
fee = await relayerApiServices[0].recommendedProcessingFees({
typeFilter: FeeTypes.Erc721NotDeployed,
destChainIDFilter: destChainId,
});
}
} else if (token.type === TokenType.ERC1155) {
if (isTokenAlreadyDeployed) {
gasLimit = erc1155DeployedGasLimit;
log(`token ${token.symbol} is already deployed on chain ${destChainId}`);
fee = await relayerApiServices[0].recommendedProcessingFees({
typeFilter: FeeTypes.Erc1155Deployed,
destChainIDFilter: destChainId,
});
} else {
gasLimit = erc1155NotDeployedGasLimit;
log(`token ${token.symbol} is not deployed on chain ${destChainId}`);
fee = await relayerApiServices[0].recommendedProcessingFees({
typeFilter: FeeTypes.Erc1155NotDeployed,
destChainIDFilter: destChainId,
});
}
}
} else {
log(`Fee for ETH bridging`);
fee = await relayerApiServices[0].recommendedProcessingFees({
typeFilter: FeeTypes.Eth,
destChainIDFilter: destChainId,
});
}
return gasPrice * gasLimit * BigInt(multiplier);
if (!fee) throw new Error('Unable to get fee from relayer API');

const feeInWei = BigInt(fee[0].amount);
log(`Recommended fee: ${feeInWei.toString()}`);
return feeInWei;
}
36 changes: 36 additions & 0 deletions packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ import {
type APIRequestParams,
type APIResponse,
type APIResponseTransaction,
type Fee,
type FeeType,
type GetAllByAddressResponse,
type PaginationInfo,
type PaginationParams,
type ProcessingFeeApiResponse,
type RelayerBlockInfo,
RelayerEventType,
} from './types';
Expand Down Expand Up @@ -278,6 +281,39 @@ export class RelayerAPIService {
}): Promise<Record<number, RelayerBlockInfo>> {
throw new Error('Not implemented');
}

async recommendedProcessingFees({
typeFilter,
destChainIDFilter,
}: {
typeFilter?: FeeType;
destChainIDFilter?: number;
}): Promise<Fee[]> {
const requestURL = `${this.baseUrl}/recommendedProcessingFees`;

try {
const response = await axios.get<ProcessingFeeApiResponse>(requestURL);

if (response.status >= 400) throw new Error('HTTP error', { cause: response });

let { fees } = response.data;

if (typeFilter) {
fees = fees.filter((fee) => fee.type === typeFilter);
}

if (destChainIDFilter !== undefined) {
fees = fees.filter((fee) => fee.destChainID === destChainIDFilter);
}

return fees;
} catch (error) {
console.error(error);
throw new Error('Failed to fetch recommended processing fees', {
cause: error instanceof Error ? error : undefined,
});
}
}
}

const _eventToTokenType = (eventType: RelayerEventType): TokenType => {
Expand Down
20 changes: 17 additions & 3 deletions packages/bridge-ui/src/libs/relayer/initRelayers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ import { configuredRelayer } from '$relayerConfig';

import { RelayerAPIService } from './RelayerAPIService';

export const relayerApiServices: RelayerAPIService[] = configuredRelayer.map(
(relayerConfig: { url: string }) => new RelayerAPIService(relayerConfig.url),
);
class RelayerServiceFactory {
private static instanceCache: Map<string, RelayerAPIService> = new Map();

public static getServices(configuredRelayers: { url: string }[]): RelayerAPIService[] {
return configuredRelayers.map((relayerConfig) => this.getService(relayerConfig.url));
}

private static getService(url: string): RelayerAPIService {
if (!this.instanceCache.has(url)) {
const newInstance = new RelayerAPIService(url);
this.instanceCache.set(url, newInstance);
}
return this.instanceCache.get(url)!;
}
}

export const relayerApiServices: RelayerAPIService[] = RelayerServiceFactory.getServices(configuredRelayer);
20 changes: 20 additions & 0 deletions packages/bridge-ui/src/libs/relayer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,23 @@ export type RelayerConfig = {
export type ConfiguredRelayer = {
configuredRelayer: RelayerConfig[];
};

export const FeeTypes = {
Eth: 'eth',
Erc20Deployed: 'erc20Deployed',
Erc20NotDeployed: 'erc20NotDeployed',
Erc721Deployed: 'erc721Deployed',
Erc721NotDeployed: 'erc721NotDeployed',
Erc1155NotDeployed: 'erc1155NotDeployed',
Erc1155Deployed: 'erc1155Deployed',
} as const;

export type FeeType = (typeof FeeTypes)[keyof typeof FeeTypes];

export type Fee = {
type: FeeType;
amount: string;
destChainID: number;
};

export type ProcessingFeeApiResponse = { fees: Fee[] };
10 changes: 5 additions & 5 deletions packages/bridge-ui/src/libs/token/getCanonicalInfoForToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,15 @@ const _getStatus = async ({ address, srcChainId, destChainId, type }: CheckCanon
// if both are zero we are dealing with a canonical address
canonicalTokenAddress = srcChainTokenAddress;
// But either chain passed could be the canonical chain, so we need to check which one
const checkSrcChainForCanonicalChain = (await srcTokenVaultContract.read.canonicalToBridged([
srcChainId,
const checkDestChainForCanonicalChain = (await destTokenVaultContract.read.canonicalToBridged([
destChainId,
srcChainTokenAddress,
])) as Address;

if (checkSrcChainForCanonicalChain === zeroAddress) {
canonicalChain = destChainId;
} else {
if (checkDestChainForCanonicalChain === zeroAddress) {
canonicalChain = srcChainId;
} else {
canonicalChain = destChainId;
}
} else if (destCanonicalCheck !== zeroAddress) {
// if the destination is not zero, we found a canonical address there
Expand Down

0 comments on commit dc97190

Please sign in to comment.