From f57b089d5e8da3da3466c7fafcfd3043a951d50c Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Mon, 19 May 2025 16:54:51 +0200 Subject: [PATCH 1/7] enable bnb chain on UI --- frontend/src/hooks/useGetNetworkIcon.tsx | 2 +- frontend/src/wagmiConfig.ts | 27 +++++------ shared/src/helpers/networks.ts | 12 ++--- shared/src/tokens/evm/config.ts | 58 ++++++++++++------------ 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/frontend/src/hooks/useGetNetworkIcon.tsx b/frontend/src/hooks/useGetNetworkIcon.tsx index 175441b19..95839eaa6 100644 --- a/frontend/src/hooks/useGetNetworkIcon.tsx +++ b/frontend/src/hooks/useGetNetworkIcon.tsx @@ -12,7 +12,7 @@ export const NETWORK_ICONS: Record = { [Networks.AssetHub]: ASSET_HUB, [Networks.Polygon]: POLYGON, [Networks.Ethereum]: ETHEREUM, - // [Networks.BSC]: BSC, + [Networks.BSC]: BSC, [Networks.Arbitrum]: ARBITRUM, [Networks.Base]: BASE, [Networks.Avalanche]: AVALANCHE, diff --git a/frontend/src/wagmiConfig.ts b/frontend/src/wagmiConfig.ts index e90b1c9dc..0420350d2 100644 --- a/frontend/src/wagmiConfig.ts +++ b/frontend/src/wagmiConfig.ts @@ -1,29 +1,29 @@ -import { polygon, arbitrum, base, avalanche, mainnet } from '@reown/appkit/networks'; -import { http } from 'wagmi'; -import { config } from './config'; +import { arbitrum, avalanche, base, bsc, mainnet, polygon } from '@reown/appkit/networks'; import { WagmiAdapter } from '@reown/appkit-adapter-wagmi'; import { createAppKit } from '@reown/appkit/react'; +import { http } from 'wagmi'; + +import { config } from './config'; // If we have an Alchemy API key, we can use it to fetch data from Polygon, otherwise use the default endpoint const transports = config.alchemyApiKey ? { - [polygon.id]: http(`https://polygon-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), - [mainnet.id]: http(`https://eth-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), - // [bsc.id]: http(`https://bnb-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), [arbitrum.id]: http(`https://arb-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), - [base.id]: http(`https://base-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), [avalanche.id]: http(`https://avax-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), + [base.id]: http(`https://base-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), + [bsc.id]: http(`https://bnb-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), + [mainnet.id]: http(`https://eth-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), + [polygon.id]: http(`https://polygon-mainnet.g.alchemy.com/v2/${config.alchemyApiKey}`), } : { - [polygon.id]: http(''), - [mainnet.id]: http(''), - // [bsc.id]: http(''), [arbitrum.id]: http(''), - [base.id]: http(''), [avalanche.id]: http(''), + [base.id]: http(''), + [bsc.id]: http(''), + [mainnet.id]: http(''), + [polygon.id]: http(''), }; -// 2. Create a metadata object - optional const metadata = { name: 'Vortex', description: 'Vortex', @@ -31,11 +31,9 @@ const metadata = { icons: [], }; -// 3. Set the networks const networks = [mainnet, polygon, arbitrum, base, avalanche]; const projectId = '495a5f574d57e27fd65caa26d9ea4f10'; -// 4. Create Wagmi Adapter const wagmiAdapter = new WagmiAdapter({ networks, projectId, @@ -43,7 +41,6 @@ const wagmiAdapter = new WagmiAdapter({ transports, }); -// 5. Create modal createAppKit({ adapters: [wagmiAdapter], // @ts-expect-error - networks is not typed diff --git a/shared/src/helpers/networks.ts b/shared/src/helpers/networks.ts index fd0533942..b05b6a300 100644 --- a/shared/src/helpers/networks.ts +++ b/shared/src/helpers/networks.ts @@ -8,7 +8,7 @@ export enum Networks { Arbitrum = 'arbitrum', Avalanche = 'avalanche', Base = 'base', - // BSC = 'bsc', + BSC = 'bsc', Ethereum = 'ethereum', Polygon = 'polygon', Moonbeam = 'moonbeam', @@ -60,11 +60,11 @@ const NETWORK_METADATA: Record = { displayName: 'Ethereum', isEVM: true, }, - // [Networks.BSC]: { - // id: bsc.id, - // displayName: 'BNB Smart Chain', - // isEVM: true, - // }, + [Networks.BSC]: { + id: bsc.id, + displayName: 'BNB Smart Chain', + isEVM: true, + }, [Networks.Arbitrum]: { id: arbitrum.id, displayName: 'Arbitrum One', diff --git a/shared/src/tokens/evm/config.ts b/shared/src/tokens/evm/config.ts index 7e9c0e0f0..20e545444 100644 --- a/shared/src/tokens/evm/config.ts +++ b/shared/src/tokens/evm/config.ts @@ -66,35 +66,35 @@ export const evmTokenConfig: Record> ...PENDULUM_USDC_AXL, }, }, - // [Networks.BSC]: { - // [EvmToken.USDC]: { - // assetSymbol: 'USDC', - // erc20AddressSourceChain: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', // USDC on BSC - // networkAssetIcon: 'bscUSDC', - // decimals: 18, - // network: Networks.BSC, - // type: TokenType.Evm, - // ...PENDULUM_USDC_AXL, - // }, - // [EvmToken.USDT]: { - // assetSymbol: 'USDT', - // erc20AddressSourceChain: '0x55d398326f99059fF775485246999027B3197955', // USDT on BSC - // networkAssetIcon: 'bscUSDT', - // decimals: 18, - // network: Networks.BSC, - // type: TokenType.Evm, - // ...PENDULUM_USDC_AXL, - // }, - // [EvmToken.USDCE]: { - // assetSymbol: 'USDC.e', - // erc20AddressSourceChain: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', // Placeholder, update with actual address - // networkAssetIcon: 'bscUSDC', - // decimals: 18, - // network: Networks.BSC, - // type: TokenType.Evm, - // ...PENDULUM_USDC_AXL, - // }, - // }, + [Networks.BSC]: { + [EvmToken.USDC]: { + assetSymbol: 'USDC', + erc20AddressSourceChain: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', // USDC on BSC + networkAssetIcon: 'bscUSDC', + decimals: 18, + network: Networks.BSC, + type: TokenType.Evm, + ...PENDULUM_USDC_AXL, + }, + [EvmToken.USDT]: { + assetSymbol: 'USDT', + erc20AddressSourceChain: '0x55d398326f99059fF775485246999027B3197955', // USDT on BSC + networkAssetIcon: 'bscUSDT', + decimals: 18, + network: Networks.BSC, + type: TokenType.Evm, + ...PENDULUM_USDC_AXL, + }, + [EvmToken.USDCE]: { + assetSymbol: 'USDC.e', + erc20AddressSourceChain: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', // Placeholder, update with actual address + networkAssetIcon: 'bscUSDC', + decimals: 18, + network: Networks.BSC, + type: TokenType.Evm, + ...PENDULUM_USDC_AXL, + }, + }, [Networks.Arbitrum]: { [EvmToken.USDC]: { assetSymbol: 'USDC', From b65e6d0f43ce82b6ecf4f460940bc0329c8a7b0f Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Mon, 19 May 2025 16:56:23 +0200 Subject: [PATCH 2/7] fix quote calculation decimals in quote.service (use .decimals instead of .pendulumDecimals) --- api/.eslintrc.js | 1 + api/src/api/helpers/contracts.ts | 42 +++++++++++----------- api/src/api/services/ramp/quote.service.ts | 7 ++-- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/api/.eslintrc.js b/api/.eslintrc.js index c5698455b..404ccc2a9 100644 --- a/api/.eslintrc.js +++ b/api/.eslintrc.js @@ -2,6 +2,7 @@ module.exports = { parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], rules: { + 'class-methods-use-this': 'off', 'no-console': 0, 'no-underscore-dangle': 0, 'no-unused-vars': 'off', diff --git a/api/src/api/helpers/contracts.ts b/api/src/api/helpers/contracts.ts index 43b5480b9..d830b7f1f 100644 --- a/api/src/api/helpers/contracts.ts +++ b/api/src/api/helpers/contracts.ts @@ -44,6 +44,28 @@ export interface ContractBalance { approximateNumber: number; } + +export function multiplyByPowerOfTen(bigDecimal: BigNumber, power: number) { + const newBigDecimal = new BigNumber(bigDecimal); + if (newBigDecimal.c[0] === 0) return newBigDecimal; + + newBigDecimal.e += power; + return newBigDecimal; +} + +export function stringifyBigWithSignificantDecimals(big: BigNumber, decimals: number) { + const rounded = roundDownToSignificantDecimals(big, decimals); + + let significantDecimals; + if (rounded.eq(BIG_0)) { + significantDecimals = decimals; + } else { + significantDecimals = Math.max(decimals, Math.min(decimals, rounded.c.length) - 1 - rounded.e); + } + + return rounded.toFixed(significantDecimals, 0); +} + export function parseContractBalanceResponse(decimals: number, balanceResponse: INumber | bigint): ContractBalance; export function parseContractBalanceResponse( @@ -79,23 +101,3 @@ export function parseContractBalanceResponse( }; } -export function stringifyBigWithSignificantDecimals(big: BigNumber, decimals: number) { - const rounded = roundDownToSignificantDecimals(big, decimals); - - let significantDecimals; - if (rounded.eq(BIG_0)) { - significantDecimals = decimals; - } else { - significantDecimals = Math.max(decimals, Math.min(decimals, rounded.c.length) - 1 - rounded.e); - } - - return rounded.toFixed(significantDecimals, 0); -} - -export function multiplyByPowerOfTen(bigDecimal: BigNumber, power: number) { - const newBigDecimal = new BigNumber(bigDecimal); - if (newBigDecimal.c[0] === 0) return newBigDecimal; - - newBigDecimal.e += power; - return newBigDecimal; -} diff --git a/api/src/api/services/ramp/quote.service.ts b/api/src/api/services/ramp/quote.service.ts index d076f3b81..1578cfa12 100644 --- a/api/src/api/services/ramp/quote.service.ts +++ b/api/src/api/services/ramp/quote.service.ts @@ -241,7 +241,7 @@ export class QuoteService extends BaseRampService { const routeParams = createOnrampRouteParams( '0x30a300612ab372cc73e53ffe87fb73d62ed68da3', // It does not matter. amountOut.preciseQuotedAmountOut.rawBalance.toFixed(), - outTokenDetails!, + outTokenDetails, getNetworkFromDestination(to)!, '0x30a300612ab372cc73e53ffe87fb73d62ed68da3', ); @@ -252,10 +252,12 @@ export class QuoteService extends BaseRampService { // Check against our moonbeam funding amounts. const squidrouterSwapValue = multiplyByPowerOfTen(Big(route.transactionRequest.value), -18); + const fundingAmountUnits = getNetworkFromDestination(to) === Networks.Ethereum ? Big(MOONBEAM_EPHEMERAL_STARTING_BALANCE_UNITS_ETHEREUM) : Big(MOONBEAM_EPHEMERAL_STARTING_BALANCE_UNITS); + const squidrouterSwapValueBuffer = getNetworkFromDestination(to) === Networks.Ethereum ? 10 : 2; // Leave 10 glmr for other operations of the ephemeral, and as buffer for potential price changes. @@ -267,9 +269,10 @@ export class QuoteService extends BaseRampService { } amountOut.preciseQuotedAmountOut = parseContractBalanceResponse( - outTokenDetails!.pendulumDecimals, + outTokenDetails.decimals, BigInt(toAmountMin), ); + amountOut.roundedDownQuotedAmountOut = amountOut.preciseQuotedAmountOut.preciseBigDecimal.round(2, 0); amountOut.effectiveExchangeRate = stringifyBigWithSignificantDecimals( amountOut.preciseQuotedAmountOut.preciseBigDecimal.div(new Big(inputAmountAfterFees)), From ceabf96ef74140ed1176ef2e78585027ebeb70e4 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Mon, 19 May 2025 17:11:42 +0200 Subject: [PATCH 3/7] update progress page message for brlaTeleport --- frontend/src/pages/progress/index.tsx | 2 +- frontend/src/translations/en.json | 2 +- frontend/src/translations/pt.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/progress/index.tsx b/frontend/src/pages/progress/index.tsx index 7b5451fc1..3d496a718 100644 --- a/frontend/src/pages/progress/index.tsx +++ b/frontend/src/pages/progress/index.tsx @@ -17,7 +17,7 @@ import { config } from '../../config'; export const ONRAMPING_PHASE_SECONDS: Record = { initial: 0, fundEphemeral: 20, - brlaTeleport: 90, + brlaTeleport: 5 * 60, moonbeamToPendulumXcm: 30, subsidizePreSwap: 24, nablaApprove: 24, diff --git a/frontend/src/translations/en.json b/frontend/src/translations/en.json index a6e4e9cff..b3d3c34fe 100644 --- a/frontend/src/translations/en.json +++ b/frontend/src/translations/en.json @@ -35,7 +35,7 @@ "stellarPayment": "Transferring {{assetSymbol}} from Stellar --> local partner", "squidrouterSwap": "Transferring {{assetSymbol}} from Moonbeam to {{network}}", "pendulumToAssethub": "Transferring {{assetSymbol}} from Pendulum --> AssetHub", - "brlaTeleport": "Transferring newly minted assets to Moonbeam" + "brlaTeleport": "Your payment is being processed. This can take up to 5 minutes." }, "success": { "title": { diff --git a/frontend/src/translations/pt.json b/frontend/src/translations/pt.json index 3705b126a..8d041bd85 100644 --- a/frontend/src/translations/pt.json +++ b/frontend/src/translations/pt.json @@ -35,7 +35,7 @@ "stellarPayment": "Transferindo {{assetSymbol}} de Stellar --> parceiro local", "squidrouterSwap": "Transferindo {{assetSymbol}} de Moonbeam para {{network}}", "pendulumToAssethub": "Transferindo {{assetSymbol}} de Pendulum --> AssetHub", - "brlaTeleport": "Transferindo ativos recém-criados para Moonbeam" + "brlaTeleport": "Seu pagamento está sendo processado. Isso pode levar até 5 minutos." }, "success": { "title": { From b3b2a367294c87118e10bd21234858d630f31de6 Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Mon, 19 May 2025 18:11:14 +0200 Subject: [PATCH 4/7] Re-Add bsc to list of wagmi networks --- frontend/src/wagmiConfig.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/wagmiConfig.ts b/frontend/src/wagmiConfig.ts index 0420350d2..24d8146df 100644 --- a/frontend/src/wagmiConfig.ts +++ b/frontend/src/wagmiConfig.ts @@ -31,7 +31,7 @@ const metadata = { icons: [], }; -const networks = [mainnet, polygon, arbitrum, base, avalanche]; +const networks = [mainnet, polygon, arbitrum, base, avalanche, bsc]; const projectId = '495a5f574d57e27fd65caa26d9ea4f10'; const wagmiAdapter = new WagmiAdapter({ From 4b4f526f0b814d20b855418391c3844073cdca39 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Mon, 19 May 2025 18:47:32 +0200 Subject: [PATCH 5/7] fix outputAmount decimals onrampTransactions.ts --- api/src/api/services/transactions/onrampTransactions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/api/services/transactions/onrampTransactions.ts b/api/src/api/services/transactions/onrampTransactions.ts index 1aef33854..59aab7908 100644 --- a/api/src/api/services/transactions/onrampTransactions.ts +++ b/api/src/api/services/transactions/onrampTransactions.ts @@ -81,7 +81,7 @@ export async function prepareOnrampTransactions( // The output amount to be obtained on Moonbeam, differs from the amount to be obtained on destination evm chain. const outputAmountRaw = (quote.metadata as QuoteTicketMetadata).onrampOutputAmountMoonbeamRaw; - const outputAmount = multiplyByPowerOfTen(new Big(outputAmountRaw), -outputTokenDetails.decimals); + const outputAmount = multiplyByPowerOfTen(new Big(outputAmountRaw), -outputTokenDetails.pendulumDecimals); const inputTokenPendulumDetails = getPendulumDetails(quote.inputCurrency); const outputTokenPendulumDetails = getPendulumDetails(quote.outputCurrency, toNetwork); From 09d873e8efd9cd2c0a2e396eaec88ebb364814d3 Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Mon, 19 May 2025 19:12:41 +0200 Subject: [PATCH 6/7] Fix bug with initial phase message always shown in progress screen --- frontend/src/pages/progress/phaseMessages.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/progress/phaseMessages.ts b/frontend/src/pages/progress/phaseMessages.ts index 00daba5b2..8c5b31530 100644 --- a/frontend/src/pages/progress/phaseMessages.ts +++ b/frontend/src/pages/progress/phaseMessages.ts @@ -19,16 +19,14 @@ export function getMessageForPhase(ramp: RampState | undefined, t: TFunction<'tr const fromNetwork = getNetworkFromDestination(quote.from); const toNetwork = getNetworkFromDestination(quote.to); - if (!fromNetwork || !toNetwork) return t('pages.progress.initial'); - const inputAssetSymbol = currentState.type === 'off' - ? getOnChainTokenDetailsOrDefault(fromNetwork, quote.inputCurrency as OnChainToken).assetSymbol + ? getOnChainTokenDetailsOrDefault(fromNetwork!, quote.inputCurrency as OnChainToken).assetSymbol : getAnyFiatTokenDetails(quote.inputCurrency as FiatToken).assetSymbol; const outputAssetSymbol = currentState.type === 'off' ? getAnyFiatTokenDetails(quote.outputCurrency as FiatToken).assetSymbol - : getOnChainTokenDetailsOrDefault(toNetwork, quote.outputCurrency as OnChainToken).assetSymbol; + : getOnChainTokenDetailsOrDefault(toNetwork!, quote.outputCurrency as OnChainToken).assetSymbol; if (currentPhase === 'complete') return t('pages.progress.success'); From 29e8b2a02111f4215a95c18b0e8962c4c41440bb Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Mon, 19 May 2025 19:16:34 +0200 Subject: [PATCH 7/7] Use proper number of relevant phases for offramps --- frontend/src/pages/progress/index.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/progress/index.tsx b/frontend/src/pages/progress/index.tsx index 3d496a718..d9106abd7 100644 --- a/frontend/src/pages/progress/index.tsx +++ b/frontend/src/pages/progress/index.tsx @@ -12,6 +12,7 @@ import { useRampActions, useRampState, useRampStore } from '../../stores/rampSto import { RampService } from '../../services/api'; import { getMessageForPhase } from './phaseMessages'; import { config } from '../../config'; +import { useRampDirection } from '../../stores/rampDirectionStore'; // The order of the phases is important for the progress bar. export const ONRAMPING_PHASE_SECONDS: Record = { @@ -55,6 +56,7 @@ export const OFFRAMPING_PHASE_SECONDS: Record = { subsidizePostSwap: 24, spacewalkRedeem: 130, stellarPayment: 6, + brlaPayoutOnMoonbeam: 30, complete: 0, timedOut: 0, @@ -65,13 +67,12 @@ export const OFFRAMPING_PHASE_SECONDS: Record = { moonbeamToPendulumXcm: 0, pendulumToAssethub: 0, pendulumToMoonbeam: 0, - brlaPayoutOnMoonbeam: 0, stellarCreateAccount: 0, }; // This constant is used to denote how many of the phases are relevant for the progress bar. // Not all phases are relevant for the progress bar, so we need to exclude some. -const RELEVANT_PHASES_COUNT = 12; +const RELEVANT_PHASES_COUNT = {off: 13, on: 12}; const useProgressUpdate = ( currentPhase: RampPhase, @@ -81,7 +82,8 @@ const useProgressUpdate = ( setDisplayedPercentage: (value: (prev: number) => number) => void, setShowCheckmark: (value: boolean) => void, ) => { - const numberOfPhases = RELEVANT_PHASES_COUNT; + const rampDirection = useRampDirection() + const numberOfPhases = rampDirection === "onramp" ? RELEVANT_PHASES_COUNT.on : RELEVANT_PHASES_COUNT.off; const intervalRef = useRef(null); useEffect(() => {