diff --git a/packages/bridge-ui/scripts/vite-plugins/generateCustomTokenConfig.ts b/packages/bridge-ui/scripts/vite-plugins/generateCustomTokenConfig.ts
index 3418b63f92..da51b194dd 100644
--- a/packages/bridge-ui/scripts/vite-plugins/generateCustomTokenConfig.ts
+++ b/packages/bridge-ui/scripts/vite-plugins/generateCustomTokenConfig.ts
@@ -3,7 +3,7 @@ import { promises as fs } from 'fs';
import path from 'path';
import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph';
-import configuredChainsSchema from '../../config/schemas/configuredChains.schema.json';
+import configuredCustomTokens from '../../config/schemas/configuredCustomTokens.schema.json';
import type { Token } from '../../src/libs/token/types';
import { decodeBase64ToJson } from './../utils/decodeBase64ToJson';
import { formatSourceFile } from './../utils/formatSourceFile';
@@ -40,7 +40,7 @@ export function generateCustomTokenConfig() {
configuredTokenConfigFile = decodeBase64ToJson(process.env.CONFIGURED_CUSTOM_TOKENS || '');
// Valid JSON against schema
- const isValid = validateJsonAgainstSchema(configuredTokenConfigFile, configuredChainsSchema);
+ const isValid = validateJsonAgainstSchema(configuredTokenConfigFile, configuredCustomTokens);
if (!isValid) {
throw new Error('encoded generateCustomTokenConfig.json is not valid.');
diff --git a/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/ProcessingFee/ProcessingFee.svelte b/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/ProcessingFee/ProcessingFee.svelte
index 2ded99110c..6aa6b7f9c9 100644
--- a/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/ProcessingFee/ProcessingFee.svelte
+++ b/packages/bridge-ui/src/components/Bridge/SharedBridgeComponents/ProcessingFee/ProcessingFee.svelte
@@ -139,7 +139,7 @@
{#if calculatingRecommendedAmount}
ETH
{:else if errorCalculatingRecommendedAmount}
- {$t('processing_fee.recommended.error')}
+
{:else}
{formatEther($processingFee ?? BigInt(0))} ETH {#if $processingFee !== recommendedAmount}
| {$t('common.customized')}
@@ -153,7 +153,7 @@
{#if calculatingRecommendedAmount}
{:else if errorCalculatingRecommendedAmount}
- {$t('processing_fee.recommended.error')}
+ {$t('processing_fee.recommended.error')}
{:else}
{formatEther($processingFee ?? BigInt(0))} ETH {#if $processingFee !== recommendedAmount}
| {$t('common.customized')}
@@ -179,7 +179,7 @@
{#if calculatingRecommendedAmount}
ETH
{:else if errorCalculatingRecommendedAmount}
- {$t('processing_fee.recommended.error')}
+
{:else}
{formatEther($processingFee ?? BigInt(0))} ETH {#if $processingFee !== recommendedAmount}
| {$t('common.customized')}
@@ -212,7 +212,7 @@
{#if calculatingRecommendedAmount}
ETH
{:else if errorCalculatingRecommendedAmount}
- {$t('processing_fee.recommended.error')}
+
{:else}
{formatEther(recommendedAmount)} ETH
{/if}
@@ -299,7 +299,10 @@
{/if}
-
+
{
return chain;
};
+export const isL2Chain = (chainId: number) => {
+ return chainConfig[chainId].type === LayerType.L2;
+};
+
export const chains: [Chain, ...Chain[]] = Object.entries(chainConfig).map(([chainId, chainConfig]) =>
mapChainConfigToChain(chainId, chainConfig),
) as [Chain, ...Chain[]];
diff --git a/packages/bridge-ui/src/libs/fee/recommendProcessingFee.ts b/packages/bridge-ui/src/libs/fee/recommendProcessingFee.ts
index 796ab923ae..9941d79e0e 100644
--- a/packages/bridge-ui/src/libs/fee/recommendProcessingFee.ts
+++ b/packages/bridge-ui/src/libs/fee/recommendProcessingFee.ts
@@ -1,11 +1,9 @@
-import { getPublicClient } from '@wagmi/core';
-
-import { recommendProcessingFeeConfig } from '$config';
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');
@@ -15,16 +13,6 @@ type RecommendProcessingFeeArgs = {
srcChainId?: number;
};
-const {
- ethGasLimit,
- erc20NotDeployedGasLimit,
- erc20DeployedGasLimit,
- erc1155DeployedGasLimit,
- erc1155NotDeployedGasLimit,
- erc721DeployedGasLimit,
- erc721NotDeployedGasLimit,
-} = recommendProcessingFeeConfig;
-
export async function recommendProcessingFee({
token,
destChainId,
@@ -33,16 +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();
-
- // 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 });
@@ -58,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;
+ 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;
}
diff --git a/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts b/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts
index ed44020974..f5936204bd 100644
--- a/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts
+++ b/packages/bridge-ui/src/libs/relayer/RelayerAPIService.ts
@@ -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';
@@ -278,6 +281,39 @@ export class RelayerAPIService {
}): Promise> {
throw new Error('Not implemented');
}
+
+ async recommendedProcessingFees({
+ typeFilter,
+ destChainIDFilter,
+ }: {
+ typeFilter?: FeeType;
+ destChainIDFilter?: number;
+ }): Promise {
+ const requestURL = `${this.baseUrl}/recommendedProcessingFees`;
+
+ try {
+ const response = await axios.get(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 => {
diff --git a/packages/bridge-ui/src/libs/relayer/initRelayers.ts b/packages/bridge-ui/src/libs/relayer/initRelayers.ts
index bb41e51d49..09757964ca 100644
--- a/packages/bridge-ui/src/libs/relayer/initRelayers.ts
+++ b/packages/bridge-ui/src/libs/relayer/initRelayers.ts
@@ -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 = 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);
diff --git a/packages/bridge-ui/src/libs/relayer/types.ts b/packages/bridge-ui/src/libs/relayer/types.ts
index dc9b30ba8f..90ed2b64ed 100644
--- a/packages/bridge-ui/src/libs/relayer/types.ts
+++ b/packages/bridge-ui/src/libs/relayer/types.ts
@@ -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[] };