diff --git a/api/src/api/controllers/brla.controller.ts b/api/src/api/controllers/brla.controller.ts index 6f97d28eb..783c2cbb5 100644 --- a/api/src/api/controllers/brla.controller.ts +++ b/api/src/api/controllers/brla.controller.ts @@ -190,9 +190,9 @@ export const triggerBrlaOfframp = async ( } }; -export const getOfframpStatus = async ( - req: Request, - res: Response, +export const getRampStatus = async ( + req: Request, + res: Response, ): Promise => { try { const { taxId } = req.query; @@ -230,7 +230,7 @@ export const getOfframpStatus = async ( status: lastEventCached.data.status, }); } catch (error) { - handleApiError(error, res, 'getOfframpStatus'); + handleApiError(error, res, 'getRampStatus'); } }; @@ -406,7 +406,7 @@ export const startKYC2 = async ( const subaccount = await brlaApiService.getSubaccount(taxId); if (!subaccount) { - res.status(httpStatus.BAD_REQUEST).json({ error: 'Subaccount not found'}); + res.status(httpStatus.BAD_REQUEST).json({ error: 'Subaccount not found' }); return; } diff --git a/api/src/api/controllers/price.controller.ts b/api/src/api/controllers/price.controller.ts index f37c51fe9..ef345cb7a 100644 --- a/api/src/api/controllers/price.controller.ts +++ b/api/src/api/controllers/price.controller.ts @@ -100,7 +100,9 @@ export const getPriceForProvider: RequestHandler { } next(); -}; \ No newline at end of file +}; diff --git a/api/src/api/routes/v1/brla.route.ts b/api/src/api/routes/v1/brla.route.ts index 8ea6719b6..e2c87178a 100644 --- a/api/src/api/routes/v1/brla.route.ts +++ b/api/src/api/routes/v1/brla.route.ts @@ -12,7 +12,7 @@ router.route('/getUser').get(brlaController.getBrlaUser); router.route('/getUserRemainingLimit').get(brlaController.getBrlaUserRemainingLimit); -router.route('/getOfframpStatus').get(brlaController.getOfframpStatus); +router.route('/getRampStatus').get(brlaController.getRampStatus); router.route('/getKycStatus').get(brlaController.fetchSubaccountKycStatus); diff --git a/api/src/api/services/phases/post-process/moonbeam-post-process-handler.ts b/api/src/api/services/phases/post-process/moonbeam-post-process-handler.ts index dbaea0c20..bfb79475f 100644 --- a/api/src/api/services/phases/post-process/moonbeam-post-process-handler.ts +++ b/api/src/api/services/phases/post-process/moonbeam-post-process-handler.ts @@ -5,6 +5,7 @@ import logger from '../../../../config/logger'; import { ApiManager } from '../../pendulum/apiManager'; import { submitExtrinsic } from '@pendulum-chain/api-solang'; +const CLEANUP_WAITING_TIME_MINUTES = 180; // 3 hours /** * Post process handler for Moonbeam cleanup operations */ @@ -51,10 +52,12 @@ export class MoonbeamPostProcessHandler extends BasePostProcessHandler { const timeDifferenceMs = Date.now() - completeTime.getTime(); const timeDifferenceMinutes = timeDifferenceMs / (1000 * 60); - if (timeDifferenceMinutes < 15) { + if (timeDifferenceMinutes < CLEANUP_WAITING_TIME_MINUTES) { return [ false, - this.createErrorObject(`At least 15 minutes must pass after the complete phase for moonbeam cleanup`), + this.createErrorObject( + `At least ${CLEANUP_WAITING_TIME_MINUTES} minutes must pass after the complete phase for moonbeam cleanup`, + ), ]; } } catch (e) { diff --git a/api/src/api/services/ramp/quote.service.ts b/api/src/api/services/ramp/quote.service.ts index 1578cfa12..cc245a0a0 100644 --- a/api/src/api/services/ramp/quote.service.ts +++ b/api/src/api/services/ramp/quote.service.ts @@ -251,8 +251,7 @@ export class QuoteService extends BaseRampService { const { toAmountMin } = route.estimate; // Check against our moonbeam funding amounts. - const squidrouterSwapValue = multiplyByPowerOfTen(Big(route.transactionRequest.value), -18); - + const squidrouterSwapValue = multiplyByPowerOfTen(new Big(route.transactionRequest.value), -18); const fundingAmountUnits = getNetworkFromDestination(to) === Networks.Ethereum ? Big(MOONBEAM_EPHEMERAL_STARTING_BALANCE_UNITS_ETHEREUM) @@ -268,10 +267,7 @@ export class QuoteService extends BaseRampService { }); } - amountOut.preciseQuotedAmountOut = parseContractBalanceResponse( - outTokenDetails.decimals, - BigInt(toAmountMin), - ); + amountOut.preciseQuotedAmountOut = parseContractBalanceResponse(outTokenDetails.decimals, BigInt(toAmountMin)); amountOut.roundedDownQuotedAmountOut = amountOut.preciseQuotedAmountOut.preciseBigDecimal.round(2, 0); amountOut.effectiveExchangeRate = stringifyBigWithSignificantDecimals( diff --git a/api/src/api/services/slack.service.ts b/api/src/api/services/slack.service.ts index 042dca077..66b47fe87 100644 --- a/api/src/api/services/slack.service.ts +++ b/api/src/api/services/slack.service.ts @@ -34,7 +34,6 @@ export class SlackNotifier { } public async sendMessage(message: SlackMessage): Promise { - const slackUserId = process.env.SLACK_USER_ID; const messageWithUserTag = { diff --git a/api/src/api/services/transactions/squidrouter/config.ts b/api/src/api/services/transactions/squidrouter/config.ts index 1c05b60e2..986bba618 100644 --- a/api/src/api/services/transactions/squidrouter/config.ts +++ b/api/src/api/services/transactions/squidrouter/config.ts @@ -1,5 +1,7 @@ import { AXL_USDC_MOONBEAM, getNetworkId, Networks } from 'shared'; +export const SQUIDROUTER_FEE_OVERPAY = 0.25; // 25% overpayment + interface ConfigBase { toChainId: string; axlUSDC_MOONBEAM: string; diff --git a/api/src/api/services/transactions/squidrouter/onramp.ts b/api/src/api/services/transactions/squidrouter/onramp.ts index 4bb6537d2..af15502c0 100644 --- a/api/src/api/services/transactions/squidrouter/onramp.ts +++ b/api/src/api/services/transactions/squidrouter/onramp.ts @@ -1,9 +1,16 @@ import { createPublicClient, encodeFunctionData, http } from 'viem'; import { moonbeam } from 'viem/chains'; -import { AXL_USDC_MOONBEAM, EvmTokenDetails, getNetworkId, Networks } from 'shared'; +import { AXL_USDC_MOONBEAM, EvmTokenDetails, getNetworkFromDestination, getNetworkId, Networks } from 'shared'; import { createOnrampRouteParams, getRoute } from './route'; import erc20ABI from '../../../../contracts/ERC20'; +import Big from 'big.js'; +import { SQUIDROUTER_FEE_OVERPAY } from './config'; +import { + MOONBEAM_EPHEMERAL_STARTING_BALANCE_UNITS, + MOONBEAM_EPHEMERAL_STARTING_BALANCE_UNITS_ETHEREUM, +} from '../../../../constants/constants'; +import { multiplyByPowerOfTen } from '../../pendulum/helpers'; export interface OnrampSquidrouterParams { fromAddress: string; @@ -35,6 +42,10 @@ export interface OnrampTransactionData { }; } +function bigNumberMin(a: Big, b: Big): Big { + return a.lt(b) ? a : b; +} + export async function createOnrampSquidrouterTransactions( params: OnrampSquidrouterParams, ): Promise { @@ -80,10 +91,21 @@ export async function createOnrampSquidrouterTransactions( maxPriorityFeePerGas: maxPriorityFeePerGas.toString(), }; + const fundingAmountUnits = + getNetworkFromDestination(params.toNetwork) === Networks.Ethereum + ? Big(MOONBEAM_EPHEMERAL_STARTING_BALANCE_UNITS_ETHEREUM) + : Big(MOONBEAM_EPHEMERAL_STARTING_BALANCE_UNITS); + const squidrouterSwapValueBuffer = getNetworkFromDestination(params.toNetwork) === Networks.Ethereum ? 10 : 2; + const freeFundingAmountRaw = multiplyByPowerOfTen(fundingAmountUnits.minus(squidrouterSwapValueBuffer), 18); // 18 decimals for GLMR. Moonbeam is always starting chain. + const overpaidFee = bigNumberMin( + new Big(route.transactionRequest.value).mul(1 + SQUIDROUTER_FEE_OVERPAY), + freeFundingAmountRaw, + ); + const swapData = { to: transactionRequest.target as `0x${string}`, data: transactionRequest.data, - value: transactionRequest.value, + value: overpaidFee.toFixed(0, 0), gas: transactionRequest.gasLimit, maxFeePerGas: maxFeePerGas.toString(), maxPriorityFeePerGas: maxPriorityFeePerGas.toString(), diff --git a/frontend/src/services/api/brla.service.ts b/frontend/src/services/api/brla.service.ts index ec0fb4509..fc81213ac 100644 --- a/frontend/src/services/api/brla.service.ts +++ b/frontend/src/services/api/brla.service.ts @@ -29,8 +29,8 @@ export class BrlaService { * @param taxId The user's tax ID * @returns The offramp status */ - static async getOfframpStatus(taxId: string): Promise { - return apiRequest('get', `${this.BASE_PATH}/getOfframpStatus`, undefined, { + static async getRampStatus(taxId: string): Promise { + return apiRequest('get', `${this.BASE_PATH}/getRampStatus`, undefined, { params: { taxId }, }); } diff --git a/frontend/src/services/signingService.tsx b/frontend/src/services/signingService.tsx index bd82a65d2..bb5d53f7f 100644 --- a/frontend/src/services/signingService.tsx +++ b/frontend/src/services/signingService.tsx @@ -178,7 +178,7 @@ export const fetchSep10Signatures = async ({ }; export const fetchOfframpStatus = async (taxId: string) => { - const statusResponse = await fetch(`${SIGNING_SERVICE_URL}/v1/brla/getOfframpStatus?taxId=${taxId}`); + const statusResponse = await fetch(`${SIGNING_SERVICE_URL}/v1/brla/getRampStatus?taxId=${taxId}`); if (statusResponse.status !== 200) { if (statusResponse.status === 404) { diff --git a/shared/src/endpoints/brla.endpoints.ts b/shared/src/endpoints/brla.endpoints.ts index 2062abc88..4a2e1056a 100644 --- a/shared/src/endpoints/brla.endpoints.ts +++ b/shared/src/endpoints/brla.endpoints.ts @@ -11,12 +11,12 @@ export namespace BrlaEndpoints { kycLevel: number; } - // GET /brla/getOfframpStatus?taxId=:taxId - export interface GetOfframpStatusRequest { + // GET /brla/getRampStatus?taxId=:taxId + export interface GetRampStatusRequest { taxId: string; } - export interface GetOfframpStatusResponse { + export interface GetRampStatusResponse { type: string; status: string; }