From 7487b85c3764251c25e1969bd003e6c8b9c11523 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Fri, 27 Mar 2026 11:18:30 +0100 Subject: [PATCH 001/117] add MXN KYC types, API methods, and SPEI payment mapping --- .../src/helpers/payment-method-mapper.ts | 8 +- .../services/alfredpay/alfredpayApiService.ts | 83 ++++++++++++++++++- .../shared/src/services/alfredpay/types.ts | 29 +++++++ .../shared/src/tokens/freeTokens/config.ts | 4 +- 4 files changed, 119 insertions(+), 5 deletions(-) diff --git a/packages/shared/src/helpers/payment-method-mapper.ts b/packages/shared/src/helpers/payment-method-mapper.ts index 3ecf66d72..36f7bb038 100644 --- a/packages/shared/src/helpers/payment-method-mapper.ts +++ b/packages/shared/src/helpers/payment-method-mapper.ts @@ -51,7 +51,13 @@ export function deriveFromTo( */ export function getPaymentMethodFromDestinations(from: DestinationType, to: DestinationType): PaymentMethod { // Check if 'from' is a payment method - const paymentMethods: PaymentMethod[] = [EPaymentMethod.PIX, EPaymentMethod.SEPA, EPaymentMethod.CBU, EPaymentMethod.ACH]; + const paymentMethods: PaymentMethod[] = [ + EPaymentMethod.PIX, + EPaymentMethod.SEPA, + EPaymentMethod.CBU, + EPaymentMethod.ACH, + EPaymentMethod.SPEI + ]; if (paymentMethods.includes(from as PaymentMethod)) { return from as PaymentMethod; diff --git a/packages/shared/src/services/alfredpay/alfredpayApiService.ts b/packages/shared/src/services/alfredpay/alfredpayApiService.ts index 1130c7002..ec98a21ca 100644 --- a/packages/shared/src/services/alfredpay/alfredpayApiService.ts +++ b/packages/shared/src/services/alfredpay/alfredpayApiService.ts @@ -7,6 +7,7 @@ import { AlfredpayFiatAccountFields, AlfredpayFiatAccountType, AlfredpayFiatCurrency, + AlfredpayKycFileType, AlfredpayOfframpQuote, AlfredpayOnrampQuote, CreateAlfredpayCustomerResponse, @@ -26,8 +27,11 @@ import { GetKycRedirectLinkResponse, GetKycStatusResponse, GetKycSubmissionResponse, + ListAlfredpayFiatAccountsResponse, RetryKybSubmissionResponse, - RetryKycSubmissionResponse + RetryKycSubmissionResponse, + SubmitKycInformationRequest, + SubmitKycInformationResponse } from "./types"; export class AlfredpayApiService { @@ -93,7 +97,21 @@ export class AlfredpayApiService { } if (!response.ok) { - throw new Error(`Request failed with status '${response.status}'. Error: ${await response.text()}`); + const errorText = await response.text(); + if (response.status === 409) { + try { + const parsed = JSON.parse(errorText); + if (parsed.errorCode === 111426 && parsed.errorMetadata) { + const { minQuantity, fromCurrency } = parsed.errorMetadata; + throw new Error(`ALFREDPAY_TRADE_LIMIT:${minQuantity}:${fromCurrency}`); + } + } catch (parseError) { + if (parseError instanceof Error && parseError.message.startsWith("ALFREDPAY_TRADE_LIMIT:")) { + throw parseError; + } + } + } + throw new Error(`Request failed with status '${response.status}'. Error: ${errorText}`); } try { return await response.json(); @@ -213,4 +231,65 @@ export class AlfredpayApiService { const path = "/api/v1/third-party-service/penny/fiatAccounts"; return (await this.executeRequest(path, "POST", payload)) as CreateAlfredpayFiatAccountResponse; } + + public async createFiatAccount( + customerId: string, + type: AlfredpayFiatAccountType, + fiatAccountFields: AlfredpayFiatAccountFields + ): Promise { + const payload: CreateAlfredpayFiatAccountRequest = { customerId, fiatAccountFields, type }; + const path = "/api/v1/third-party-service/penny/fiatAccounts"; + return (await this.executeRequest(path, "POST", payload)) as CreateAlfredpayFiatAccountResponse; + } + + public async listFiatAccounts(customerId: string): Promise { + const path = `/api/v1/third-party-service/penny/fiatAccounts?customerId=${encodeURIComponent(customerId)}`; + return (await this.executeRequest(path, "GET")) as ListAlfredpayFiatAccountsResponse; + } + + public async deleteFiatAccount(fiatAccountId: string): Promise { + const path = `/api/v1/third-party-service/penny/fiatAccounts/${encodeURIComponent(fiatAccountId)}`; + await this.executeRequest(path, "DELETE"); + } + + public async submitKycInformation( + customerId: string, + data: SubmitKycInformationRequest + ): Promise { + const path = `/api/v1/third-party-service/penny/customers/${customerId}/kyc`; + return (await this.executeRequest(path, "POST", { + kycSubmission: { ...data, nationalities: [data.country] } + })) as SubmitKycInformationResponse; + } + + public async submitKycFile( + customerId: string, + submissionId: string, + fileType: AlfredpayKycFileType, + file: Blob + ): Promise { + const formData = new FormData(); + formData.append("fileBody", file); + formData.append("fileType", fileType); + + const url = `${ALFREDPAY_BASE_URL}/api/v1/third-party-service/penny/customers/${customerId}/kyc/${submissionId}/files`; + const response = await fetch(url, { + body: formData, + headers: { + "api-key": this.apiKey, + "api-secret": this.apiSecret + }, + method: "POST" + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Failed to upload KYC file: ${errorText}`); + } + } + + public async sendKycSubmission(customerId: string, submissionId: string): Promise { + const path = `/api/v1/third-party-service/penny/customers/${customerId}/kyc/${submissionId}/submit`; + await this.executeRequest(path, "POST"); + } } diff --git a/packages/shared/src/services/alfredpay/types.ts b/packages/shared/src/services/alfredpay/types.ts index 4ea36bfbb..64428b3d5 100644 --- a/packages/shared/src/services/alfredpay/types.ts +++ b/packages/shared/src/services/alfredpay/types.ts @@ -338,3 +338,32 @@ export type ListAlfredpayFiatAccountsResponse = AlfredpayFiatAccount[]; const ALFREDPAY_FIAT_TOKEN_SET = new Set([FiatToken.USD, FiatToken.MXN, FiatToken.COP]); export const isAlfredpayToken = (token: FiatToken): boolean => ALFREDPAY_FIAT_TOKEN_SET.has(token); + +// MXN KYC form submission types +export enum AlfredpayDocumentType { + INE = "INE", + RESIDENT_CARD = "Resident card", + PASSPORT = "passport" +} + +export interface SubmitKycInformationRequest { + firstName: string; + lastName: string; + dateOfBirth: string; // YYYY-MM-DD + email: string; + country: string; + city: string; + state: string; + zipCode: string; + address: string; + dni: string; +} + +export interface SubmitKycInformationResponse { + submissionId: string; +} + +export enum AlfredpayKycFileType { + FRONT = "National ID Front", + BACK = "National ID Back" +} diff --git a/packages/shared/src/tokens/freeTokens/config.ts b/packages/shared/src/tokens/freeTokens/config.ts index 3b19068d7..3d5fcfc01 100644 --- a/packages/shared/src/tokens/freeTokens/config.ts +++ b/packages/shared/src/tokens/freeTokens/config.ts @@ -29,8 +29,8 @@ export const freeTokenConfig: Partial> = }, maxBuyAmountRaw: "10000000000", maxSellAmountRaw: "100000000000000000000", - minBuyAmountRaw: "1", - minSellAmountRaw: "0.01", + minBuyAmountRaw: "5000", + minSellAmountRaw: "5000", type: TokenType.Fiat }, [FiatToken.COP]: { From d737d88201aedf3b6f49f57748283f975554e0dc Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Fri, 27 Mar 2026 11:19:17 +0100 Subject: [PATCH 002/117] remove mcp.json --- .mcp.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .mcp.json diff --git a/.mcp.json b/.mcp.json deleted file mode 100644 index a8a3dab29..000000000 --- a/.mcp.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "mcpServers": { - "linear-server": { - "type": "sse", - "url": "https://mcp.linear.app/sse" - }, - "obsidian": { - "args": ["-y", "obsidian-mcp", "/Users/kacpersatoshipay/Obsidian/Sharqiewicz"], - "command": "npx" - } - } -} From 469e9adad50e4ee54b5906f0ed624159a4d63871 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Fri, 27 Mar 2026 11:30:57 +0100 Subject: [PATCH 003/117] add MXN KYC endpoints and propagate email from Supabase JWT --- apps/api/package.json | 2 + .../api/controllers/alfredpay.controller.ts | 199 +++++++++++++++++- apps/api/src/api/middlewares/supabaseAuth.ts | 2 + apps/api/src/api/routes/v1/alfredpay.route.ts | 12 ++ .../src/api/services/auth/supabase.service.ts | 2 + 5 files changed, 206 insertions(+), 11 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index 43e2381dd..ccf621cea 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -12,6 +12,7 @@ "@polkadot/util-crypto": "catalog:", "@scure/bip39": "^1.5.4", "@supabase/supabase-js": "catalog:", + "@types/multer": "^2.1.0", "@vortexfi/shared": "workspace:*", "@wagmi/core": "catalog:", "axios": "catalog:", @@ -34,6 +35,7 @@ "joi": "^17.13.3", "method-override": "^3.0.0", "morgan": "^1.8.1", + "multer": "^2.1.1", "node-cache": "^5.1.2", "p-limit": "^6.1.0", "pg": "^8.14.1", diff --git a/apps/api/src/api/controllers/alfredpay.controller.ts b/apps/api/src/api/controllers/alfredpay.controller.ts index 1feafa3b0..5bf4c6d2c 100644 --- a/apps/api/src/api/controllers/alfredpay.controller.ts +++ b/apps/api/src/api/controllers/alfredpay.controller.ts @@ -1,23 +1,26 @@ import { AlfredPayCountry, AlfredPayStatus, + AlfredpayAddFiatAccountRequest, AlfredpayApiService, AlfredpayCreateCustomerRequest, AlfredpayCreateCustomerResponse, AlfredpayCustomerType, + AlfredpayFiatAccountType, AlfredpayGetKybRedirectLinkResponse, AlfredpayGetKycRedirectLinkRequest, AlfredpayGetKycRedirectLinkResponse, AlfredpayGetKycStatusResponse, AlfredpayKybStatus, + AlfredpayKycFileType, AlfredpayKycStatus, AlfredpayStatusRequest, - AlfredpayStatusResponse + AlfredpayStatusResponse, + SubmitKycInformationRequest } from "@vortexfi/shared"; import { Request, Response } from "express"; import logger from "../../config/logger"; import AlfredPayCustomer from "../../models/alfredPayCustomer.model"; -import { SupabaseAuthService } from "../services/auth/supabase.service"; export class AlfredpayController { private static mapKycStatus(status: AlfredpayKycStatus): AlfredPayStatus | null { @@ -96,10 +99,10 @@ export class AlfredpayController { try { const { country } = req.body as AlfredpayCreateCustomerRequest; const userId = req.userId!; + const userEmail = req.userEmail; - const user = await SupabaseAuthService.getUserProfile(userId); - if (!user || !user.email) { - return res.status(404).json({ error: "User not found or email missing" }); + if (!userEmail) { + return res.status(400).json({ error: "User email not available" }); } // Check if customer already exists in our DB @@ -113,7 +116,7 @@ export class AlfredpayController { const alfredpayService = AlfredpayApiService.getInstance(); - const newCustomer = await alfredpayService.createCustomer(user.email, AlfredpayCustomerType.INDIVIDUAL, country); + const newCustomer = await alfredpayService.createCustomer(userEmail, AlfredpayCustomerType.INDIVIDUAL, country); const customerId = newCustomer.customerId; await AlfredPayCustomer.create({ @@ -131,7 +134,8 @@ export class AlfredpayController { res.json(response); } catch (error) { logger.error("Error creating Alfredpay customer:", error); - res.status(500).json({ error: "Internal server error" }); + const message = error instanceof Error ? error.message : "Internal server error"; + res.status(500).json({ error: message }); } } @@ -338,10 +342,10 @@ export class AlfredpayController { try { const { country } = req.body as { country: string }; const userId = req.userId!; + const userEmail = req.userEmail; - const user = await SupabaseAuthService.getUserProfile(userId); - if (!user || !user.email) { - return res.status(404).json({ error: "User not found or email missing" }); + if (!userEmail) { + return res.status(400).json({ error: "User email not available" }); } const type = AlfredpayCustomerType.BUSINESS; @@ -356,7 +360,7 @@ export class AlfredpayController { const alfredpayService = AlfredpayApiService.getInstance(); - const newCustomer = await alfredpayService.createCustomer(user.email, type, country); + const newCustomer = await alfredpayService.createCustomer(userEmail, type, country); const customerId = newCustomer.customerId; await AlfredPayCustomer.create({ @@ -417,4 +421,177 @@ export class AlfredpayController { res.status(500).json({ error: "Internal server error" }); } } + + static async submitKycInformation(req: Request, res: Response) { + try { + const { country, ...kycData } = req.body as SubmitKycInformationRequest & { country: string }; + const userId = req.userId!; + + const alfredPayCustomer = await AlfredPayCustomer.findOne({ + where: { country: country as AlfredPayCountry, type: AlfredpayCustomerType.INDIVIDUAL, userId } + }); + + if (!alfredPayCustomer) { + return res.status(404).json({ error: "Alfredpay customer not found" }); + } + + const alfredpayService = AlfredpayApiService.getInstance(); + const result = await alfredpayService.submitKycInformation(alfredPayCustomer.alfredPayId, { ...kycData, country }); + + res.json(result); + } catch (error) { + logger.error("Error submitting KYC information:", error); + const message = error instanceof Error ? error.message : "Internal server error"; + res.status(500).json({ error: message }); + } + } + + static async submitKycFile(req: Request, res: Response) { + try { + const { country, submissionId, fileType } = req.body as { country: string; submissionId: string; fileType: string }; + const userId = req.userId!; + + if (!req.file) { + return res.status(400).json({ error: "No file uploaded" }); + } + + const alfredPayCustomer = await AlfredPayCustomer.findOne({ + where: { country: country as AlfredPayCountry, type: AlfredpayCustomerType.INDIVIDUAL, userId } + }); + + if (!alfredPayCustomer) { + return res.status(404).json({ error: "Alfredpay customer not found" }); + } + + const fileBlob = new File([req.file.buffer], req.file.originalname, { type: req.file.mimetype }); + const alfredpayService = AlfredpayApiService.getInstance(); + await alfredpayService.submitKycFile( + alfredPayCustomer.alfredPayId, + submissionId, + fileType as AlfredpayKycFileType, + fileBlob + ); + + res.json({ success: true }); + } catch (error) { + logger.error("Error submitting KYC file:", error); + const message = error instanceof Error ? error.message : "Internal server error"; + res.status(500).json({ error: message }); + } + } + + static async sendKycSubmission(req: Request, res: Response) { + try { + const { country, submissionId } = req.body as { country: string; submissionId: string }; + const userId = req.userId!; + + const alfredPayCustomer = await AlfredPayCustomer.findOne({ + where: { country: country as AlfredPayCountry, type: AlfredpayCustomerType.INDIVIDUAL, userId } + }); + + if (!alfredPayCustomer) { + return res.status(404).json({ error: "Alfredpay customer not found" }); + } + + const alfredpayService = AlfredpayApiService.getInstance(); + await alfredpayService.sendKycSubmission(alfredPayCustomer.alfredPayId, submissionId); + + res.json({ success: true }); + } catch (error) { + logger.error("Error sending KYC submission:", error); + const message = error instanceof Error ? error.message : "Internal server error"; + res.status(500).json({ error: message }); + } + } + + static async addFiatAccount(req: Request, res: Response) { + try { + const { + country, + type, + accountNumber, + accountType, + accountName, + accountBankCode, + accountAlias, + routingNumber, + networkIdentifier + } = req.body as AlfredpayAddFiatAccountRequest; + const userId = req.userId!; + + const alfredPayCustomer = await AlfredPayCustomer.findOne({ + order: [["updatedAt", "DESC"]], + where: { country: country as AlfredPayCountry, userId } + }); + + if (!alfredPayCustomer) { + return res.status(404).json({ error: "Alfredpay customer not found" }); + } + + const alfredpayService = AlfredpayApiService.getInstance(); + const result = await alfredpayService.createFiatAccount(alfredPayCustomer.alfredPayId, type as AlfredpayFiatAccountType, { + accountAlias: accountAlias ?? "", + accountBankCode, + accountName, + accountNumber, + accountType: accountType ?? "", + networkIdentifier: networkIdentifier ?? "", + routingNumber + }); + + res.json(result); + } catch (error) { + logger.error("Error adding fiat account:", error); + res.status(500).json({ error: "Internal server error" }); + } + } + + static async listFiatAccounts(req: Request, res: Response) { + try { + const { country } = req.query as { country: string }; + const userId = req.userId!; + + const alfredPayCustomer = await AlfredPayCustomer.findOne({ + order: [["updatedAt", "DESC"]], + where: { country: country as AlfredPayCountry, userId } + }); + + if (!alfredPayCustomer) { + return res.status(404).json({ error: "Alfredpay customer not found" }); + } + + const alfredpayService = AlfredpayApiService.getInstance(); + const accounts = await alfredpayService.listFiatAccounts(alfredPayCustomer.alfredPayId); + + res.json(accounts); + } catch (error) { + logger.error("Error listing fiat accounts:", error); + res.status(500).json({ error: "Internal server error" }); + } + } + + static async deleteFiatAccount(req: Request, res: Response) { + try { + const { fiatAccountId } = req.params; + const { country } = req.query as { country: string }; + const userId = req.userId!; + + const alfredPayCustomer = await AlfredPayCustomer.findOne({ + order: [["updatedAt", "DESC"]], + where: { country: country as AlfredPayCountry, userId } + }); + + if (!alfredPayCustomer) { + return res.status(404).json({ error: "Alfredpay customer not found" }); + } + + const alfredpayService = AlfredpayApiService.getInstance(); + await alfredpayService.deleteFiatAccount(fiatAccountId); + + res.status(204).send(); + } catch (error) { + logger.error("Error deleting fiat account:", error); + res.status(500).json({ error: "Internal server error" }); + } + } } diff --git a/apps/api/src/api/middlewares/supabaseAuth.ts b/apps/api/src/api/middlewares/supabaseAuth.ts index eb2479211..3137a7a66 100644 --- a/apps/api/src/api/middlewares/supabaseAuth.ts +++ b/apps/api/src/api/middlewares/supabaseAuth.ts @@ -6,6 +6,7 @@ declare global { namespace Express { interface Request { userId?: string; + userEmail?: string; } } } @@ -33,6 +34,7 @@ export async function requireAuth(req: Request, res: Response, next: NextFunctio } req.userId = result.user_id; + req.userEmail = result.email; next(); } catch (error) { console.error("Auth middleware error:", error); diff --git a/apps/api/src/api/routes/v1/alfredpay.route.ts b/apps/api/src/api/routes/v1/alfredpay.route.ts index 3fd75cfe0..5cfd3925c 100644 --- a/apps/api/src/api/routes/v1/alfredpay.route.ts +++ b/apps/api/src/api/routes/v1/alfredpay.route.ts @@ -1,9 +1,11 @@ import { Router } from "express"; +import multer from "multer"; import { AlfredpayController } from "../../controllers/alfredpay.controller"; import { validateResultCountry } from "../../middlewares/alfredpay.middleware"; import { requireAuth } from "../../middlewares/supabaseAuth"; const router = Router(); +const upload = multer({ limits: { fileSize: 5 * 1024 * 1024 }, storage: multer.memoryStorage() }); router.get("/alfredpayStatus", requireAuth, validateResultCountry, AlfredpayController.alfredpayStatus); router.post("/createIndividualCustomer", requireAuth, validateResultCountry, AlfredpayController.createIndividualCustomer); @@ -15,4 +17,14 @@ router.post("/retryKyc", requireAuth, validateResultCountry, AlfredpayController router.post("/createBusinessCustomer", requireAuth, validateResultCountry, AlfredpayController.createBusinessCustomer); router.get("/getKybRedirectLink", requireAuth, validateResultCountry, AlfredpayController.getKybRedirectLink); +// MXN API-based KYC +router.post("/submitKycInformation", requireAuth, validateResultCountry, AlfredpayController.submitKycInformation); +router.post("/submitKycFile", requireAuth, upload.single("file"), validateResultCountry, AlfredpayController.submitKycFile); +router.post("/sendKycSubmission", requireAuth, validateResultCountry, AlfredpayController.sendKycSubmission); + +// Fiat accounts (USD + MXN) +router.post("/fiatAccounts", requireAuth, validateResultCountry, AlfredpayController.addFiatAccount); +router.get("/fiatAccounts", requireAuth, validateResultCountry, AlfredpayController.listFiatAccounts); +router.delete("/fiatAccounts/:fiatAccountId", requireAuth, validateResultCountry, AlfredpayController.deleteFiatAccount); + export default router; diff --git a/apps/api/src/api/services/auth/supabase.service.ts b/apps/api/src/api/services/auth/supabase.service.ts index 1743ee606..50aaa56e3 100644 --- a/apps/api/src/api/services/auth/supabase.service.ts +++ b/apps/api/src/api/services/auth/supabase.service.ts @@ -143,6 +143,7 @@ export class SupabaseAuthService { static async verifyToken(accessToken: string): Promise<{ valid: boolean; user_id?: string; + email?: string; }> { const { data, error } = await supabase.auth.getUser(accessToken); @@ -151,6 +152,7 @@ export class SupabaseAuthService { } return { + email: data.user.email, user_id: data.user.id, valid: true }; From dd639e526d7f3e4db2ae3f545f363ac418f7a4c2 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Fri, 27 Mar 2026 11:37:45 +0100 Subject: [PATCH 004/117] route MXN onramp through AlfredPay and add SPEI quote support --- .../api/src/api/services/priceFeed.service.ts | 21 ++++++++++++++++++- .../src/api/services/quote/core/helpers.ts | 6 ++++-- .../services/quote/engines/discount/onramp.ts | 5 +++++ .../services/quote/engines/finalize/onramp.ts | 13 +++++++++--- apps/api/src/api/services/quote/index.ts | 12 +++++++++++ .../services/quote/routes/route-resolver.ts | 8 ++++++- 6 files changed, 58 insertions(+), 7 deletions(-) diff --git a/apps/api/src/api/services/priceFeed.service.ts b/apps/api/src/api/services/priceFeed.service.ts index c6b3ae996..bc36ad285 100644 --- a/apps/api/src/api/services/priceFeed.service.ts +++ b/apps/api/src/api/services/priceFeed.service.ts @@ -199,6 +199,26 @@ export class PriceFeedService { return cachedEntry.value; } + // Check if the currency has a Pendulum representative (Nabla pool). + // Currencies like MXN and COP are TokenType.Fiat with no Pendulum pool — use CoinGecko for those. + let outputTokenPendulumDetails; + try { + outputTokenPendulumDetails = getPendulumDetails(toCurrency); + } catch { + // No Pendulum representative — fall back to CoinGecko using USDC as a USD proxy. + logger.debug(`Cache miss for ${cacheKey}. No Pendulum pool for ${toCurrency}, fetching from CoinGecko.`); + try { + const rate = await this.getCryptoPrice("usd-coin", toCurrency.toLowerCase()); + this.fiatExchangeRateCache.set(cacheKey, { expiresAt: now + this.fiatCacheTtlMs, value: rate }); + return rate; + } catch (cgError) { + if (cgError instanceof Error) { + logger.error(`Error fetching fiat exchange rate from ${fromCurrency} to ${toCurrency}: ${cgError.message}`); + } + throw cgError; + } + } + logger.debug(`Cache miss for ${cacheKey}. Fetching from Nabla.`); try { @@ -211,7 +231,6 @@ export class PriceFeedService { // We assume that the exchange rate from axlUSDC to the target currency in the Forex AMM // resemble the real fiat exchange rate. const inputTokenPendulumDetails = PENDULUM_USDC_AXL; - const outputTokenPendulumDetails = getPendulumDetails(toCurrency); // Call getTokenOutAmount to get the exchange rate const amountOut = await getTokenOutAmount({ diff --git a/apps/api/src/api/services/quote/core/helpers.ts b/apps/api/src/api/services/quote/core/helpers.ts index 7f68d00d3..abb6b96ca 100644 --- a/apps/api/src/api/services/quote/core/helpers.ts +++ b/apps/api/src/api/services/quote/core/helpers.ts @@ -23,14 +23,16 @@ export const SUPPORTED_CHAINS: { EPaymentMethod.PIX as DestinationType, EPaymentMethod.SEPA as DestinationType, EPaymentMethod.CBU as DestinationType, - EPaymentMethod.ACH as DestinationType + EPaymentMethod.ACH as DestinationType, + EPaymentMethod.SPEI as DestinationType ] }, [RampDirection.BUY]: { from: [ EPaymentMethod.PIX as DestinationType, EPaymentMethod.SEPA as DestinationType, - EPaymentMethod.ACH as DestinationType + EPaymentMethod.ACH as DestinationType, + EPaymentMethod.SPEI as DestinationType ], to: [ Networks.AssetHub, diff --git a/apps/api/src/api/services/quote/engines/discount/onramp.ts b/apps/api/src/api/services/quote/engines/discount/onramp.ts index dd8cf1ebc..6265b8d9f 100644 --- a/apps/api/src/api/services/quote/engines/discount/onramp.ts +++ b/apps/api/src/api/services/quote/engines/discount/onramp.ts @@ -70,10 +70,15 @@ export class OnRampDiscountEngine extends BaseDiscountEngine { const targetOutputAmountDecimal = actualOutputAmountDecimal.plus(actualSubsidyAmountDecimal); const targetOutputAmountRaw = Big(actualOutputAmountRaw).plus(actualSubsidyAmountRaw).toFixed(0, 0); + console.log("expectedOutputAmountDecimal: ", expectedOutputAmountDecimal); + console.log("actualSubsidyAmountDecimal: ", actualSubsidyAmountDecimal); + const subsidyRate = expectedOutputAmountDecimal.gt(0) ? actualSubsidyAmountDecimal.div(expectedOutputAmountDecimal) : new Big(0); + console.log("subsidyRate: ", subsidyRate); + return { actualOutputAmountDecimal, actualOutputAmountRaw, diff --git a/apps/api/src/api/services/quote/engines/finalize/onramp.ts b/apps/api/src/api/services/quote/engines/finalize/onramp.ts index 418d04881..812845b67 100644 --- a/apps/api/src/api/services/quote/engines/finalize/onramp.ts +++ b/apps/api/src/api/services/quote/engines/finalize/onramp.ts @@ -46,11 +46,18 @@ export class OnRampFinalizeEngine extends BaseFinalizeEngine { }); } finalOutputAmountDecimal = new Big(output); - } else if (request.inputCurrency === FiatToken.USD) { - const output = ctx.alfredpayMint?.outputAmountDecimal; + } else if ( + request.inputCurrency === FiatToken.USD || + request.inputCurrency === FiatToken.MXN || + request.inputCurrency === FiatToken.COP + ) { + // evmToEvm is set when Squid Router ran (e.g. USDC Polygon → USDT Arbitrum). + // When destination is USDC on Polygon, Squid Router is skipped (skipRouteCalculation) + // because Alfredpay already minted USDC there — use the mint output directly. + const output = ctx.evmToEvm?.outputAmountDecimal ?? ctx.alfredpayMint?.outputAmountDecimal; if (!output) { throw new APIError({ - message: "OnRampFinalizeEngine requires alfredpayMint output for EVM", + message: "OnRampFinalizeEngine requires bridge output for EVM", status: httpStatus.INTERNAL_SERVER_ERROR }); } diff --git a/apps/api/src/api/services/quote/index.ts b/apps/api/src/api/services/quote/index.ts index bba4852b0..39e052328 100644 --- a/apps/api/src/api/services/quote/index.ts +++ b/apps/api/src/api/services/quote/index.ts @@ -188,6 +188,18 @@ export class QuoteService extends BaseRampService { throw error; } + // Detect Alfredpay trade limit error and surface it as a user-facing limit error + if (error instanceof Error && error.message.startsWith("ALFREDPAY_TRADE_LIMIT:")) { + const [, minQuantity, currency] = error.message.split(":"); + const isOnramp = ctx.request.rampType === RampDirection.BUY; + throw new APIError({ + message: isOnramp + ? `${QuoteError.BelowLowerLimitBuy} ${minQuantity} ${currency}` + : `${QuoteError.BelowLowerLimitSell} ${minQuantity} ${currency}`, + status: httpStatus.BAD_REQUEST + }); + } + // Wrap unexpected errors as generic failure throw new APIError({ message: QuoteError.FailedToCalculateQuote, status: httpStatus.INTERNAL_SERVER_ERROR }); } diff --git a/apps/api/src/api/services/quote/routes/route-resolver.ts b/apps/api/src/api/services/quote/routes/route-resolver.ts index 9012fc271..d3c50e4a6 100644 --- a/apps/api/src/api/services/quote/routes/route-resolver.ts +++ b/apps/api/src/api/services/quote/routes/route-resolver.ts @@ -26,7 +26,11 @@ export class RouteResolver { } else { if (ctx.request.inputCurrency === FiatToken.EURC) { return new OnrampMoneriumToEvmStrategy(); - } else if (ctx.request.inputCurrency === FiatToken.USD) { + } else if ( + ctx.request.inputCurrency === FiatToken.USD || + ctx.request.inputCurrency === FiatToken.MXN || + ctx.request.inputCurrency === FiatToken.COP + ) { return new OnrampAlfredpayToEvmStrategy(); } else { return new OnrampAveniaToEvmStrategy(); @@ -48,7 +52,9 @@ export class RouteResolver { switch (ctx.to) { case "pix": return new OfframpToPixStrategy(); + case "wire": case "ach": + case "spei": return new OfframpEvmToAlfredpayStrategy(); case "sepa": case "cbu": From 816f9677d93fc0bf5609c3561b4afd82770c094f Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Fri, 27 Mar 2026 11:38:22 +0100 Subject: [PATCH 005/117] implement MXN KYC form, document upload, and submission flow --- .../components/Alfredpay/AlfredpayKycFlow.tsx | 33 ++- .../src/hooks/ramp/useRampSubmission.ts | 5 +- .../src/machines/alfredpayKyc.machine.ts | 208 +++++++++++++++--- apps/frontend/src/machines/kyc.states.ts | 13 +- .../src/services/api/alfredpay.service.ts | 26 +++ 5 files changed, 242 insertions(+), 43 deletions(-) diff --git a/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx b/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx index 9b43d8150..2f1000faf 100644 --- a/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx +++ b/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx @@ -7,6 +7,8 @@ import { FailureScreen } from "./FailureScreen"; import { FillingScreen } from "./FillingScreen"; import { LinkReadyScreen } from "./LinkReadyScreen"; import { LoadingScreen } from "./LoadingScreen"; +import { MxnDocumentUploadScreen } from "./MxnDocumentUploadScreen"; +import { MxnKycFormScreen } from "./MxnKycFormScreen"; import { OpeningLinkScreen } from "./OpeningLinkScreen"; import { PollingScreen } from "./PollingScreen"; @@ -23,34 +25,55 @@ export const AlfredpayKycFlow = () => { const userCancel = useCallback(() => actor?.send({ type: "USER_CANCEL" }), [actor]); const retryProcess = useCallback(() => actor?.send({ type: "RETRY_PROCESS" }), [actor]); const cancelProcess = useCallback(() => actor?.send({ type: "CANCEL_PROCESS" }), [actor]); + const submitForm = useCallback( + (data: import("../../machines/alfredpayKyc.machine").MxnKycFormData) => actor?.send({ data, type: "SUBMIT_FORM" }), + [actor] + ); + const submitFiles = useCallback( + (files: import("../../machines/alfredpayKyc.machine").MxnKycFiles) => actor?.send({ files, type: "SUBMIT_FILES" }), + [actor] + ); if (!actor || !state) return null; const { stateValue, context } = state; const kycOrKyb = context.business ? "KYB" : "KYC"; + const isMxn = context.country === "MX"; if ( stateValue === "CheckingStatus" || stateValue === "CreatingCustomer" || stateValue === "GettingKycLink" || - stateValue === "Retrying" + stateValue === "Retrying" || + stateValue === "SubmittingKycInfo" || + stateValue === "SubmittingFiles" || + stateValue === "SendingSubmission" ) { return ; } + if (stateValue === "FillingKycForm" && isMxn) { + return ; + } + + if (stateValue === "UploadingDocuments" && isMxn) { + return ; + } + if (stateValue === "PollingStatus") { return ; } - if (stateValue === "LinkReady") { + // USD-only screens + if (stateValue === "LinkReady" && !isMxn) { return ; } - if (stateValue === "OpeningLink") { + if (stateValue === "OpeningLink" && !isMxn) { return ; } - if (stateValue === "FillingKyc" || stateValue === "FinishingFilling") { + if ((stateValue === "FillingKyc" || stateValue === "FinishingFilling") && !isMxn) { return ( { return ; } - if (stateValue === "CostumerDefinition") { + if (stateValue === "CustomerDefinition" && !isMxn) { return ( { ); const onRampConfirm = useCallback( - async (data?: { pixId?: string; taxId?: string; walletAddress?: string; moneriumWalletAddress?: string }) => { + async (data: { pixId?: string; taxId?: string; walletAddress?: string; moneriumWalletAddress?: string } = {}) => { if (executionPreparing) return; setExecutionPreparing(true); try { - if (!data) { - throw new Error("Invalid ramp data."); - } console.log("DEBUG: Ramp Submission Data: ", data); const executionInput = await prepareExecutionInput(data); diff --git a/apps/frontend/src/machines/alfredpayKyc.machine.ts b/apps/frontend/src/machines/alfredpayKyc.machine.ts index b41699dc3..b63416666 100644 --- a/apps/frontend/src/machines/alfredpayKyc.machine.ts +++ b/apps/frontend/src/machines/alfredpayKyc.machine.ts @@ -1,8 +1,25 @@ -import { AlfredPayStatus, AlfredpayCustomerType } from "@vortexfi/shared"; +import { AlfredPayStatus, AlfredpayCustomerType, AlfredpayKycFileType } from "@vortexfi/shared"; import { assign, fromPromise, setup } from "xstate"; import { AlfredpayService } from "../services/api/alfredpay.service"; import { AlfredpayKycContext } from "./kyc.states"; +export interface MxnKycFormData { + firstName: string; + lastName: string; + dateOfBirth: string; + email: string; + city: string; + state: string; + zipCode: string; + address: string; + dni: string; +} + +export interface MxnKycFiles { + front: File; + back: File; +} + const POLLING_TIMEOUT_MS = 20 * 60 * 1000; // 20 minutes export enum AlfredpayKycMachineErrorType { @@ -56,12 +73,10 @@ export const alfredpayKycMachine = setup({ input.business ? AlfredpayCustomerType.BUSINESS : AlfredpayCustomerType.INDIVIDUAL ); }), - pollStatus: fromPromise(async ({ input }: { input: AlfredpayKycContext }) => { + pollStatus: fromPromise(async ({ input, signal }: { input: AlfredpayKycContext; signal: AbortSignal }) => { const country = input.country || "US"; - // Submission ID check removed as backend handles it - const startTime = Date.now(); - while (true) { + while (!signal.aborted) { if (Date.now() - startTime > POLLING_TIMEOUT_MS) { throw new Error("Polling timeout"); } @@ -74,10 +89,18 @@ export const alfredpayKycMachine = setup({ return response; } } catch (e) { + if (signal.aborted) throw e; // Ignore and retry } - await new Promise(resolve => setTimeout(resolve, 5000)); + await new Promise((resolve, reject) => { + const id = setTimeout(resolve, 5000); + signal.addEventListener("abort", () => { + clearTimeout(id); + reject(new Error("Aborted")); + }); + }); } + throw new Error("Aborted"); }), retryKyc: fromPromise(async ({ input }: { input: AlfredpayKycContext }) => { const country = input.country || "US"; @@ -86,12 +109,34 @@ export const alfredpayKycMachine = setup({ input.business ? AlfredpayCustomerType.BUSINESS : AlfredpayCustomerType.INDIVIDUAL ); }), - waitForValidation: fromPromise(async ({ input }: { input: AlfredpayKycContext }) => { - const country = input.country || "US"; - // Submission ID check removed as backend handles it + sendSubmission: fromPromise(async ({ input }: { input: AlfredpayKycContext }) => { + const country = input.country || "MX"; + if (!input.submissionId) throw new Error("Submission ID missing"); + return AlfredpayService.sendKycSubmission(country, input.submissionId); + }), + + submitFiles: fromPromise( + async ({ input }: { input: AlfredpayKycContext & { mxnFormData?: MxnKycFormData; mxnFiles?: MxnKycFiles } }) => { + const country = input.country || "MX"; + if (!input.submissionId) throw new Error("Submission ID missing"); + if (!input.mxnFiles) throw new Error("MXN KYC files missing"); + await AlfredpayService.submitKycFile(country, input.submissionId, AlfredpayKycFileType.FRONT, input.mxnFiles.front); + if (input.mxnFiles.back && input.mxnFormData?.documentType !== "Passport") { + await AlfredpayService.submitKycFile(country, input.submissionId, AlfredpayKycFileType.BACK, input.mxnFiles.back); + } + } + ), + submitKycInfo: fromPromise(async ({ input }: { input: AlfredpayKycContext & { mxnFormData?: MxnKycFormData } }) => { + const country = input.country || "MX"; + if (!input.mxnFormData) throw new Error("MXN KYC form data missing"); + return AlfredpayService.submitKycInformation(country, input.mxnFormData); + }), + + waitForValidation: fromPromise(async ({ input, signal }: { input: AlfredpayKycContext; signal: AbortSignal }) => { + const country = input.country || "US"; const startTime = Date.now(); - while (true) { + while (!signal.aborted) { if (Date.now() - startTime > POLLING_TIMEOUT_MS) { throw new Error("Polling timeout"); } @@ -108,14 +153,22 @@ export const alfredpayKycMachine = setup({ return status; } } catch (e) { + if (signal.aborted) throw e; // Ignore errors during polling and keep trying } - await new Promise(resolve => setTimeout(resolve, 5000)); + await new Promise((resolve, reject) => { + const id = setTimeout(resolve, 5000); + signal.addEventListener("abort", () => { + clearTimeout(id); + reject(new Error("Aborted")); + }); + }); } + throw new Error("Aborted"); }) }, types: { - context: {} as AlfredpayKycContext, + context: {} as AlfredpayKycContext & { mxnFormData?: MxnKycFormData; mxnFiles?: MxnKycFiles }, events: {} as | { type: "OPEN_LINK" } | { type: "COMPLETED_FILLING" } @@ -127,9 +180,11 @@ export const alfredpayKycMachine = setup({ | { type: "RETRY_PROCESS" } | { type: "CANCEL_PROCESS" } | { type: "USER_RETRY" } - | { type: "USER_CANCEL" }, + | { type: "USER_CANCEL" } + | { type: "SUBMIT_FORM"; data: MxnKycFormData } + | { type: "SUBMIT_FILES"; files: MxnKycFiles }, input: {} as AlfredpayKycContext, - output: {} as { error?: AlfredpayKycMachineError; kycResponse?: any } + output: {} as { error?: AlfredpayKycMachineError } } }).createMachine({ context: ({ input }) => ({ ...input, country: input.country || "US" }), @@ -164,15 +219,27 @@ export const alfredpayKycMachine = setup({ target: "FailureKyc" }, { - // Default state for normal flow. + // MXN uses API-based form, not iFrame link + guard: ({ context }) => context.country === "MX", + target: "FillingKycForm" + }, + { + // Default state for normal flow (iFrame countries like US). target: "GettingKycLink" } ], onError: [ + { + // MXN: no customer → skip CustomerDefinition, always individual + guard: ({ context, event }) => + context.country === "MX" && + ((event.error as Error).message.includes("404") || (event.error as Error).message.includes("Not Found")), + target: "CreatingCustomer" + }, { guard: ({ event }) => (event.error as Error).message.includes("404") || (event.error as Error).message.includes("Not Found"), - target: "CostumerDefinition" + target: "CustomerDefinition" }, { actions: assign({ @@ -185,25 +252,19 @@ export const alfredpayKycMachine = setup({ src: "checkStatus" } }, - CostumerDefinition: { - on: { - TOGGLE_BUSINESS: { - actions: assign({ - business: ({ context }) => !context.business - }) - }, - USER_ACCEPT: { - target: "CreatingCustomer" - } - } - }, CreatingCustomer: { invoke: { id: "createCustomer", input: ({ context }) => context, - onDone: { - target: "GettingKycLink" - }, + onDone: [ + { + guard: ({ context }) => context.country === "MX", + target: "FillingKycForm" + }, + { + target: "GettingKycLink" + } + ], onError: { actions: assign({ error: ({ context }) => @@ -217,6 +278,18 @@ export const alfredpayKycMachine = setup({ src: "createCustomer" } }, + CustomerDefinition: { + on: { + TOGGLE_BUSINESS: { + actions: assign({ + business: ({ context }) => !context.business + }) + }, + USER_ACCEPT: { + target: "CreatingCustomer" + } + } + }, Done: { type: "final" }, @@ -262,6 +335,15 @@ export const alfredpayKycMachine = setup({ } } }, + + FillingKycForm: { + on: { + SUBMIT_FORM: { + actions: assign({ mxnFormData: ({ event }) => event.data }), + target: "SubmittingKycInfo" + } + } + }, FinishingFilling: { invoke: { id: "notifyFinished", @@ -370,6 +452,70 @@ export const alfredpayKycMachine = setup({ src: "retryKyc" } }, + + SendingSubmission: { + invoke: { + id: "sendSubmission", + input: ({ context }) => context, + onDone: { + target: "PollingStatus" + }, + onError: { + actions: assign({ + error: () => + new AlfredpayKycMachineError("Failed to send KYC submission", AlfredpayKycMachineErrorType.UnknownError) + }), + target: "Failure" + }, + src: "sendSubmission" + } + }, + + SubmittingFiles: { + invoke: { + id: "submitFiles", + input: ({ context }) => context, + onDone: { + target: "SendingSubmission" + }, + onError: { + actions: assign({ + error: () => + new AlfredpayKycMachineError("Failed to upload ID documents", AlfredpayKycMachineErrorType.UnknownError) + }), + target: "Failure" + }, + src: "submitFiles" + } + }, + + SubmittingKycInfo: { + invoke: { + id: "submitKycInfo", + input: ({ context }) => context, + onDone: { + actions: assign({ submissionId: ({ event }) => (event.output as { submissionId: string }).submissionId }), + target: "UploadingDocuments" + }, + onError: { + actions: assign({ + error: () => + new AlfredpayKycMachineError("Failed to submit KYC information", AlfredpayKycMachineErrorType.UnknownError) + }), + target: "Failure" + }, + src: "submitKycInfo" + } + }, + + UploadingDocuments: { + on: { + SUBMIT_FILES: { + actions: assign({ mxnFiles: ({ event }) => event.files }), + target: "SubmittingFiles" + } + } + }, VerificationDone: { on: { CONFIRM_SUCCESS: { target: "Done" } diff --git a/apps/frontend/src/machines/kyc.states.ts b/apps/frontend/src/machines/kyc.states.ts index e0ab63b17..59c1f0c4d 100644 --- a/apps/frontend/src/machines/kyc.states.ts +++ b/apps/frontend/src/machines/kyc.states.ts @@ -1,8 +1,9 @@ import { FiatToken, KycFailureReason, RampDirection } from "@vortexfi/shared"; import { assign, DoneActorEvent, sendTo } from "xstate"; +import { ALFREDPAY_FIAT_TOKEN_TO_COUNTRY } from "../constants/fiatAccountMethods"; import { KYCFormData } from "../hooks/brla/useKYCForm"; import { KycStatus } from "../services/signingService"; -import { AlfredpayKycMachineError } from "./alfredpayKyc.machine"; +import { AlfredpayKycMachineError, MxnKycFiles, MxnKycFormData } from "./alfredpayKyc.machine"; import { AveniaKycMachineError, UploadIds } from "./brlaKyc.machine"; import { MoneriumKycMachineError, MoneriumKycMachineErrorType } from "./moneriumKyc.machine"; import { RampContext, SelectedAveniaData } from "./types"; @@ -14,6 +15,8 @@ export interface AlfredpayKycContext extends RampContext { country?: string; error?: AlfredpayKycMachineError; business?: boolean; + mxnFormData?: MxnKycFormData; + mxnFiles?: MxnKycFiles; } export interface AveniaKycContext extends RampContext { @@ -94,8 +97,11 @@ export const kycStateNode = { id: "alfredpayKyc", input: ({ context }: { context: RampContext }): AlfredpayKycContext => { console.log("Invoking Alfredpay KYC actor with RampContext input:", context); + const fiatToken = context.executionInput?.fiatToken; + const country = fiatToken ? (ALFREDPAY_FIAT_TOKEN_TO_COUNTRY[fiatToken] ?? "US") : "US"; return { - ...context + ...context, + country }; }, onDone: [ @@ -164,7 +170,8 @@ export const kycStateNode = { Deciding: { always: [ { - guard: ({ context }: { context: RampContext }) => context.executionInput?.fiatToken === FiatToken.USD, + guard: ({ context }: { context: RampContext }) => + context.executionInput?.fiatToken === FiatToken.USD || context.executionInput?.fiatToken === FiatToken.MXN, target: "Alfredpay" }, { diff --git a/apps/frontend/src/services/api/alfredpay.service.ts b/apps/frontend/src/services/api/alfredpay.service.ts index f0af68376..6efc8394f 100644 --- a/apps/frontend/src/services/api/alfredpay.service.ts +++ b/apps/frontend/src/services/api/alfredpay.service.ts @@ -129,5 +129,31 @@ export const AlfredpayService = { type }); return response.data; + }, + + async sendKycSubmission(country: string, submissionId: string): Promise { + await apiClient.post("/alfredpay/sendKycSubmission", { country, submissionId }); + }, + + async submitKycFile(country: string, submissionId: string, fileType: string, file: File): Promise { + const formData = new FormData(); + formData.append("country", country); + formData.append("submissionId", submissionId); + formData.append("fileType", fileType); + formData.append("file", file); + await apiClient.post("/alfredpay/submitKycFile", formData, { + headers: { "Content-Type": "multipart/form-data" } + }); + }, + + async submitKycInformation( + country: string, + data: Omit + ): Promise<{ submissionId: string }> { + const response = await apiClient.post<{ submissionId: string }>("/alfredpay/submitKycInformation", { + country, + ...data + }); + return response.data; } }; From 815ee17565a3040cb6134f436b608dd02aeff581 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Fri, 27 Mar 2026 11:39:01 +0100 Subject: [PATCH 006/117] : update fiat account registration UI for SPEI --- .../src/constants/fiatAccountForms.ts | 54 +++++--- .../src/machines/fiatAccount.machine.ts | 5 +- .../AccountCardDeck.tsx | 131 ++++++++---------- .../AccountTypePickerScreen.tsx | 4 +- .../RegisterFiatAccountScreen.tsx | 16 ++- .../RegisteredAccountsList.tsx | 2 +- 6 files changed, 115 insertions(+), 97 deletions(-) diff --git a/apps/frontend/src/constants/fiatAccountForms.ts b/apps/frontend/src/constants/fiatAccountForms.ts index f8ece1b16..0daac3d1f 100644 --- a/apps/frontend/src/constants/fiatAccountForms.ts +++ b/apps/frontend/src/constants/fiatAccountForms.ts @@ -12,39 +12,57 @@ export interface FieldDef { export const FORMS: Record = { ACH: [ - { field: "accountBankCode", label: "Bank Name", required: true, type: "text" }, - { field: "routingNumber", label: "Routing Number (9 digits)", placeholder: "021000021", required: true, type: "text" }, - { field: "accountNumber", label: "Account Number", required: true, type: "text" }, + { field: "accountBankCode", label: "components.fiatAccountForms.bankName", required: true, type: "text" }, + { + field: "routingNumber", + label: "components.fiatAccountForms.routingNumber", + placeholder: "components.fiatAccountForms.placeholders.routingNumber", + required: true, + type: "text" + }, + { field: "accountNumber", label: "components.fiatAccountForms.accountNumber", required: true, type: "text" }, { field: "accountType", - label: "Account Type", + label: "components.fiatAccountForms.accountType", options: [ - { label: "Checking", value: "CHECKING" }, - { label: "Savings", value: "SAVINGS" } + { label: "components.fiatAccountForms.options.checking", value: "CHECKING" }, + { label: "components.fiatAccountForms.options.savings", value: "SAVINGS" } ], required: true, type: "select" }, - { field: "accountName", label: "Account Holder Name", required: true, type: "text" }, - { field: "accountAlias", label: "Nickname (optional)", required: false, type: "text" } + { field: "accountName", label: "components.fiatAccountForms.accountName", required: true, type: "text" }, + { field: "accountAlias", label: "components.fiatAccountForms.accountAlias", required: false, type: "text" } ], SPEI: [ { field: "accountBankCode", - label: "Bank Name", - placeholder: "e.g. BBVA, Santander, Banamex", + label: "components.fiatAccountForms.bankName", + placeholder: "components.fiatAccountForms.placeholders.bankNameMx", + required: true, + type: "text" + }, + { + field: "accountNumber", + label: "components.fiatAccountForms.clabe", + placeholder: "components.fiatAccountForms.placeholders.clabe", required: true, type: "text" }, - { field: "accountNumber", label: "CLABE (18 digits)", placeholder: "032180000118359719", required: true, type: "text" }, - { field: "accountName", label: "Account Holder Name", required: true, type: "text" }, - { field: "accountAlias", label: "Nickname (optional)", required: false, type: "text" } + { field: "accountName", label: "components.fiatAccountForms.accountName", required: true, type: "text" }, + { field: "accountAlias", label: "components.fiatAccountForms.accountAlias", required: false, type: "text" } ], WIRE: [ - { field: "accountBankCode", label: "Bank Name", required: true, type: "text" }, - { field: "routingNumber", label: "Routing / ABA Number", placeholder: "021000021", required: true, type: "text" }, - { field: "accountNumber", label: "Account Number", required: true, type: "text" }, - { field: "accountName", label: "Account Holder Name", required: true, type: "text" }, - { field: "accountAlias", label: "Nickname (optional)", required: false, type: "text" } + { field: "accountBankCode", label: "components.fiatAccountForms.bankName", required: true, type: "text" }, + { + field: "routingNumber", + label: "components.fiatAccountForms.routingAba", + placeholder: "components.fiatAccountForms.placeholders.routingNumber", + required: true, + type: "text" + }, + { field: "accountNumber", label: "components.fiatAccountForms.accountNumber", required: true, type: "text" }, + { field: "accountName", label: "components.fiatAccountForms.accountName", required: true, type: "text" }, + { field: "accountAlias", label: "components.fiatAccountForms.accountAlias", required: false, type: "text" } ] }; diff --git a/apps/frontend/src/machines/fiatAccount.machine.ts b/apps/frontend/src/machines/fiatAccount.machine.ts index 4d503aa4b..9aeb6a2bc 100644 --- a/apps/frontend/src/machines/fiatAccount.machine.ts +++ b/apps/frontend/src/machines/fiatAccount.machine.ts @@ -49,7 +49,10 @@ export const fiatAccountMachine = setup({ AccountsList: { on: { ADD_NEW: { target: "PickAccountType" }, - GO_BACK: { target: "#fiatAccount.Closed" } + GO_BACK: { + actions: assign({ fiatRegistrationCountry: null, selectedFiatAccountId: null }), + target: "#fiatAccount.Closed" + } } }, PickAccountType: { diff --git a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountCardDeck.tsx b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountCardDeck.tsx index ba4fb2680..8165181c4 100644 --- a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountCardDeck.tsx +++ b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountCardDeck.tsx @@ -103,29 +103,41 @@ export function AccountCardDeck({ accounts, onDelete }: AccountCardDeckProps) { return () => document.removeEventListener("pointerdown", handler); }, [isExpanded, canHover]); + const sharedCardStyle = (i: number) => ({ + height: CARD_HEIGHT, + left: 0, + position: "absolute" as const, + right: 0, + zIndex: orderedAccounts.length - i + }); + return ( - {orderedAccounts.map((account, i) => ( - 0 - ? t("components.fiatAccountMethods.switchToAccount", { - accountType: ALFRED_TO_ACCOUNT_TYPE[account.type], - last4: account.fiatAccountFields.accountNumber.slice(-4) - }) - : undefined - } - exit={{ opacity: 0, scale: 0.94, transition: { duration: 0.2 } }} - initial={false} - key={account.fiatAccountId} - onClick={ - i > 0 - ? canHover + {orderedAccounts.map((account, i) => + i === 0 ? ( + + + + ) : ( + setActiveId(account.fiatAccountId) : !isExpanded ? () => setIsExpanded(true) @@ -133,56 +145,35 @@ export function AccountCardDeck({ accounts, onDelete }: AccountCardDeckProps) { setActiveId(account.fiatAccountId); setIsExpanded(false); } - : undefined - } - onHoverEnd={i > 0 && canHover ? () => setHoveredId(null) : undefined} - onHoverStart={i > 0 && canHover ? () => setHoveredId(account.fiatAccountId) : undefined} - onKeyDown={ - i > 0 - ? e => { - if (e.key === "Enter" || e.key === " ") setActiveId(account.fiatAccountId); - } - : undefined - } - role={i > 0 ? "button" : undefined} - style={{ - cursor: i > 0 ? "pointer" : "default", - height: CARD_HEIGHT, - left: 0, - position: "absolute", - right: 0, - zIndex: orderedAccounts.length - i - }} - tabIndex={i > 0 ? 0 : undefined} - transition={spring} - whileHover={i > 0 && canHover ? { y: -10 } : undefined} - > - {i === 0 ? ( - - ) : ( - <> - - - {hoveredId === account.fiatAccountId && ( - - - {t("components.fiatAccountMethods.clickToSelect")} - - - )} - - - )} - - ))} + } + onHoverEnd={canHover ? () => setHoveredId(null) : undefined} + onHoverStart={canHover ? () => setHoveredId(account.fiatAccountId) : undefined} + style={{ cursor: "pointer", ...sharedCardStyle(i) }} + transition={spring} + type="button" + whileHover={canHover ? { y: -10 } : undefined} + > + + + {hoveredId === account.fiatAccountId && ( + + + {t("components.fiatAccountMethods.clickToSelect")} + + + )} + + + ) + )} ); diff --git a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountTypePickerScreen.tsx b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountTypePickerScreen.tsx index ac5b89efb..ef6dd436f 100644 --- a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountTypePickerScreen.tsx +++ b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/AccountTypePickerScreen.tsx @@ -45,7 +45,9 @@ export function AccountTypePickerScreen({ countryConfig, onSelect }: AccountType type="button" > - + ))} diff --git a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisterFiatAccountScreen.tsx b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisterFiatAccountScreen.tsx index 854b482bc..7140b9b7b 100644 --- a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisterFiatAccountScreen.tsx +++ b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisterFiatAccountScreen.tsx @@ -1,6 +1,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import type { AlfredpayFiatAccountType } from "@vortexfi/shared"; import type { TFunction } from "i18next"; +import { useMemo } from "react"; import { Controller, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { toast } from "react-toastify"; @@ -32,7 +33,7 @@ function buildZodSchema( let schema: z.ZodTypeAny = z.string(); if (f.required) { - schema = z.string().min(1, t("components.fiatAccountRegistration.validation.fieldRequired", { field: f.label })); + schema = z.string().min(1, t("components.fiatAccountRegistration.validation.fieldRequired", { field: t(f.label) })); } else { schema = z.string().optional(); } @@ -65,7 +66,7 @@ export function RegisterFiatAccountScreen({ country, accountType, onSuccess }: R const fields: FieldDef[] = FORMS[accountType] ?? []; - const schema = buildZodSchema(fields, accountType, t); + const schema = useMemo(() => buildZodSchema(fields, accountType, t), [fields, accountType, t]); const { control, @@ -143,7 +144,7 @@ export function RegisterFiatAccountScreen({ country, accountType, onSuccess }: R {fields.map(f => (
{f.type === "select" ? ( @@ -153,7 +154,7 @@ export function RegisterFiatAccountScreen({ country, accountType, onSuccess }: R render={({ field }) => ( diff --git a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisteredAccountsList.tsx b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisteredAccountsList.tsx index 895f3d414..142004409 100644 --- a/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisteredAccountsList.tsx +++ b/apps/frontend/src/pages/alfredpay/FiatAccountRegistration/RegisteredAccountsList.tsx @@ -17,7 +17,7 @@ export function RegisteredAccountsList({ accounts, isLoading, kycApproved, onAdd const { t } = useTranslation(); return (
-

{t("components.fiatAccountRegistration.title")}

+

{t("components.fiatAccountRegistration.title")}

{!kycApproved && }
From 60edb760ed32903f891f816375ec9ce23f591cd2 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Fri, 27 Mar 2026 11:39:37 +0100 Subject: [PATCH 007/117] enable MXN token, update UI components, and add translations --- .../src/components/Alfredpay/DoneScreen.tsx | 2 +- .../components/Alfredpay/FillingScreen.tsx | 9 +- .../Alfredpay/MxnDocumentUploadScreen.tsx | 92 +++++++++ .../components/Alfredpay/MxnKycFormScreen.tsx | 181 ++++++++++++++++++ .../src/components/Navbar/DesktopNavbar.tsx | 4 +- .../src/components/ui/DropdownSelector.tsx | 3 + apps/frontend/src/config/tokenAvailability.ts | 2 +- apps/frontend/src/pages/ramp/index.tsx | 5 +- apps/frontend/src/translations/en.json | 47 ++++- apps/frontend/src/translations/pt.json | 45 +++++ 10 files changed, 381 insertions(+), 9 deletions(-) create mode 100644 apps/frontend/src/components/Alfredpay/MxnDocumentUploadScreen.tsx create mode 100644 apps/frontend/src/components/Alfredpay/MxnKycFormScreen.tsx diff --git a/apps/frontend/src/components/Alfredpay/DoneScreen.tsx b/apps/frontend/src/components/Alfredpay/DoneScreen.tsx index 510ff7703..272873d9a 100644 --- a/apps/frontend/src/components/Alfredpay/DoneScreen.tsx +++ b/apps/frontend/src/components/Alfredpay/DoneScreen.tsx @@ -15,7 +15,7 @@ export const DoneScreen = memo(({ kycOrKyb, onContinue }: DoneScreenProps) => { return (
- Business Handshake + Document verified

{t("components.alfredpayKycFlow.completed", { kycOrKyb })}

{t("components.alfredpayKycFlow.accountVerified")}

{onContinue && ( diff --git a/apps/frontend/src/components/Alfredpay/FillingScreen.tsx b/apps/frontend/src/components/Alfredpay/FillingScreen.tsx index 89d1368c5..93d7995bb 100644 --- a/apps/frontend/src/components/Alfredpay/FillingScreen.tsx +++ b/apps/frontend/src/components/Alfredpay/FillingScreen.tsx @@ -18,7 +18,7 @@ export const FillingScreen = memo(({ kycOrKyb, isSubmitting, onCompletedFilling, return (
- Business Handshake + Document ready

{t("components.alfredpayKycFlow.completeInNewWindow", { kycOrKyb })}

{onOpenLink && ( )} - + {error &&

{error}

} +
+ ); +} + +export function MxnDocumentUploadScreen({ onSubmit }: MxnDocumentUploadScreenProps) { + const { t } = useTranslation(); + const [front, setFront] = useState(null); + const [back, setBack] = useState(null); + + const isValid = front !== null && back !== null; + + const handleSubmit = () => { + if (!front || !back) return; + onSubmit({ back, front }); + }; + + return ( +
+ +

{t("components.mxnDocumentUpload.title")}

+

{t("components.mxnDocumentUpload.subtitle")}

+ +
+ + + +

{t("components.mxnDocumentUpload.fileHint")}

+ + +
+
+ ); +} diff --git a/apps/frontend/src/components/Alfredpay/MxnKycFormScreen.tsx b/apps/frontend/src/components/Alfredpay/MxnKycFormScreen.tsx new file mode 100644 index 000000000..dbab1af23 --- /dev/null +++ b/apps/frontend/src/components/Alfredpay/MxnKycFormScreen.tsx @@ -0,0 +1,181 @@ +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { z } from "zod"; +import type { MxnKycFormData } from "../../machines/alfredpayKyc.machine"; +import { MenuButtons } from "../MenuButtons"; + +const schema = z.object({ + address: z.string().min(1), + city: z.string().min(1), + dateOfBirth: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Use YYYY-MM-DD format"), + dni: z.string().min(1), + email: z.string().email(), + firstName: z.string().min(1), + lastName: z.string().min(1), + state: z.string().min(1), + zipCode: z.string().min(1) +}); + +interface MxnKycFormScreenProps { + onSubmit: (data: MxnKycFormData) => void; +} + +export function MxnKycFormScreen({ onSubmit }: MxnKycFormScreenProps) { + const { t } = useTranslation(); + + const { + formState: { errors }, + handleSubmit, + register + } = useForm({ resolver: zodResolver(schema) }); + + const inputClass = (hasError: boolean) => + `input-vortex-primary input-ghost w-full rounded-lg border p-2 text-base ${hasError ? "border-error" : "border-neutral-300"}`; + + return ( +
+ +

{t("components.mxnKycForm.title")}

+

{t("components.mxnKycForm.subtitle")}

+ +
+
+
+ + + {errors.firstName && {errors.firstName.message}} +
+ +
+ + + {errors.lastName && {errors.lastName.message}} +
+
+ +
+ + + {errors.dateOfBirth && {errors.dateOfBirth.message}} +
+ +
+ + + {errors.email && {errors.email.message}} +
+ +
+ + + {errors.dni && {errors.dni.message}} +
+ +
+ + + {errors.address && {errors.address.message}} +
+ +
+
+ + + {errors.city && {errors.city.message}} +
+ +
+ + + {errors.state && {errors.state.message}} +
+
+ +
+ + + {errors.zipCode && {errors.zipCode.message}} +
+ + +
+
+ ); +} diff --git a/apps/frontend/src/components/Navbar/DesktopNavbar.tsx b/apps/frontend/src/components/Navbar/DesktopNavbar.tsx index 8d8816422..9c4264a26 100644 --- a/apps/frontend/src/components/Navbar/DesktopNavbar.tsx +++ b/apps/frontend/src/components/Navbar/DesktopNavbar.tsx @@ -59,8 +59,8 @@ export const DesktopNavbar = () => {
- - Buy & Sell + + Open App
diff --git a/apps/frontend/src/components/ui/DropdownSelector.tsx b/apps/frontend/src/components/ui/DropdownSelector.tsx index 8c551cd96..27342576d 100644 --- a/apps/frontend/src/components/ui/DropdownSelector.tsx +++ b/apps/frontend/src/components/ui/DropdownSelector.tsx @@ -5,6 +5,7 @@ import { cn } from "../../helpers/cn"; interface DropdownSelectorProps { label?: string; + triggerAriaLabel?: string; open: boolean; onOpenChange: (open: boolean) => void; triggerContent: ReactNode; @@ -15,6 +16,7 @@ interface DropdownSelectorProps { export function DropdownSelector({ label, + triggerAriaLabel, open, onOpenChange, triggerContent, @@ -62,6 +64,7 @@ export function DropdownSelector({ + +
+ ); +} diff --git a/packages/shared/src/helpers/payment-method-mapper.ts b/packages/shared/src/helpers/payment-method-mapper.ts index 36f7bb038..85b035507 100644 --- a/packages/shared/src/helpers/payment-method-mapper.ts +++ b/packages/shared/src/helpers/payment-method-mapper.ts @@ -75,7 +75,7 @@ export const mapFiatToDestination = (fiatToken: FiatToken): DestinationType => { const destinationMap: Record = { ARS: EPaymentMethod.CBU, BRL: EPaymentMethod.PIX, - COP: EPaymentMethod.SPEI, + COP: EPaymentMethod.ACH, EUR: EPaymentMethod.SEPA, MXN: EPaymentMethod.SPEI, USD: EPaymentMethod.ACH From 0a3efc0c45ce4d0a55e9bedd8f6bdf640b823bd6 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Thu, 2 Apr 2026 11:38:35 +0200 Subject: [PATCH 011/117] replace axios with native fetch wrapper in frontend --- .../src/services/api/alfredpay.service.ts | 102 ++------------ apps/frontend/src/services/api/api-client.ts | 131 +++++++++--------- apps/frontend/src/services/api/auth.api.ts | 55 ++------ .../src/services/api/monerium.service.ts | 31 +---- 4 files changed, 104 insertions(+), 215 deletions(-) diff --git a/apps/frontend/src/services/api/alfredpay.service.ts b/apps/frontend/src/services/api/alfredpay.service.ts index f0af68376..3b56c2a4e 100644 --- a/apps/frontend/src/services/api/alfredpay.service.ts +++ b/apps/frontend/src/services/api/alfredpay.service.ts @@ -14,120 +14,46 @@ import { import { apiClient } from "./api-client"; export const AlfredpayService = { - /** - * Register a new fiat account. - */ async addFiatAccount(payload: AlfredpayAddFiatAccountRequest): Promise { - const response = await apiClient.post("/alfredpay/fiatAccounts", payload); - return response.data; + return apiClient.post("/alfredpay/fiatAccounts", payload); }, async createBusinessCustomer(country: string): Promise { - const response = await apiClient.post("/alfredpay/createBusinessCustomer", { - country - }); - return response.data; + return apiClient.post("/alfredpay/createBusinessCustomer", { country }); }, - /** - * Create a new Alfredpay individual customer. - */ async createIndividualCustomer(country: string): Promise { - const request: AlfredpayCreateCustomerRequest = { - country - }; - const response = await apiClient.post("/alfredpay/createIndividualCustomer", request); - return response.data; + const request: AlfredpayCreateCustomerRequest = { country }; + return apiClient.post("/alfredpay/createIndividualCustomer", request); }, - - /** - * Delete a registered fiat account. - */ async deleteFiatAccount(fiatAccountId: string, country: string): Promise { await apiClient.delete(`/alfredpay/fiatAccounts/${fiatAccountId}`, { params: { country } }); }, - /** - * Check Alfredpay status for a user in a specific country. - */ async getAlfredpayStatus(country: string): Promise { - const response = await apiClient.get("/alfredpay/alfredpayStatus", { - params: { country } - }); - return response.data; + return apiClient.get("/alfredpay/alfredpayStatus", { params: { country } }); }, - - /** - * Get dynamic form requirements for a country + payment method combo. - */ async getFiatAccountRequirements(country: string, paymentMethod: string): Promise { - const response = await apiClient.get("/alfredpay/fiatAccountRequirements", { + return apiClient.get("/alfredpay/fiatAccountRequirements", { params: { country, paymentMethod } }); - return response.data; }, - async getKybRedirectLink(country: string): Promise { - const response = await apiClient.get("/alfredpay/getKybRedirectLink", { - params: { country } - }); - return response.data; + return apiClient.get("/alfredpay/getKybRedirectLink", { params: { country } }); }, - - /** - * Get the KYC redirect link for a user. - */ async getKycRedirectLink(country: string): Promise { - const response = await apiClient.get("/alfredpay/getKycRedirectLink", { - params: { country } - }); - return response.data; + return apiClient.get("/alfredpay/getKycRedirectLink", { params: { country } }); }, - - /** - * Get the status of a specific KYC submission. - */ async getKycStatus(country: string, type?: AlfredpayCustomerType): Promise { - const response = await apiClient.get("/alfredpay/getKycStatus", { - params: { country, type } - }); - return response.data; + return apiClient.get("/alfredpay/getKycStatus", { params: { country, type } }); }, - - /** - * List all registered fiat accounts for the current user in a given country. - */ - async listFiatAccounts(country: string): Promise { - const response = await apiClient.get("/alfredpay/fiatAccounts", { - params: { country } - }); - return response.data; + async listFiatAccounts(country: string, signal?: AbortSignal): Promise { + return apiClient.get("/alfredpay/fiatAccounts", { params: { country }, signal }); }, - - /** - * Notify that the KYC redirect process is finished. - */ async notifyKycRedirectFinished(country: string, type?: AlfredpayCustomerType): Promise<{ success: boolean }> { - const response = await apiClient.post<{ success: boolean }>("/alfredpay/kycRedirectFinished", { - country, - type - }); - return response.data; + return apiClient.post<{ success: boolean }>("/alfredpay/kycRedirectFinished", { country, type }); }, - - /** - * Notify that the KYC redirect link has been opened. - */ async notifyKycRedirectOpened(country: string, type?: AlfredpayCustomerType): Promise<{ success: boolean }> { - const response = await apiClient.post<{ success: boolean }>("/alfredpay/kycRedirectOpened", { - country, - type - }); - return response.data; + return apiClient.post<{ success: boolean }>("/alfredpay/kycRedirectOpened", { country, type }); }, - async retryKyc(country: string, type?: AlfredpayCustomerType): Promise { - const response = await apiClient.post("/alfredpay/retryKyc", { - country, - type - }); - return response.data; + return apiClient.post("/alfredpay/retryKyc", { country, type }); } }; diff --git a/apps/frontend/src/services/api/api-client.ts b/apps/frontend/src/services/api/api-client.ts index 025fcfd29..fa10e6039 100644 --- a/apps/frontend/src/services/api/api-client.ts +++ b/apps/frontend/src/services/api/api-client.ts @@ -1,83 +1,90 @@ -import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios"; import { SIGNING_SERVICE_URL } from "../../constants/constants"; import { AuthService } from "../auth"; -// TODO: CONSIDER REACT TANSTACK QUERY +export class ApiError extends Error { + status: number; + data: { error?: string; message?: string; details?: string }; -/** - * Base API client for making requests to the backend - */ -export const apiClient: AxiosInstance = axios.create({ - baseURL: `${SIGNING_SERVICE_URL}/v1`, - headers: { - "Content-Type": "application/json" - }, - timeout: 30000 -}); + constructor(status: number, data: Record, message: string) { + super(message); + this.status = status; + this.data = data; + } +} + +export function isApiError(error: unknown): error is ApiError { + return error instanceof ApiError; +} -// Add request interceptor for common headers and auth token -apiClient.interceptors.request.use( - config => { - // Add Authorization header if user is authenticated - const tokens = AuthService.getTokens(); - if (tokens?.accessToken) { - config.headers.Authorization = `Bearer ${tokens.accessToken}`; +async function apiFetch( + method: string, + path: string, + options: { + data?: unknown; + params?: Record; + headers?: Record; + signal?: AbortSignal; + } = {} +): Promise { + const tokens = AuthService.getTokens(); + + const url = new URL(`${SIGNING_SERVICE_URL}/v1${path}`); + if (options.params) { + for (const [key, value] of Object.entries(options.params)) { + if (value !== undefined) url.searchParams.set(key, String(value)); } - return config; - }, - error => { - return Promise.reject(error); } -); -// Add response interceptor for error handling -apiClient.interceptors.response.use( - response => { - return response; - }, - (error: AxiosError) => { - console.error("API Error:", error.response?.data || error.message); - return Promise.reject(error); + const isFormData = options.data instanceof FormData; + + const response = await fetch(url.toString(), { + body: isFormData ? (options.data as FormData) : options.data !== undefined ? JSON.stringify(options.data) : undefined, + headers: { + ...(tokens?.accessToken ? { Authorization: `Bearer ${tokens.accessToken}` } : {}), + ...(!isFormData ? { "Content-Type": "application/json" } : {}), + ...options.headers + }, + method, + signal: options.signal ?? AbortSignal.timeout(30000) + }); + + if (!response.ok) { + const errorData = (await response.json().catch(() => ({}))) as { error?: string; message?: string }; + console.error("API Error:", errorData); + throw new ApiError(response.status, errorData, errorData.error ?? errorData.message ?? response.statusText); } -); -/** - * Helper function to handle API errors - * @param error The error object - * @param defaultMessage Default error message - * @returns Formatted error message - */ + if (response.status === 204) return undefined as T; + return response.json() as Promise; +} + export const handleApiError = (error: unknown, defaultMessage = "An error occurred"): string => { - if (axios.isAxiosError(error)) { - const responseData = error.response?.data as { error?: string; message?: string; details?: string } | undefined; - return responseData?.error || responseData?.message || error.message || defaultMessage; + if (isApiError(error)) { + return error.data?.error ?? error.data?.message ?? error.message ?? defaultMessage; } return error instanceof Error ? error.message : defaultMessage; }; -/** - * Generic API request function with error handling - * @param method The HTTP method - * @param url The endpoint URL - * @param data The request data - * @param config Additional axios config - * @returns The response data - */ export async function apiRequest( method: "get" | "post" | "put" | "delete", url: string, data?: unknown, - config?: AxiosRequestConfig -): Promise { - try { - const response = await apiClient.request({ - data, - method, - url, - ...config - }); - return response.data; - } catch (error) { - throw new Error(handleApiError(error)); + config?: { + params?: Record; + headers?: Record; + signal?: AbortSignal; } +): Promise { + return apiFetch(method, url, { data, ...config }); } + +type Params = Record; + +export const apiClient = { + delete: (url: string, config?: { params?: Params }) => apiFetch("DELETE", url, { params: config?.params }), + get: (url: string, config?: { params?: Params; signal?: AbortSignal }) => + apiFetch("GET", url, { params: config?.params, signal: config?.signal }), + post: (url: string, data?: unknown, config?: { headers?: Record; params?: Params }) => + apiFetch("POST", url, { data, headers: config?.headers, params: config?.params }), + put: (url: string, data?: unknown) => apiFetch("PUT", url, { data }) +}; diff --git a/apps/frontend/src/services/api/auth.api.ts b/apps/frontend/src/services/api/auth.api.ts index dddee6b1e..7424d8c09 100644 --- a/apps/frontend/src/services/api/auth.api.ts +++ b/apps/frontend/src/services/api/auth.api.ts @@ -13,70 +13,43 @@ export interface VerifyOTPResponse { } export class AuthAPI { - /** - * Check if email exists - */ static async checkEmail(email: string): Promise { - const response = await apiClient.get("/auth/check-email", { - params: { email } - }); - return response.data; + return apiClient.get("/auth/check-email", { params: { email } }); } - /** - * Request OTP - */ static async requestOTP(email: string, locale?: string): Promise { - await apiClient.post("/auth/request-otp", { - email, - locale - }); + await apiClient.post("/auth/request-otp", { email, locale }); } - /** - * Verify OTP - */ static async verifyOTP(email: string, token: string): Promise { - const response = await apiClient.post<{ success: boolean; access_token: string; refresh_token: string; user_id: string }>( + const data = await apiClient.post<{ success: boolean; access_token: string; refresh_token: string; user_id: string }>( "/auth/verify-otp", - { - email, - token - } + { email, token } ); return { - accessToken: response.data.access_token, - refreshToken: response.data.refresh_token, - success: response.data.success, - userId: response.data.user_id + accessToken: data.access_token, + refreshToken: data.refresh_token, + success: data.success, + userId: data.user_id }; } - /** - * Refresh token - */ static async refreshToken(refreshToken: string): Promise { - const response = await apiClient.post<{ success: boolean; access_token: string; refresh_token: string }>("/auth/refresh", { + const data = await apiClient.post<{ success: boolean; access_token: string; refresh_token: string }>("/auth/refresh", { refresh_token: refreshToken }); return { - accessToken: response.data.access_token, - refreshToken: response.data.refresh_token, - success: response.data.success, + accessToken: data.access_token, + refreshToken: data.refresh_token, + success: data.success, userId: "" // Refresh doesn't return user_id, but interface requires it }; } - /** - * Verify access token - */ static async verifyToken(accessToken: string): Promise<{ valid: boolean; userId?: string }> { - const response = await apiClient.post<{ valid: boolean; user_id?: string }>("/auth/verify", { + const data = await apiClient.post<{ valid: boolean; user_id?: string }>("/auth/verify", { access_token: accessToken }); - return { - userId: response.data.user_id, - valid: response.data.valid - }; + return { userId: data.user_id, valid: data.valid }; } } diff --git a/apps/frontend/src/services/api/monerium.service.ts b/apps/frontend/src/services/api/monerium.service.ts index bd93acee1..fcd922c6c 100644 --- a/apps/frontend/src/services/api/monerium.service.ts +++ b/apps/frontend/src/services/api/monerium.service.ts @@ -1,31 +1,23 @@ -import axios from "axios"; import { MONERIUM_MINT_NETWORK } from "../monerium/moneriumAuth"; -import { apiClient } from "./api-client"; +import { apiClient, isApiError } from "./api-client"; export interface MoneriumUserStatus { isNewUser: boolean; } export const MoneriumService = { - /** - * Check if a user exists in Monerium from our backend. - */ async checkUserStatus(address: string): Promise { try { console.log("Checking Monerium user status for address:", address); await apiClient.get("/monerium/address-exists", { params: { address, network: MONERIUM_MINT_NETWORK } }); - return { - isNewUser: false - }; + return { isNewUser: false }; } catch (error: unknown) { - if (axios.isAxiosError(error)) { - if (error.response && error.response.status === 404) { + if (isApiError(error)) { + if (error.status === 404) { console.log("Monerium user not found"); - return { - isNewUser: true - }; + return { isNewUser: true }; } throw new Error(`Error checking Monerium user status: ${error.message}`); } @@ -33,24 +25,15 @@ export const MoneriumService = { } }, - /** - * Create signature for Monerium offrampm, 10 minutes from now. - */ async createRampMessage(amount: string, iban: string): Promise { const date = new Date(Date.now() + 1000 * 60 * 10).toISOString(); return `Send EUR ${amount} to ${iban} at ${date}`; }, - /** - * Validate Monerium auth tokens - */ async validateAuthTokens(authCode: string, codeVerifier: string): Promise { try { - const response = await apiClient.post("/monerium/validate-auth", { - authCode, - codeVerifier - }); - return response.data.valid; + const data = await apiClient.post<{ valid: boolean }>("/monerium/validate-auth", { authCode, codeVerifier }); + return data.valid; } catch (error) { console.error("Error validating Monerium auth tokens:", error); return false; From 1aa743d7bd457978f89af859445e58f6f6e20e8a Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Thu, 2 Apr 2026 11:40:53 +0200 Subject: [PATCH 012/117] replace axios with native fetch in shared package --- .../shared/src/services/squidrouter/route.ts | 120 +++++++++++------- .../shared/src/tokens/evm/dynamicEvmTokens.ts | 11 +- 2 files changed, 77 insertions(+), 54 deletions(-) diff --git a/packages/shared/src/services/squidrouter/route.ts b/packages/shared/src/services/squidrouter/route.ts index e8861568c..d22111f7e 100644 --- a/packages/shared/src/services/squidrouter/route.ts +++ b/packages/shared/src/services/squidrouter/route.ts @@ -1,4 +1,3 @@ -import axios, { AxiosError } from "axios"; import PQueue from "p-queue"; import logger from "../../logger"; import { squidRouterConfigBase } from "./config"; @@ -112,16 +111,34 @@ export interface GetRouteOptions { // This prevents hitting SquidRouter API rate limits for the same user when multiple getRoute() calls happen in quick succession. const routeQueues = new Map(); +class HttpError extends Error { + status: number; + data: unknown; + + constructor(status: number, data: unknown) { + super(`HTTP ${status}`); + this.status = status; + this.data = data; + } +} + +async function squidFetch(url: string, options: RequestInit): Promise<{ data: T; headers: Headers }> { + const response = await fetch(url, options); + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new HttpError(response.status, errorData); + } + const data = (await response.json()) as T; + return { data, headers: response.headers }; +} + /** * Get a route from Squidrouter. * * When useCache is true, returns a stripped-down SquidrouterCachedRouteResult without transactionRequest. * When useCache is false or not specified (default), returns the full SquidrouterRouteResult. */ -export async function getRoute( - params: RouteParams, - options: { useCache: true } -): Promise; +export async function getRoute(params: RouteParams, options: { useCache: true }): Promise; export async function getRoute(params: RouteParams, options?: { useCache?: false }): Promise; export async function getRoute( params: RouteParams, @@ -148,7 +165,8 @@ export async function getRoute( } try { - const result = (await queue.add(() => getRouteInternal(params))) as SquidrouterRouteResult; + const result = await queue.add(() => getRouteInternal(params)); + if (!result) throw new Error("Route fetch returned no result"); if (useCache) { const cacheKey = generateRouteCacheKey(params); @@ -167,47 +185,54 @@ export async function getRoute( } async function getRouteInternal(params: RouteParams): Promise { - // This is the integrator ID for the Squidrouter API const { integratorId } = squidRouterConfigBase; const url = `${SQUIDROUTER_BASE_URL}/route`; + let fetchResult: Awaited>>; try { - const result = await axios.post(url, params, { + fetchResult = await squidFetch<{ route: SquidrouterRoute }>(url, { + body: JSON.stringify(params), headers: { "Content-Type": "application/json", "x-integrator-id": integratorId - } + }, + method: "POST" }); - - const requestId = result.headers["x-request-id"]; // Retrieve request ID from response headers - - if (!result.data || !result.data.route) { - logger.current.error(`Invalid API response structure. Request ID: ${requestId}`); - throw new Error("Invalid response from Squid Router API"); - } - - // FIXME remove this check once squidRouter works as expected again. - // Check if slippage of received route is reasonable. - const route = result.data.route; - if (route.estimate?.aggregateSlippage !== undefined) { - const slippage = route.estimate.aggregateSlippage; - if (slippage > 2.5) { - logger.current.warn(`Received route with high slippage: ${slippage}%. Request ID: ${requestId}`); - // FIXME: temporarily disabled because we are facing issues with squidrouter routes failing the swap to USDT - // throw new Error(`The slippage of the route is too high: ${slippage}%. Please try again later.`); - } - } - - return { data: { route }, requestId }; } catch (error) { - if (error instanceof AxiosError && error.response) { - logger.current.error(`Error fetching route from Squidrouter API: ${JSON.stringify(error.response?.data)}}`); - throw new Error(`Failed to fetch route: ${error.response?.data?.message || "Unknown error"}`); + if (error instanceof HttpError) { + logger.current.error(`Error fetching route from Squidrouter API: ${JSON.stringify(error.data)}`); + const message = + typeof error.data === "object" && error.data !== null && "message" in error.data + ? String((error.data as { message: unknown }).message) + : "Unknown error"; + error.message = `Failed to fetch route: ${message}`; } else { logger.current.error(`Error with parameters: ${JSON.stringify(params)}`); - throw error; + } + throw error; + } + + const { data, headers } = fetchResult; + const requestId = headers.get("x-request-id"); + + if (!data || !data.route) { + logger.current.error(`Invalid API response structure. Request ID: ${requestId}`); + throw new Error("Invalid response from Squid Router API"); + } + + // FIXME remove this check once squidRouter works as expected again. + // Check if slippage of received route is reasonable. + const route = data.route; + if (route.estimate?.aggregateSlippage !== undefined) { + const slippage = route.estimate.aggregateSlippage; + if (slippage > 2.5) { + logger.current.warn(`Received route with high slippage: ${slippage}%. Request ID: ${requestId}`); + // FIXME: temporarily disabled because we are facing issues with squidrouter routes failing the swap to USDT + // throw new Error(`The slippage of the route is too high: ${slippage}%. Please try again later.`); } } + + return { data: { route }, requestId: requestId ?? "" }; } // Function to get the status of the transaction using Squid API @@ -225,24 +250,23 @@ export async function getStatus( logger.current.debug( `Fetching status for transaction ID: ${transactionId} with integrator ID: ${integratorId} from Squidrouter API.` ); + + const url = new URL(`${SQUIDROUTER_BASE_URL}/status`); + if (fromChainId) url.searchParams.set("fromChainId", fromChainId); + if (toChainId) url.searchParams.set("toChainId", toChainId); + url.searchParams.set("transactionId", transactionId); + if (quoteId) url.searchParams.set("quoteId", quoteId); + try { - const result = await axios.get(`${SQUIDROUTER_BASE_URL}/status`, { - headers: { - "x-integrator-id": integratorId - }, - params: { - fromChainId, - quoteId, - toChainId, - transactionId - } + const { data } = await squidFetch(url.toString(), { + headers: { "x-integrator-id": integratorId } }); - return result.data; + return data; } catch (error) { - if (error instanceof AxiosError && error.response) { - logger.current.error("API error:", error.response.data); + if (error instanceof HttpError) { + logger.current.error("API error:", error.data); } - logger.current.error(`Couldn't get status from squidRouter for transactionID ${transactionId}.}`); + logger.current.error(`Couldn't get status from squidRouter for transactionID ${transactionId}.`); throw error; } } diff --git a/packages/shared/src/tokens/evm/dynamicEvmTokens.ts b/packages/shared/src/tokens/evm/dynamicEvmTokens.ts index 039cdbb1b..5211c72e2 100644 --- a/packages/shared/src/tokens/evm/dynamicEvmTokens.ts +++ b/packages/shared/src/tokens/evm/dynamicEvmTokens.ts @@ -1,4 +1,3 @@ -import axios from "axios"; import { EvmNetworks, getNetworkId, isNetworkEVM, Networks } from "../../helpers/networks"; import logger from "../../logger"; import { squidRouterConfigBase } from "../../services/squidrouter/config"; @@ -245,12 +244,12 @@ function buildPriceLookup(tokensByNetwork: Record { - const result = await axios.get(SQUID_ROUTER_API_URL, { - headers: { - "x-integrator-id": squidRouterConfigBase.integratorId - } + const response = await fetch(SQUID_ROUTER_API_URL, { + headers: { "x-integrator-id": squidRouterConfigBase.integratorId } }); - return result.data.tokens; + if (!response.ok) throw new Error(`Failed to fetch SquidRouter tokens: ${response.status}`); + const data = await response.json(); + return data.tokens; } function buildFallbackFromStaticConfig(): Record>> { From ff17113c53f56fa9505ecf8f982790f9fba36d50 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Thu, 2 Apr 2026 11:41:54 +0200 Subject: [PATCH 013/117] thread AbortSignal from TanStack Query into service calls --- apps/frontend/src/hooks/alfredpay/useFiatAccounts.ts | 2 +- apps/frontend/src/hooks/useRampHistory.ts | 4 ++-- .../FeeComparisonTable/hooks/useFeeComparisonData.ts | 5 +++-- apps/frontend/src/services/api/price.service.ts | 6 ++++-- apps/frontend/src/services/api/ramp.service.ts | 9 +++++++-- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/frontend/src/hooks/alfredpay/useFiatAccounts.ts b/apps/frontend/src/hooks/alfredpay/useFiatAccounts.ts index eec131449..2b56d4ecd 100644 --- a/apps/frontend/src/hooks/alfredpay/useFiatAccounts.ts +++ b/apps/frontend/src/hooks/alfredpay/useFiatAccounts.ts @@ -18,7 +18,7 @@ export function useFiatAccounts(country: string, options?: { enabled?: boolean } const enabled = (options?.enabled ?? true) && !!country; return useQuery({ enabled, - queryFn: () => AlfredpayService.listFiatAccounts(country), + queryFn: ({ signal }) => AlfredpayService.listFiatAccounts(country, signal), queryKey: [cacheKeys.fiatAccounts, country], ...(inactiveOptions["5m"] as FiatAccountsQueryPartialOptions) }); diff --git a/apps/frontend/src/hooks/useRampHistory.ts b/apps/frontend/src/hooks/useRampHistory.ts index 018967c80..4cfc46bcb 100644 --- a/apps/frontend/src/hooks/useRampHistory.ts +++ b/apps/frontend/src/hooks/useRampHistory.ts @@ -30,12 +30,12 @@ export function useRampHistory(walletAddress?: string) { return useQuery({ enabled: addresses.length > 0, - queryFn: async () => { + queryFn: async ({ signal }) => { const allTransactions: Transaction[] = []; for (const address of addresses) { try { - const response = await RampService.getRampHistory(address, 100); + const response = await RampService.getRampHistory(address, 100, undefined, signal); const transactions = response.transactions.map(formatTransaction); allTransactions.push(...transactions); } catch (error) { diff --git a/apps/frontend/src/sections/individuals/FeeComparison/FeeComparisonTable/hooks/useFeeComparisonData.ts b/apps/frontend/src/sections/individuals/FeeComparison/FeeComparisonTable/hooks/useFeeComparisonData.ts index 195d8dc8e..8cf92d30c 100644 --- a/apps/frontend/src/sections/individuals/FeeComparison/FeeComparisonTable/hooks/useFeeComparisonData.ts +++ b/apps/frontend/src/sections/individuals/FeeComparison/FeeComparisonTable/hooks/useFeeComparisonData.ts @@ -27,13 +27,14 @@ export function useFeeComparisonData( ) { // Fetch prices from all providers (including vortex) const { data: allPricesResponse, isLoading: isLoadingPrices } = useQuery({ - queryFn: () => { + queryFn: ({ signal }) => { return PriceService.getAllPricesBundled( sourceAssetSymbol.toLowerCase() as Currency, targetAssetSymbol.toLowerCase() as Currency, amount, direction, - network + network, + signal ); }, queryKey: [cacheKeys.allPrices, amount, sourceAssetSymbol, targetAssetSymbol, network, direction], diff --git a/apps/frontend/src/services/api/price.service.ts b/apps/frontend/src/services/api/price.service.ts index 13c482841..a4eab539d 100644 --- a/apps/frontend/src/services/api/price.service.ts +++ b/apps/frontend/src/services/api/price.service.ts @@ -118,7 +118,8 @@ export class PriceService { targetCurrency: Currency, amount: string, direction: RampDirection, - network?: string + network?: string, + signal?: AbortSignal ): Promise { return apiRequest("get", `${this.BASE_PATH}/all`, undefined, { params: { @@ -127,7 +128,8 @@ export class PriceService { network, sourceCurrency, targetCurrency - } + }, + signal }); } diff --git a/apps/frontend/src/services/api/ramp.service.ts b/apps/frontend/src/services/api/ramp.service.ts index bdc8feefc..7d31672db 100644 --- a/apps/frontend/src/services/api/ramp.service.ts +++ b/apps/frontend/src/services/api/ramp.service.ts @@ -137,7 +137,12 @@ export class RampService { * @param offset The offset for pagination * @returns The transaction history */ - static async getRampHistory(walletAddress: string, limit?: number, offset?: number): Promise { + static async getRampHistory( + walletAddress: string, + limit?: number, + offset?: number, + signal?: AbortSignal + ): Promise { const queryParams = new URLSearchParams(); if (limit) queryParams.append("limit", limit.toString()); if (offset) queryParams.append("offset", offset.toString()); @@ -145,6 +150,6 @@ export class RampService { const queryString = queryParams.toString(); const url = `${this.BASE_PATH}/history/${walletAddress}${queryString ? `?${queryString}` : ""}`; - return apiRequest("get", url); + return apiRequest("get", url, undefined, { signal }); } } From b8c48e75a5f81bdfeacbc6e137c8ee73e2637ed7 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Thu, 2 Apr 2026 11:42:35 +0200 Subject: [PATCH 014/117] remove axios dependency --- apps/api/package.json | 2 +- apps/frontend/package.json | 2 +- bun.lock | 4 ---- package.json | 2 +- packages/shared/package.json | 2 +- 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index 43e2381dd..ead6396d5 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -14,7 +14,7 @@ "@supabase/supabase-js": "catalog:", "@vortexfi/shared": "workspace:*", "@wagmi/core": "catalog:", - "axios": "catalog:", + "bcrypt": "catalog:", "big.js": "catalog:", "body-parser": "^1.17.0", diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 5681d7f1c..871be846c 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -43,7 +43,7 @@ "@walletconnect/universal-provider": "^2.21.10", "@walletconnect/utils": "catalog:", "@xstate/react": "^6.0.0", - "axios": "catalog:", + "big.js": "catalog:", "bn.js": "^5.2.1", "buffer": "^6.0.3", diff --git a/bun.lock b/bun.lock index 09dcae887..173815272 100644 --- a/bun.lock +++ b/bun.lock @@ -33,7 +33,6 @@ "@supabase/supabase-js": "catalog:", "@vortexfi/shared": "workspace:*", "@wagmi/core": "catalog:", - "axios": "catalog:", "bcrypt": "catalog:", "big.js": "catalog:", "body-parser": "^1.17.0", @@ -145,7 +144,6 @@ "@walletconnect/universal-provider": "^2.21.10", "@walletconnect/utils": "catalog:", "@xstate/react": "^6.0.0", - "axios": "catalog:", "big.js": "catalog:", "bn.js": "^5.2.1", "buffer": "^6.0.3", @@ -290,7 +288,6 @@ "@scure/bip39": "catalog:", "@types/node-forge": "^1.3.14", "@wagmi/core": "catalog:", - "axios": "catalog:", "big.js": "catalog:", "node-forge": "^1.3.1", "p-queue": "^9.1.0", @@ -366,7 +363,6 @@ "@wagmi/core": "^2.22.1", "@walletconnect/types": "^2.23.0", "@walletconnect/utils": "^2.23.0", - "axios": "1.9.0", "bcrypt": "5.1.1", "big.js": "^7.0.1", "clsx": "^1.2.1", diff --git a/package.json b/package.json index e8fa11f86..a5218db25 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@wagmi/core": "^2.22.1", "@walletconnect/types": "^2.23.0", "@walletconnect/utils": "^2.23.0", - "axios": "1.9.0", + "bcrypt": "5.1.1", "big.js": "^7.0.1", "clsx": "^1.2.1", diff --git a/packages/shared/package.json b/packages/shared/package.json index 9dd8dcf41..fc25fb9ba 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -13,7 +13,7 @@ "@scure/bip39": "catalog:", "@types/node-forge": "^1.3.14", "@wagmi/core": "catalog:", - "axios": "catalog:", + "big.js": "catalog:", "node-forge": "^1.3.1", "p-queue": "^9.1.0", From 8254aa8d5177103e6c14fe0d50514df78f83f14d Mon Sep 17 00:00:00 2001 From: "aikido-autofix[bot]" <119856028+aikido-autofix[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 10:43:01 +0000 Subject: [PATCH 015/117] fix(security): update dependencies --- bun.lock | 228 +++++++++------------------------------------------ package.json | 15 +++- 2 files changed, 52 insertions(+), 191 deletions(-) diff --git a/bun.lock b/bun.lock index 09dcae887..48516a3dc 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "vortex-monorepo", @@ -316,6 +317,7 @@ }, }, "overrides": { + "@fastify/busboy": "3.2.0", "@polkadot/api": "^16.4.6", "@polkadot/api-augment": "^16.4.6", "@polkadot/api-base": "^16.4.6", @@ -332,7 +334,19 @@ "@polkadot/types-known": "^16.4.6", "@polkadot/util": "^13.5.6", "@polkadot/util-crypto": "^13.5.6", + "adm-zip": "0.5.2", + "ajv": "8.18.0", + "axios": "1.13.5", "big.js": "^7.0.1", + "bn.js": "4.12.3", + "handlebars": "4.7.9", + "lodash": "4.18.0", + "node-forge": "1.4.0", + "path-to-regexp": "8.4.0", + "pino": "10.1.1", + "tar": "7.5.11", + "tmp": "0.2.4", + "undici": "7.24.1", "viem": "^2.37.9", "wagmi": "^2.17.5", }, @@ -815,7 +829,7 @@ "@ethersproject/wordlists": ["@ethersproject/wordlists@5.8.0", "", { "dependencies": { "@ethersproject/bytes": "^5.8.0", "@ethersproject/hash": "^5.8.0", "@ethersproject/logger": "^5.8.0", "@ethersproject/properties": "^5.8.0", "@ethersproject/strings": "^5.8.0" } }, "sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg=="], - "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + "@fastify/busboy": ["@fastify/busboy@3.2.0", "", {}, "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA=="], "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], @@ -939,6 +953,8 @@ "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + "@joshwooding/vite-plugin-react-docgen-typescript": ["@joshwooding/vite-plugin-react-docgen-typescript@0.6.1", "", { "dependencies": { "glob": "^10.0.0", "magic-string": "^0.30.0", "react-docgen-typescript": "^2.2.2" }, "peerDependencies": { "typescript": ">= 4.3.x", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["typescript"] }, "sha512-J4BaTocTOYFkMHIra1JDWrMWpNmBl4EkplIwHEsV8aeUOtdWjwSnln9U7twjMFTAEB7mptNtSKyVi1Y2W9sDJw=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -1189,6 +1205,8 @@ "@phosphor-icons/webcomponents": ["@phosphor-icons/webcomponents@2.1.5", "", { "dependencies": { "lit": "^3" } }, "sha512-JcvQkZxvcX2jK+QCclm8+e8HXqtdFW9xV4/kk2aL9Y3dJA2oQVt+pzbv1orkumz3rfx4K9mn9fDoMr1He1yr7Q=="], + "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="], + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], "@polkadot-api/json-rpc-provider": ["@polkadot-api/json-rpc-provider@0.0.1", "", {}, "sha512-/SMC/l7foRjpykLTUTacIH05H3mr9ip8b5xxfwXlVezXrNVLp3Cv0GX6uItkKd+ZjzVPf3PFrDF2B2/HLSNESA=="], @@ -2217,7 +2235,7 @@ "acorn-walk": ["acorn-walk@8.3.5", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw=="], - "adm-zip": ["adm-zip@0.4.16", "", {}, "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg=="], + "adm-zip": ["adm-zip@0.5.2", "", {}, "sha512-lUI3ZSNsfQXNYNzGjt68MdxzCs0eW29lgL74y/Y2h4nARgHmH3poFWuK3LonvFbNHFt4dTb2X/QQ4c1ZUWWsJw=="], "aes-js": ["aes-js@4.0.0-beta.5", "", {}, "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="], @@ -2319,7 +2337,7 @@ "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], - "axios": ["axios@1.9.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg=="], + "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="], "axios-retry": ["axios-retry@4.5.0", "", { "dependencies": { "is-retry-allowed": "^2.2.0" }, "peerDependencies": { "axios": "0.x || 1.x" } }, "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ=="], @@ -2393,7 +2411,7 @@ "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], - "bn.js": ["bn.js@5.2.3", "", {}, "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w=="], + "bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], "body-parser": ["body-parser@1.20.4", "", { "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "~1.2.0", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", "qs": "~6.14.0", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" } }, "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA=="], @@ -2499,7 +2517,7 @@ "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], "ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], @@ -2731,8 +2749,6 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "duplexify": ["duplexify@4.1.3", "", { "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", "stream-shift": "^1.0.2" } }, "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA=="], - "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], @@ -2909,12 +2925,8 @@ "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], - "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], "fast-stable-stringify": ["fast-stable-stringify@1.0.0", "", {}, "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag=="], @@ -2991,8 +3003,6 @@ "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], - "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], - "fs-readdir-recursive": ["fs-readdir-recursive@1.1.0", "", {}, "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA=="], "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], @@ -3081,7 +3091,7 @@ "h3": ["h3@1.15.10", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-YzJeWSkDZxAhvmp8dexjRK5hxziRO7I9m0N53WhvYL5NiWfkUkzssVzY9jvGu0HBoLFW6+duYmNSn6MaZBCCtg=="], - "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], + "handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="], "hardhat": ["hardhat@2.28.6", "", { "dependencies": { "@ethereumjs/util": "^9.1.0", "@ethersproject/abi": "^5.1.2", "@nomicfoundation/edr": "0.12.0-next.23", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "adm-zip": "^0.4.16", "aggregate-error": "^3.0.0", "ansi-escapes": "^4.3.0", "boxen": "^5.1.2", "chokidar": "^4.0.0", "ci-info": "^2.0.0", "debug": "^4.1.1", "enquirer": "^2.3.0", "env-paths": "^2.2.0", "ethereum-cryptography": "^1.0.3", "find-up": "^5.0.0", "fp-ts": "1.19.3", "fs-extra": "^7.0.1", "immutable": "^4.0.0-rc.12", "io-ts": "1.10.4", "json-stream-stringify": "^3.1.4", "keccak": "^3.0.2", "lodash": "^4.17.11", "micro-eth-signer": "^0.14.0", "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", "picocolors": "^1.1.0", "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", "solc": "0.8.26", "source-map-support": "^0.5.13", "stacktrace-parser": "^0.1.10", "tinyglobby": "^0.2.6", "tsort": "0.0.1", "undici": "^5.14.0", "uuid": "^8.3.2", "ws": "^7.4.6" }, "peerDependencies": { "ts-node": "*", "typescript": "*" }, "optionalPeers": ["ts-node", "typescript"], "bin": { "hardhat": "internal/cli/bootstrap.js" } }, "sha512-zQze7qe+8ltwHvhX5NQ8sN1N37WWZGw8L63y+2XcPxGwAjc/SMF829z3NS6o1krX0sryhAsVBK/xrwUqlsot4Q=="], @@ -3427,7 +3437,7 @@ "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + "lodash": ["lodash@4.18.0", "", {}, "sha512-l1mfj2atMqndAHI3ls7XqPxEjV2J9ZkcNyHpoZA3r2T1LLwDB69jgkMWh71YKwhBbK0G2f4WSn05ahmQXVxupA=="], "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], @@ -3541,9 +3551,9 @@ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], "mipd": ["mipd@0.0.7", "", { "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg=="], @@ -3617,7 +3627,7 @@ "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], - "node-forge": ["node-forge@1.3.3", "", {}, "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg=="], + "node-forge": ["node-forge@1.4.0", "", {}, "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ=="], "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], @@ -3695,8 +3705,6 @@ "os-browserify": ["os-browserify@0.3.0", "", {}, "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A=="], - "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], - "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], "ox": ["ox@0.14.7", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-zSQ/cfBdolj7U4++NAvH7sI+VG0T3pEohITCgcQj8KlawvTDY4vGVhDT64Atsm0d6adWfIYHDpu88iUBMMp+AQ=="], @@ -3757,7 +3765,7 @@ "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "path-to-regexp": ["path-to-regexp@8.4.0", "", {}, "sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg=="], "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], @@ -3793,9 +3801,9 @@ "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], - "pino": ["pino@10.0.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "slow-redact": "^0.3.0", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA=="], + "pino": ["pino@10.1.1", "", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^3.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^4.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-3qqVfpJtRQUCAOs4rTOEwLH6mwJJ/CSAlbis8fKOiMzTtXh0HN/VLsn3UWVTJ7U8DsWmxeNon2IpGb+wORXH4g=="], - "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], + "pino-abstract-transport": ["pino-abstract-transport@3.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg=="], "pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="], @@ -4105,8 +4113,6 @@ "slice-ansi": ["slice-ansi@8.0.0", "", { "dependencies": { "ansi-styles": "^6.2.3", "is-fullwidth-code-point": "^5.1.0" } }, "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg=="], - "slow-redact": ["slow-redact@0.3.2", "", {}, "sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw=="], - "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], "smoldot": ["smoldot@2.0.26", "", { "dependencies": { "ws": "^8.8.1" } }, "sha512-F+qYmH4z2s2FK+CxGj8moYcd1ekSIKH8ywkdqlOz88Dat35iB1DIYL11aILN46YSGMzQW/lbJNS307zBSDN5Ig=="], @@ -4171,8 +4177,6 @@ "stream-json": ["stream-json@1.9.1", "", { "dependencies": { "stream-chain": "^2.2.5" } }, "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw=="], - "stream-shift": ["stream-shift@1.0.3", "", {}, "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="], - "streamx": ["streamx@2.25.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg=="], "strict-uri-encode": ["strict-uri-encode@2.0.0", "", {}, "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="], @@ -4247,7 +4251,7 @@ "tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="], - "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + "tar": ["tar@7.5.11", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ=="], "tar-stream": ["tar-stream@3.1.8", "", { "dependencies": { "b4a": "^1.6.4", "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ=="], @@ -4267,7 +4271,7 @@ "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], + "thread-stream": ["thread-stream@4.0.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA=="], "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], @@ -4297,7 +4301,7 @@ "title-case": ["title-case@3.0.3", "", { "dependencies": { "tslib": "^2.0.3" } }, "sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA=="], - "tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], + "tmp": ["tmp@0.2.4", "", {}, "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ=="], "to-buffer": ["to-buffer@1.2.2", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw=="], @@ -4401,7 +4405,7 @@ "underscore": ["underscore@1.13.8", "", {}, "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ=="], - "undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + "undici": ["undici@7.24.1", "", {}, "sha512-5xoBibbmnjlcR3jdqtY2Lnx7WbrD/tHlT01TmvqZUFVc9Q1w4+j5hbnapTqbcXITMH1ovjq/W7BkqBilHiVAaA=="], "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], @@ -4591,7 +4595,7 @@ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], @@ -4637,8 +4641,6 @@ "@coinbase/cdp-sdk/abitype": ["abitype@1.0.6", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3 >=3.22.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A=="], - "@coinbase/cdp-sdk/axios": ["axios@1.13.6", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ=="], - "@coinbase/cdp-sdk/jose": ["jose@6.2.2", "", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="], "@coinbase/wallet-sdk/@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="], @@ -4651,8 +4653,6 @@ "@coinbase/wallet-sdk/zustand": ["zustand@5.0.3", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg=="], - "@eslint/eslintrc/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], - "@eslint/eslintrc/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], "@ethereumjs/common/@ethereumjs/util": ["@ethereumjs/util@8.1.0", "", { "dependencies": { "@ethereumjs/rlp": "^4.0.1", "ethereum-cryptography": "^2.0.0", "micro-ftch": "^0.3.1" } }, "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA=="], @@ -4809,8 +4809,6 @@ "@nomicfoundation/hardhat-verify/cbor": ["cbor@8.1.0", "", { "dependencies": { "nofilter": "^3.1.0" } }, "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg=="], - "@nomicfoundation/ignition-core/lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], - "@paraspell/sdk-core/@scure/base": ["@scure/base@2.0.0", "", {}, "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w=="], "@polkadot/rpc-provider/@polkadot/x-global": ["@polkadot/x-global@14.0.3", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-MzMEynJ7HMTy/plLmdyP8rv14RS/6s29HZodUG9aCOscBnEiEDxVEax/ztRJqxhhQuHeYdx0LYDwVbdQDTkqNw=="], @@ -4845,8 +4843,6 @@ "@reown/appkit-wallet/zod": ["zod@3.22.4", "", {}, "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg=="], - "@rushstack/node-core-library/ajv": ["ajv@8.13.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.4.1" } }, "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="], - "@rushstack/node-core-library/fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], "@rushstack/node-core-library/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], @@ -5017,8 +5013,6 @@ "@walletconnect/window-metadata/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], - "@whatwg-node/node-fetch/@fastify/busboy": ["@fastify/busboy@3.2.0", "", {}, "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA=="], - "@xhmikosr/downloader/content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], "accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], @@ -5027,8 +5021,6 @@ "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "asn1.js/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], - "axios-retry/is-retry-allowed": ["is-retry-allowed@2.2.0", "", {}, "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg=="], "babel-plugin-transform-vite-meta-glob/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], @@ -5085,20 +5077,14 @@ "concat-stream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], - "create-ecdh/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], - "decompress-response/mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "diffie-hellman/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], - "eciesjs/@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], "editorconfig/commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], "editorconfig/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], - "elliptic/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], - "engine.io-client/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], "escodegen/esprima": ["esprima@2.7.3", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A=="], @@ -5109,8 +5095,6 @@ "escodegen/source-map": ["source-map@0.2.0", "", { "dependencies": { "amdefine": ">=0.0.4" } }, "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA=="], - "eslint/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], - "eslint/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], "eslint-plugin-react/doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], @@ -5127,8 +5111,6 @@ "eth-gas-reporter/@solidity-parser/parser": ["@solidity-parser/parser@0.14.5", "", { "dependencies": { "antlr4ts": "^0.5.0-alpha.4" } }, "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg=="], - "eth-gas-reporter/axios": ["axios@1.13.6", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ=="], - "eth-gas-reporter/ethers": ["ethers@5.8.0", "", { "dependencies": { "@ethersproject/abi": "5.8.0", "@ethersproject/abstract-provider": "5.8.0", "@ethersproject/abstract-signer": "5.8.0", "@ethersproject/address": "5.8.0", "@ethersproject/base64": "5.8.0", "@ethersproject/basex": "5.8.0", "@ethersproject/bignumber": "5.8.0", "@ethersproject/bytes": "5.8.0", "@ethersproject/constants": "5.8.0", "@ethersproject/contracts": "5.8.0", "@ethersproject/hash": "5.8.0", "@ethersproject/hdnode": "5.8.0", "@ethersproject/json-wallets": "5.8.0", "@ethersproject/keccak256": "5.8.0", "@ethersproject/logger": "5.8.0", "@ethersproject/networks": "5.8.0", "@ethersproject/pbkdf2": "5.8.0", "@ethersproject/properties": "5.8.0", "@ethersproject/providers": "5.8.0", "@ethersproject/random": "5.8.0", "@ethersproject/rlp": "5.8.0", "@ethersproject/sha2": "5.8.0", "@ethersproject/signing-key": "5.8.0", "@ethersproject/solidity": "5.8.0", "@ethersproject/strings": "5.8.0", "@ethersproject/transactions": "5.8.0", "@ethersproject/units": "5.8.0", "@ethersproject/wallet": "5.8.0", "@ethersproject/web": "5.8.0", "@ethersproject/wordlists": "5.8.0" } }, "sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg=="], "eth-json-rpc-filters/pify": ["pify@5.0.0", "", {}, "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA=="], @@ -5151,8 +5133,6 @@ "ethers/ws": ["ws@8.17.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="], - "ethjs-unit/bn.js": ["bn.js@4.11.6", "", {}, "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA=="], - "express/body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], "express/cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], @@ -5167,8 +5147,6 @@ "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "gaxios/https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], "gaxios/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], @@ -5247,10 +5225,6 @@ "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "miller-rabin/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], - - "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "mocha/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], "mocha/diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="], @@ -5287,8 +5261,6 @@ "nopt/abbrev": ["abbrev@1.1.1", "", {}, "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="], - "number-to-bn/bn.js": ["bn.js@4.11.6", "", {}, "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA=="], - "obj-multiplex/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "ox/@adraffy/ens-normalize": ["@adraffy/ens-normalize@1.11.1", "", {}, "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ=="], @@ -5299,8 +5271,6 @@ "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "porto/ox": ["ox@0.9.17", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-rKAnhzhRU3Xh3hiko+i1ZxywZ55eWQzeS/Q4HRKLx2PqfHOolisZHErSsJVipGlmQKHW5qwOED/GighEw9dbLg=="], "porto/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], @@ -5309,8 +5279,6 @@ "pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], - "public-encrypt/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], - "qrcode/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], "react-docgen/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], @@ -5499,8 +5467,6 @@ "@coinbase/wallet-sdk/ox/@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], - "@eslint/eslintrc/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - "@eslint/eslintrc/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "@ethereumjs/common/@ethereumjs/util/@ethereumjs/rlp": ["@ethereumjs/rlp@4.0.1", "", { "bin": { "rlp": "bin/rlp" } }, "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw=="], @@ -5545,8 +5511,6 @@ "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "@joshwooding/vite-plugin-react-docgen-typescript/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/rpc-errors": ["@metamask/rpc-errors@6.4.0", "", { "dependencies": { "@metamask/utils": "^9.0.0", "fast-safe-stringify": "^2.0.6" } }, "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg=="], "@metamask/eth-json-rpc-provider/@metamask/json-rpc-engine/@metamask/utils": ["@metamask/utils@8.5.0", "", { "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.0.0", "@noble/hashes": "^1.3.1", "@scure/base": "^1.1.3", "@types/debug": "^4.1.7", "debug": "^4.3.4", "pony-cause": "^2.1.10", "semver": "^7.5.4", "uuid": "^9.0.1" } }, "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ=="], @@ -5705,8 +5669,6 @@ "@walletconnect/utils/ox/@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], - "babel-plugin-transform-vite-meta-glob/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "borsh/bs58/base-x": ["base-x@3.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA=="], @@ -5755,8 +5717,6 @@ "eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.2", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.2", "@typescript-eslint/tsconfig-utils": "8.57.2", "@typescript-eslint/types": "8.57.2", "@typescript-eslint/visitor-keys": "8.57.2", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA=="], - "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - "eslint/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], "eth-block-tracker/@metamask/utils/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], @@ -5809,8 +5769,6 @@ "jayson/@types/ws/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="], - "js-beautify/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "js-beautify/nopt/abbrev": ["abbrev@2.0.0", "", {}, "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="], "log-update/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], @@ -6107,6 +6065,8 @@ "@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/ox": ["ox@0.9.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg=="], + "@rushstack/node-core-library/semver/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "@sentry/bundler-plugin-core/unplugin/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "@sentry/bundler-plugin-core/unplugin/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], @@ -6149,12 +6109,6 @@ "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/core/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="], - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino": ["pino@7.11.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.0.0", "on-exit-leak-free": "^0.2.0", "pino-abstract-transport": "v0.5.0", "pino-std-serializers": "^4.0.0", "process-warning": "^1.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.1.0", "safe-stable-stringify": "^2.1.0", "sonic-boom": "^2.2.1", "thread-stream": "^0.15.1" }, "bin": { "pino": "bin.js" } }, "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino": ["pino@7.11.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.0.0", "on-exit-leak-free": "^0.2.0", "pino-abstract-transport": "v0.5.0", "pino-std-serializers": "^4.0.0", "process-warning": "^1.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.1.0", "safe-stable-stringify": "^2.1.0", "sonic-boom": "^2.2.1", "thread-stream": "^0.15.1" }, "bin": { "pino": "bin.js" } }, "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino": ["pino@7.11.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.0.0", "on-exit-leak-free": "^0.2.0", "pino-abstract-transport": "v0.5.0", "pino-std-serializers": "^4.0.0", "process-warning": "^1.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.1.0", "safe-stable-stringify": "^2.1.0", "sonic-boom": "^2.2.1", "thread-stream": "^0.15.1" }, "bin": { "pino": "bin.js" } }, "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg=="], - "cli-table3/string-width/strip-ansi/ansi-regex": ["ansi-regex@3.0.1", "", {}, "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="], "cli-truncate/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], @@ -6283,14 +6237,6 @@ "@storybook/react-vite/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="], - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino": ["pino@7.11.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.0.0", "on-exit-leak-free": "^0.2.0", "pino-abstract-transport": "v0.5.0", "pino-std-serializers": "^4.0.0", "process-warning": "^1.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.1.0", "safe-stable-stringify": "^2.1.0", "sonic-boom": "^2.2.1", "thread-stream": "^0.15.1" }, "bin": { "pino": "bin.js" } }, "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino": ["pino@7.11.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.0.0", "on-exit-leak-free": "^0.2.0", "pino-abstract-transport": "v0.5.0", "pino-std-serializers": "^4.0.0", "process-warning": "^1.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.1.0", "safe-stable-stringify": "^2.1.0", "sonic-boom": "^2.2.1", "thread-stream": "^0.15.1" }, "bin": { "pino": "bin.js" } }, "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino": ["pino@7.11.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.0.0", "on-exit-leak-free": "^0.2.0", "pino-abstract-transport": "v0.5.0", "pino-std-serializers": "^4.0.0", "process-warning": "^1.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.1.0", "safe-stable-stringify": "^2.1.0", "sonic-boom": "^2.2.1", "thread-stream": "^0.15.1" }, "bin": { "pino": "bin.js" } }, "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino": ["pino@7.11.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.0.0", "on-exit-leak-free": "^0.2.0", "pino-abstract-transport": "v0.5.0", "pino-std-serializers": "^4.0.0", "process-warning": "^1.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.1.0", "safe-stable-stringify": "^2.1.0", "sonic-boom": "^2.2.1", "thread-stream": "^0.15.1" }, "bin": { "pino": "bin.js" } }, "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg=="], - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core": ["@walletconnect/core@2.21.0", "", { "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/relay-api": "1.0.11", "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", "@walletconnect/types": "2.21.0", "@walletconnect/utils": "2.21.0", "@walletconnect/window-getters": "1.0.1", "es-toolkit": "1.33.0", "events": "3.3.0", "uint8arrays": "3.1.0" } }, "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw=="], "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/@noble/ciphers": ["@noble/ciphers@1.2.1", "", {}, "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA=="], @@ -6301,48 +6247,6 @@ "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/utils/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="], - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino/on-exit-leak-free": ["on-exit-leak-free@0.2.0", "", {}, "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg=="], - - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino/pino-abstract-transport": ["pino-abstract-transport@0.5.0", "", { "dependencies": { "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ=="], - - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino/pino-std-serializers": ["pino-std-serializers@4.0.0", "", {}, "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="], - - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino/process-warning": ["process-warning@1.0.0", "", {}, "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="], - - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino/real-require": ["real-require@0.1.0", "", {}, "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="], - - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino/sonic-boom": ["sonic-boom@2.8.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg=="], - - "@walletconnect/ethereum-provider/@walletconnect/sign-client/@walletconnect/logger/pino/thread-stream": ["thread-stream@0.15.2", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino/on-exit-leak-free": ["on-exit-leak-free@0.2.0", "", {}, "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino/pino-abstract-transport": ["pino-abstract-transport@0.5.0", "", { "dependencies": { "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino/pino-std-serializers": ["pino-std-serializers@4.0.0", "", {}, "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino/process-warning": ["process-warning@1.0.0", "", {}, "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino/real-require": ["real-require@0.1.0", "", {}, "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino/sonic-boom": ["sonic-boom@2.8.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg=="], - - "@walletconnect/ethereum-provider/@walletconnect/types/@walletconnect/logger/pino/thread-stream": ["thread-stream@0.15.2", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino/on-exit-leak-free": ["on-exit-leak-free@0.2.0", "", {}, "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino/pino-abstract-transport": ["pino-abstract-transport@0.5.0", "", { "dependencies": { "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino/pino-std-serializers": ["pino-std-serializers@4.0.0", "", {}, "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino/process-warning": ["process-warning@1.0.0", "", {}, "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino/real-require": ["real-require@0.1.0", "", {}, "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino/sonic-boom": ["sonic-boom@2.8.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg=="], - - "@walletconnect/ethereum-provider/@walletconnect/universal-provider/@walletconnect/logger/pino/thread-stream": ["thread-stream@0.15.2", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="], - "command-line-usage/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], @@ -6363,62 +6267,6 @@ "solidity-coverage/web3-utils/ethereum-cryptography/@scure/bip39/@scure/base": ["@scure/base@1.1.9", "", {}, "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg=="], - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino/on-exit-leak-free": ["on-exit-leak-free@0.2.0", "", {}, "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino/pino-abstract-transport": ["pino-abstract-transport@0.5.0", "", { "dependencies": { "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino/pino-std-serializers": ["pino-std-serializers@4.0.0", "", {}, "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino/process-warning": ["process-warning@1.0.0", "", {}, "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino/real-require": ["real-require@0.1.0", "", {}, "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino/sonic-boom": ["sonic-boom@2.8.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-utils/@walletconnect/logger/pino/thread-stream": ["thread-stream@0.15.2", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino/on-exit-leak-free": ["on-exit-leak-free@0.2.0", "", {}, "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino/pino-abstract-transport": ["pino-abstract-transport@0.5.0", "", { "dependencies": { "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino/pino-std-serializers": ["pino-std-serializers@4.0.0", "", {}, "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino/process-warning": ["process-warning@1.0.0", "", {}, "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino/real-require": ["real-require@0.1.0", "", {}, "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino/sonic-boom": ["sonic-boom@2.8.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@reown/appkit-wallet/@walletconnect/logger/pino/thread-stream": ["thread-stream@0.15.2", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino/on-exit-leak-free": ["on-exit-leak-free@0.2.0", "", {}, "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino/pino-abstract-transport": ["pino-abstract-transport@0.5.0", "", { "dependencies": { "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino/pino-std-serializers": ["pino-std-serializers@4.0.0", "", {}, "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino/process-warning": ["process-warning@1.0.0", "", {}, "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino/real-require": ["real-require@0.1.0", "", {}, "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino/sonic-boom": ["sonic-boom@2.8.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/types/@walletconnect/logger/pino/thread-stream": ["thread-stream@0.15.2", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino/on-exit-leak-free": ["on-exit-leak-free@0.2.0", "", {}, "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino/pino-abstract-transport": ["pino-abstract-transport@0.5.0", "", { "dependencies": { "duplexify": "^4.1.2", "split2": "^4.0.0" } }, "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino/pino-std-serializers": ["pino-std-serializers@4.0.0", "", {}, "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino/process-warning": ["process-warning@1.0.0", "", {}, "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino/real-require": ["real-require@0.1.0", "", {}, "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino/sonic-boom": ["sonic-boom@2.8.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg=="], - - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/logger/pino/thread-stream": ["thread-stream@0.15.2", "", { "dependencies": { "real-require": "^0.1.0" } }, "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA=="], - "@walletconnect/ethereum-provider/@reown/appkit/@walletconnect/universal-provider/@walletconnect/sign-client/@walletconnect/core/uint8arrays": ["uint8arrays@3.1.0", "", { "dependencies": { "multiformats": "^9.4.2" } }, "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog=="], "eslint-plugin-storybook/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], diff --git a/package.json b/package.json index e8fa11f86..74bec386f 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,20 @@ "@polkadot/util-crypto": "^13.5.6", "big.js": "^7.0.1", "viem": "^2.37.9", - "wagmi": "^2.17.5" + "wagmi": "^2.17.5", + "handlebars": "4.7.9", + "undici": "7.24.1", + "lodash": "4.18.0", + "tar": "7.5.11", + "adm-zip": "0.5.2", + "axios": "1.13.5", + "node-forge": "1.4.0", + "path-to-regexp": "8.4.0", + "@fastify/busboy": "3.2.0", + "bn.js": "4.12.3", + "tmp": "0.2.4", + "pino": "10.1.1", + "ajv": "8.18.0" }, "packageManager": "bun@1.3.1", "private": true, From cbeeae1a771894c16d7eb61e9e3190cd9818dac0 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Thu, 2 Apr 2026 14:15:36 +0200 Subject: [PATCH 016/117] address PR comments --- apps/frontend/src/hooks/useRampHistory.ts | 1 + apps/frontend/src/services/api/api-client.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/hooks/useRampHistory.ts b/apps/frontend/src/hooks/useRampHistory.ts index 4cfc46bcb..2c0255b9e 100644 --- a/apps/frontend/src/hooks/useRampHistory.ts +++ b/apps/frontend/src/hooks/useRampHistory.ts @@ -39,6 +39,7 @@ export function useRampHistory(walletAddress?: string) { const transactions = response.transactions.map(formatTransaction); allTransactions.push(...transactions); } catch (error) { + if (error instanceof DOMException && error.name === "AbortError") throw error; console.warn(`Failed to fetch wallet history for ${address}:`, error); } } diff --git a/apps/frontend/src/services/api/api-client.ts b/apps/frontend/src/services/api/api-client.ts index fa10e6039..3c8508538 100644 --- a/apps/frontend/src/services/api/api-client.ts +++ b/apps/frontend/src/services/api/api-client.ts @@ -5,7 +5,7 @@ export class ApiError extends Error { status: number; data: { error?: string; message?: string; details?: string }; - constructor(status: number, data: Record, message: string) { + constructor(status: number, data: { error?: string; message?: string; details?: string }, message: string) { super(message); this.status = status; this.data = data; @@ -45,7 +45,7 @@ async function apiFetch( ...options.headers }, method, - signal: options.signal ?? AbortSignal.timeout(30000) + signal: options.signal ? AbortSignal.any([options.signal, AbortSignal.timeout(30000)]) : AbortSignal.timeout(30000) }); if (!response.ok) { From 5ab69658d00f2f594d08ba33c78cc7248ca1b9e8 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Tue, 7 Apr 2026 10:05:46 +0200 Subject: [PATCH 017/117] add COP support and Colombia KYC/fiat account types --- .../shared/src/endpoints/quote.endpoints.ts | 3 ++ .../supported-fiat-currencies.endpoints.ts | 31 +++++++++---------- .../services/alfredpay/alfredpayApiService.ts | 8 +++-- .../shared/src/services/alfredpay/types.ts | 20 +++++++++--- .../shared/src/tokens/freeTokens/config.ts | 4 +-- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/packages/shared/src/endpoints/quote.endpoints.ts b/packages/shared/src/endpoints/quote.endpoints.ts index df98166da..6e9f614c0 100644 --- a/packages/shared/src/endpoints/quote.endpoints.ts +++ b/packages/shared/src/endpoints/quote.endpoints.ts @@ -99,6 +99,9 @@ export enum QuoteError { BelowLowerLimitSell = "Output amount below minimum SELL limit of", BelowLowerLimitBuy = "Input amount below minimum BUY limit of", + // Availability errors + UnsupportedCurrency = "Currency not supported", + // Token/calculation errors UnableToGetPendulumTokenDetails = "Unable to get Pendulum token details", FailedToCalculateQuote = "Failed to calculate the quote. Please try a lower amount.", diff --git a/packages/shared/src/endpoints/supported-fiat-currencies.endpoints.ts b/packages/shared/src/endpoints/supported-fiat-currencies.endpoints.ts index 1e0c070ca..8c5492cfe 100644 --- a/packages/shared/src/endpoints/supported-fiat-currencies.endpoints.ts +++ b/packages/shared/src/endpoints/supported-fiat-currencies.endpoints.ts @@ -1,7 +1,10 @@ +import { FiatToken } from "../tokens"; + export interface SupportedFiatCurrency { - symbol: string; + symbol: FiatToken; name: string; decimals: number; + enabled: boolean; } export type GetSupportedFiatCurrenciesRequest = Record; @@ -11,19 +14,15 @@ export interface GetSupportedFiatCurrenciesResponse { } export const SUPPORTED_FIAT_CURRENCIES: SupportedFiatCurrency[] = [ - { - decimals: 2, - name: "Euro", - symbol: "EUR" - }, - { - decimals: 2, - name: "Brazilian Real", - symbol: "BRL" - }, - { - decimals: 2, - name: "Argentine Peso", - symbol: "ARS" - } + { decimals: 2, enabled: true, name: "Euro", symbol: FiatToken.EURC }, + { decimals: 2, enabled: true, name: "Brazilian Real", symbol: FiatToken.BRL }, + { decimals: 2, enabled: true, name: "Argentine Peso", symbol: FiatToken.ARS }, + { decimals: 2, enabled: true, name: "US Dollar", symbol: FiatToken.USD }, + { decimals: 2, enabled: true, name: "Mexican Peso", symbol: FiatToken.MXN }, + { decimals: 2, enabled: true, name: "Colombian Peso", symbol: FiatToken.COP } ]; + +export const isSupportedFiatCurrency = (value: unknown): boolean => { + if (typeof value !== "string") return false; + return SUPPORTED_FIAT_CURRENCIES.some(c => c.enabled && c.symbol === value.toUpperCase()); +}; diff --git a/packages/shared/src/services/alfredpay/alfredpayApiService.ts b/packages/shared/src/services/alfredpay/alfredpayApiService.ts index ec98a21ca..87d7adec4 100644 --- a/packages/shared/src/services/alfredpay/alfredpayApiService.ts +++ b/packages/shared/src/services/alfredpay/alfredpayApiService.ts @@ -257,9 +257,11 @@ export class AlfredpayApiService { data: SubmitKycInformationRequest ): Promise { const path = `/api/v1/third-party-service/penny/customers/${customerId}/kyc`; - return (await this.executeRequest(path, "POST", { - kycSubmission: { ...data, nationalities: [data.country] } - })) as SubmitKycInformationResponse; + const kycSubmission: Record = { ...data, nationalities: [data.country] }; + if (!data.typeDocument) delete kycSubmission.typeDocument; + if (!data.typeDocumentCol) delete kycSubmission.typeDocumentCol; + if (!data.phoneNumber) delete kycSubmission.phoneNumber; + return (await this.executeRequest(path, "POST", { kycSubmission })) as SubmitKycInformationResponse; } public async submitKycFile( diff --git a/packages/shared/src/services/alfredpay/types.ts b/packages/shared/src/services/alfredpay/types.ts index 64428b3d5..f3eceddef 100644 --- a/packages/shared/src/services/alfredpay/types.ts +++ b/packages/shared/src/services/alfredpay/types.ts @@ -14,7 +14,8 @@ export enum AlfredPayStatus { UserCompleted = "USER_COMPLETED", Verifying = "VERIFYING", Failed = "FAILED", - Success = "SUCCESS" + Success = "SUCCESS", + UpdateRequired = "UPDATE_REQUIRED" } export enum AlfredPayCountry { @@ -210,10 +211,11 @@ export interface CreateAlfredpayOfframpRequest { originAddress: string; } -// TODO: Define actual offramp statuses when the offramp flow is implemented export enum AlfredpayOfframpStatus { - PENDING = "PENDING", - COMPLETED = "COMPLETED", + ON_CHAIN_DEPOSIT_RECEIVED = "ON_CHAIN_DEPOSIT_RECEIVED", + TRADE_COMPLETED = "TRADE_COMPLETED", + FIAT_TRANSFER_INITIATED = "FIAT_TRANSFER_INITIATED", + FIAT_TRANSFER_COMPLETED = "FIAT_TRANSFER_COMPLETED", FAILED = "FAILED" } @@ -346,17 +348,25 @@ export enum AlfredpayDocumentType { PASSPORT = "passport" } +export enum AlfredpayColombiaDocumentType { + CC = "CC", + CE = "CE" +} + export interface SubmitKycInformationRequest { firstName: string; lastName: string; dateOfBirth: string; // YYYY-MM-DD - email: string; + email?: string; country: string; city: string; state: string; zipCode: string; address: string; dni: string; + typeDocument?: string; // MXN + typeDocumentCol?: AlfredpayColombiaDocumentType; + phoneNumber?: string; // Colombia } export interface SubmitKycInformationResponse { diff --git a/packages/shared/src/tokens/freeTokens/config.ts b/packages/shared/src/tokens/freeTokens/config.ts index 3d5fcfc01..031b8258f 100644 --- a/packages/shared/src/tokens/freeTokens/config.ts +++ b/packages/shared/src/tokens/freeTokens/config.ts @@ -43,8 +43,8 @@ export const freeTokenConfig: Partial> = }, maxBuyAmountRaw: "10000000000", maxSellAmountRaw: "100000000000000000000", - minBuyAmountRaw: "1", - minSellAmountRaw: "0.01", + minBuyAmountRaw: "1000000", + minSellAmountRaw: "1000000", type: TokenType.Fiat } }; From c2367bccbac34deeca81d309bd09a72c56ad2e8b Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Tue, 7 Apr 2026 10:15:37 +0200 Subject: [PATCH 018/117] extend Alfredpay phase handlers and transaction routes to MXN/COP --- .../api/controllers/alfredpay.controller.ts | 8 +++- .../controllers/fiat-currencies.controller.ts | 2 +- apps/api/src/api/middlewares/validators.ts | 14 ++++++ .../alfredpay-offramp-transfer-handler.ts | 2 +- .../handlers/final-settlement-subsidy.ts | 7 +-- .../phases/handlers/fund-ephemeral-handler.ts | 13 +++--- .../phases/handlers/initial-phase-handler.ts | 6 +-- .../squid-router-pay-phase-handler.ts | 7 ++- .../engines/fee/offramp-evm-to-alfredpay.ts | 14 ++++-- .../engines/partners/offramp-alfredpay.ts | 5 ++- .../api/src/api/services/ramp/ramp.service.ts | 16 ++++--- .../transactions/offramp/common/types.ts | 1 + .../services/transactions/offramp/index.ts | 5 ++- .../offramp/routes/evm-to-alfredpay.ts | 44 ++++++++++++++++++- .../api/services/transactions/onramp/index.ts | 4 +- .../onramp/routes/alfredpay-to-evm.ts | 14 +++++- 16 files changed, 126 insertions(+), 36 deletions(-) diff --git a/apps/api/src/api/controllers/alfredpay.controller.ts b/apps/api/src/api/controllers/alfredpay.controller.ts index 5bf4c6d2c..e688191fe 100644 --- a/apps/api/src/api/controllers/alfredpay.controller.ts +++ b/apps/api/src/api/controllers/alfredpay.controller.ts @@ -31,10 +31,11 @@ export class AlfredpayController { return AlfredPayStatus.Failed; case AlfredpayKycStatus.COMPLETED: return AlfredPayStatus.Success; + case AlfredpayKycStatus.UPDATE_REQUIRED: + return AlfredPayStatus.UpdateRequired; case AlfredpayKycStatus.CREATED: default: return null; // Do nothing - // TODO how do we map their UPDATE_REQUIRED required? what does it mean in terms of flow, for our user? } } @@ -326,6 +327,11 @@ export class AlfredpayController { const linkResponse = await alfredpayService.getKybRedirectLink(alfredPayCustomer.alfredPayId); await alfredPayCustomer.update({ status: AlfredPayStatus.Consulted }); return res.json(linkResponse as AlfredpayGetKybRedirectLinkResponse); + } else if (country === "MX" || country === "CO") { + // MX/CO use API-based (form) KYC — no redirect link needed. + // Just reset status so the user can re-fill the form. + await alfredPayCustomer.update({ status: AlfredPayStatus.Consulted }); + return res.json({ success: true }); } else { await alfredpayService.retryKycSubmission(alfredPayCustomer.alfredPayId, lastSubmission.submissionId); const linkResponse = await alfredpayService.getKycRedirectLink(alfredPayCustomer.alfredPayId, country); diff --git a/apps/api/src/api/controllers/fiat-currencies.controller.ts b/apps/api/src/api/controllers/fiat-currencies.controller.ts index b083ad08d..f8b26231d 100644 --- a/apps/api/src/api/controllers/fiat-currencies.controller.ts +++ b/apps/api/src/api/controllers/fiat-currencies.controller.ts @@ -19,7 +19,7 @@ export const getSupportedFiatCurrenciesHandler = async ( ): Promise => { try { res.status(httpStatus.OK).json({ - currencies: SUPPORTED_FIAT_CURRENCIES + currencies: SUPPORTED_FIAT_CURRENCIES.filter(c => c.enabled) }); } catch (error) { next(error); diff --git a/apps/api/src/api/middlewares/validators.ts b/apps/api/src/api/middlewares/validators.ts index cecf9178e..28e3b89fd 100644 --- a/apps/api/src/api/middlewares/validators.ts +++ b/apps/api/src/api/middlewares/validators.ts @@ -5,6 +5,7 @@ import { Currency, GetWidgetUrlLocked, GetWidgetUrlRefresh, + isSupportedFiatCurrency, isValidAveniaAccountType, isValidCurrencyForDirection, isValidDirection, @@ -396,6 +397,12 @@ export const validateCreateQuoteInput: RequestHandler { try { - // Always Polygon for Monerium onramp, Moonbeam for BRL + // Always Polygon for Monerium/Alfredpay onramp, Moonbeam for BRL const fromChain = - quote.inputCurrency === FiatToken.EURC || quote.inputCurrency === FiatToken.USD ? Networks.Polygon : Networks.Moonbeam; + quote.inputCurrency === FiatToken.EURC || isAlfredpayToken(quote.inputCurrency as FiatToken) + ? Networks.Polygon + : Networks.Moonbeam; const fromChainId = getNetworkId(fromChain)?.toString(); const toChain = quote.to === Networks.AssetHub ? Networks.Moonbeam : quote.to; const toChainId = getNetworkId(toChain)?.toString(); diff --git a/apps/api/src/api/services/quote/engines/fee/offramp-evm-to-alfredpay.ts b/apps/api/src/api/services/quote/engines/fee/offramp-evm-to-alfredpay.ts index e0fd6401f..97cd7a4b8 100644 --- a/apps/api/src/api/services/quote/engines/fee/offramp-evm-to-alfredpay.ts +++ b/apps/api/src/api/services/quote/engines/fee/offramp-evm-to-alfredpay.ts @@ -1,4 +1,4 @@ -import { EvmToken, FiatToken, RampCurrency, RampDirection } from "@vortexfi/shared"; +import { EvmToken, RampCurrency, RampDirection } from "@vortexfi/shared"; import { QuoteContext } from "../../core/types"; import { BaseFeeEngine, FeeComputation, FeeConfig } from "./index"; @@ -9,13 +9,19 @@ export class OffRampEvmToAlfredpayFeeEngine extends BaseFeeEngine { }; protected validate(ctx: QuoteContext): void { - // No specific validation needed + if (!ctx.alfredpayOfframp) { + throw new Error("OffRampEvmToAlfredpayFeeEngine requires alfredpayOfframp in context"); + } } protected async compute(ctx: QuoteContext, anchorFee: string, feeCurrency: RampCurrency): Promise { - // TODO apply fees from quote. + // biome-ignore lint/style/noNonNullAssertion: Context is validated in `validate` + const alfredpayFee = ctx.alfredpayOfframp!.fee.toString(); + // biome-ignore lint/style/noNonNullAssertion: Context is validated in `validate` + const alfredpayFeeCurrency = ctx.alfredpayOfframp!.currency as RampCurrency; + return { - anchor: { amount: "0", currency: FiatToken.USD as RampCurrency }, + anchor: { amount: alfredpayFee, currency: alfredpayFeeCurrency }, network: { amount: "0", currency: EvmToken.USDC as RampCurrency } }; } diff --git a/apps/api/src/api/services/quote/engines/partners/offramp-alfredpay.ts b/apps/api/src/api/services/quote/engines/partners/offramp-alfredpay.ts index 0e8d1d0ed..46bf0733c 100644 --- a/apps/api/src/api/services/quote/engines/partners/offramp-alfredpay.ts +++ b/apps/api/src/api/services/quote/engines/partners/offramp-alfredpay.ts @@ -48,7 +48,10 @@ export class OfframpTransactionAlfredpayEngine extends BaseInitializeEngine { const fromAmount = new Big(ctx.evmToEvm.outputAmountDecimal); const toAmount = new Big(quote.toAmount); - const alfredpayFee = Big(0); + const alfredpayFee = AlfredpayApiService.sumFeesByCurrency( + quote.fees, + req.outputCurrency as unknown as AlfredpayFiatCurrency + ); ctx.alfredpayOfframp = { currency: ctx.request.outputCurrency, diff --git a/apps/api/src/api/services/ramp/ramp.service.ts b/apps/api/src/api/services/ramp/ramp.service.ts index acf3a0bd4..59d05c9e9 100644 --- a/apps/api/src/api/services/ramp/ramp.service.ts +++ b/apps/api/src/api/services/ramp/ramp.service.ts @@ -18,6 +18,7 @@ import { GetRampStatusResponse, generateReferenceLabel, IbanPaymentData, + isAlfredpayToken, MoneriumErrors, Networks, QuoteError, @@ -272,13 +273,12 @@ export class RampService extends BaseRampService { ); let achPaymentData: AlfredpayFiatPaymentInstructions | undefined = undefined; - if (quote.inputCurrency === FiatToken.USD) { + if (isAlfredpayToken(quote.inputCurrency as FiatToken)) { achPaymentData = await this.processAlfredpayOnrampStart(rampState, quote, transaction); } - if (quote.outputCurrency === FiatToken.USD) { - // TODO mocking. Currently failing in sandbox. - //await this.processAlfredpayOfframpStart(rampState, quote, transaction); + if (isAlfredpayToken(quote.outputCurrency as FiatToken)) { + await this.processAlfredpayOfframpStart(rampState, quote, transaction); } // Create response @@ -486,6 +486,7 @@ export class RampService extends BaseRampService { } const response: GetRampStatusResponse = { + achPaymentData: rampState.state.fiatPaymentInstructions, anchorFeeFiat: fiatFees.anchor, anchorFeeUsd: usdFees.anchor, countryCode: quote.countryCode || undefined, @@ -826,6 +827,7 @@ export class RampService extends BaseRampService { userId?: string ): Promise<{ unsignedTxs: UnsignedTx[]; stateMeta: Partial }> { const { unsignedTxs, stateMeta } = await prepareOfframpTransactions({ + fiatAccountId: additionalData?.fiatAccountId as string | undefined, quote, signingAccounts: normalizedSigningAccounts, stellarPaymentData: additionalData?.paymentData, @@ -1020,7 +1022,7 @@ export class RampService extends BaseRampService { } else { if (quote.inputCurrency === FiatToken.EURC) { return this.prepareMoneriumOnrampTransactions(quote, normalizedSigningAccounts, additionalData); - } else if (quote.inputCurrency === FiatToken.USD) { + } else if (isAlfredpayToken(quote.inputCurrency as FiatToken)) { return this.prepareAlfredpayOnrampTransactions(quote, normalizedSigningAccounts, additionalData, userId); } return this.prepareAveniaOnrampTransactions(quote, normalizedSigningAccounts, additionalData, signingAccounts); @@ -1039,7 +1041,7 @@ export class RampService extends BaseRampService { } private validateRampStateData(rampState: RampState, quote: QuoteTicket): void { - if (rampState.type === RampDirection.SELL && quote.outputCurrency !== FiatToken.USD) { + if (rampState.type === RampDirection.SELL && !isAlfredpayToken(quote.outputCurrency as FiatToken)) { if (rampState.from === Networks.AssetHub && !rampState.state.assethubToPendulumHash) { throw new APIError({ message: `Missing required additional data 'assethubToPendulumHash' for ${rampState.type} ramp. Cannot proceed.`, @@ -1159,7 +1161,7 @@ export class RampService extends BaseRampService { chain: AlfredpayChain.MATIC, customerId: rampState.state.alfredpayUserId, depositAddress: rampState.state.evmEphemeralAddress, - fromCurrency: AlfredpayFiatCurrency.USD, + fromCurrency: quote.inputCurrency as unknown as AlfredpayFiatCurrency, paymentMethodType: AlfredpayPaymentMethodType.BANK, quoteId: alfredpayQuoteId, toCurrency: AlfredpayOnChainCurrency.USDC diff --git a/apps/api/src/api/services/transactions/offramp/common/types.ts b/apps/api/src/api/services/transactions/offramp/common/types.ts index c97f216b3..f1c1a9f57 100644 --- a/apps/api/src/api/services/transactions/offramp/common/types.ts +++ b/apps/api/src/api/services/transactions/offramp/common/types.ts @@ -12,6 +12,7 @@ export interface OfframpTransactionParams { brlaEvmAddress?: string; moneriumAuthToken?: string; userId?: string; + fiatAccountId?: string; } export interface OfframpTransactionsWithMeta { diff --git a/apps/api/src/api/services/transactions/offramp/index.ts b/apps/api/src/api/services/transactions/offramp/index.ts index 4793d7b6f..4edc1d6bf 100644 --- a/apps/api/src/api/services/transactions/offramp/index.ts +++ b/apps/api/src/api/services/transactions/offramp/index.ts @@ -2,6 +2,7 @@ import { FiatToken, getNetworkFromDestination, getOnChainTokenDetails, + isAlfredpayToken, isEvmTokenDetails, OnChainToken } from "@vortexfi/shared"; @@ -32,8 +33,8 @@ export async function prepareOfframpTransactions(params: OfframpTransactionParam } else if (quote.outputCurrency === FiatToken.EURC && params.moneriumAuthToken) { // Monerium EVM offramp return prepareEvmToMoneriumEvmOfframpTransactions(params); - } else if (quote.outputCurrency === FiatToken.USD) { - // Alfredpay offramp + } else if (isAlfredpayToken(quote.outputCurrency as FiatToken)) { + // Alfredpay offramp (USD, MXN, COP) return prepareEvmToAlfredpayOfframpTransactions(params); } else { // Stellar offramp diff --git a/apps/api/src/api/services/transactions/offramp/routes/evm-to-alfredpay.ts b/apps/api/src/api/services/transactions/offramp/routes/evm-to-alfredpay.ts index 23cc936e7..6a095d54c 100644 --- a/apps/api/src/api/services/transactions/offramp/routes/evm-to-alfredpay.ts +++ b/apps/api/src/api/services/transactions/offramp/routes/evm-to-alfredpay.ts @@ -1,11 +1,17 @@ import { + AlfredPayCountry, AlfredPayStatus, + AlfredpayApiService, + AlfredpayChain, + AlfredpayFiatCurrency, + AlfredpayOnChainCurrency, createOfframpSquidrouterTransactionsToEvm, ERC20_USDC_POLYGON, EvmClientManager, EvmNetworks, EvmTokenDetails, EvmTransactionData, + FiatToken, getNetworkFromDestination, getNetworkId, getOnChainTokenDetails, @@ -123,6 +129,7 @@ const erc20Abi = [ * This route handles: EVM → Polygon (USDC) → Alfredpay (Fiat) */ export async function prepareEvmToAlfredpayOfframpTransactions({ + fiatAccountId, quote, signingAccounts, userAddress, @@ -160,8 +167,18 @@ export async function prepareEvmToAlfredpayOfframpTransactions({ throw new Error(`Unsupported source network ${fromNetwork} for EVM to Alfredpay type offramp`); } + const fiatToCountry: Partial> = { + [FiatToken.USD]: AlfredPayCountry.US, + [FiatToken.MXN]: AlfredPayCountry.MX, + [FiatToken.COP]: AlfredPayCountry.CO + }; + const customerCountry = fiatToCountry[quote.outputCurrency as FiatToken]; + if (!customerCountry) { + throw new Error(`Unsupported Alfredpay output currency: ${quote.outputCurrency}`); + } + const customer = await AlfredPayCustomer.findOne({ - where: { userId } + where: { country: customerCountry, userId } }); if (!customer) { @@ -172,6 +189,27 @@ export async function prepareEvmToAlfredpayOfframpTransactions({ throw new Error(`Alfredpay customer status is ${customer.status}, expected Success. Proceed first with KYC.`); } + if (!fiatAccountId) { + throw new Error("fiatAccountId is required for Alfredpay offramp"); + } + + const alfredpayQuoteId = quote.metadata.alfredpayOfframp?.quoteId; + if (!alfredpayQuoteId) { + throw new Error("Missing alfredpayOfframp.quoteId in quote metadata"); + } + + const alfredpayService = AlfredpayApiService.getInstance(); + const offrampOrder = await alfredpayService.createOfframp({ + amount: quote.inputAmount, + chain: AlfredpayChain.MATIC, + customerId: customer.alfredPayId, + fiatAccountId, + fromCurrency: AlfredpayOnChainCurrency.USDC, + originAddress: userAddress, + quoteId: alfredpayQuoteId, + toCurrency: quote.outputCurrency as unknown as AlfredpayFiatCurrency + }); + const inputAmountRaw = new Big(quote.inputAmount).mul(new Big(10).pow(inputTokenDetails.decimals)).toFixed(0, 0); const bridgeResult = await createOfframpSquidrouterTransactionsToEvm({ @@ -280,8 +318,10 @@ export async function prepareEvmToAlfredpayOfframpTransactions({ stateMeta = { ...stateMeta, + alfredpayTransactionId: offrampOrder.transactionId, alfredpayUserId: customer.alfredPayId, evmEphemeralAddress: evmEphemeralEntry.address, + fiatAccountId, squidRouterPermitExecutionValue: bridgeResult.swapData.value, walletAddress: userAddress }; @@ -289,7 +329,7 @@ export async function prepareEvmToAlfredpayOfframpTransactions({ const finalTransferTxData = await addOnrampDestinationChainTransactions({ amountRaw: quote.metadata.alfredpayOfframp.inputAmountRaw, destinationNetwork: Networks.Polygon as EvmNetworks, - toAddress: "0x7Ba99e99Bc669B3508AFf9CC0A898E869459F877", // TODO placeholder + toAddress: offrampOrder.depositAddress as `0x${string}`, toToken: ERC20_USDC_POLYGON }); diff --git a/apps/api/src/api/services/transactions/onramp/index.ts b/apps/api/src/api/services/transactions/onramp/index.ts index 4227e3184..d2f99e229 100644 --- a/apps/api/src/api/services/transactions/onramp/index.ts +++ b/apps/api/src/api/services/transactions/onramp/index.ts @@ -1,4 +1,4 @@ -import { FiatToken, Networks } from "@vortexfi/shared"; +import { FiatToken, isAlfredpayToken, Networks } from "@vortexfi/shared"; import { AlfredpayOnrampTransactionParams, AveniaOnrampTransactionParams, @@ -44,7 +44,7 @@ export async function prepareOnrampTransactions( } else { return prepareMoneriumToEvmOnrampTransactions(params); } - } else if (quote.inputCurrency === FiatToken.USD) { + } else if (isAlfredpayToken(quote.inputCurrency as FiatToken)) { if (!("userId" in params)) { throw new Error("Alfredpay onramps requires logged in user"); } diff --git a/apps/api/src/api/services/transactions/onramp/routes/alfredpay-to-evm.ts b/apps/api/src/api/services/transactions/onramp/routes/alfredpay-to-evm.ts index 3eac4077d..8e0999e52 100644 --- a/apps/api/src/api/services/transactions/onramp/routes/alfredpay-to-evm.ts +++ b/apps/api/src/api/services/transactions/onramp/routes/alfredpay-to-evm.ts @@ -1,4 +1,5 @@ import { + AlfredPayCountry, AlfredPayStatus, createOnrampSquidrouterTransactionsFromPolygonToEvm, createOnrampSquidrouterTransactionsOnDestinationChain, @@ -8,6 +9,7 @@ import { EvmTokenDetails, EvmTransactionData, evmTokenConfig, + FiatToken, getNetworkFromDestination, getOnChainTokenDetails, getOnChainTokenDetailsOrDefault, @@ -60,8 +62,18 @@ export async function prepareAlfredpayToEvmOnrampTransactions({ throw new Error(`Output token details not found for ${quote.outputCurrency} on network ${toNetwork}`); } + const fiatToCountry: Partial> = { + [FiatToken.USD]: AlfredPayCountry.US, + [FiatToken.MXN]: AlfredPayCountry.MX, + [FiatToken.COP]: AlfredPayCountry.CO + }; + const customerCountry = fiatToCountry[quote.inputCurrency as FiatToken]; + if (!customerCountry) { + throw new Error(`Unsupported Alfredpay input currency: ${quote.inputCurrency}`); + } + const customer = await AlfredPayCustomer.findOne({ - where: { userId } + where: { country: customerCountry, userId } }); if (!customer) { From 8071888cbf888f1c116307dcb232e7075f327905 Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Tue, 7 Apr 2026 10:20:47 +0200 Subject: [PATCH 019/117] restore Alfredpay document upload on back navigation --- .../src/hooks/useStepBackNavigation.ts | 17 ++++- .../src/machines/alfredpayKyc.machine.ts | 70 +++++++++++++------ 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/apps/frontend/src/hooks/useStepBackNavigation.ts b/apps/frontend/src/hooks/useStepBackNavigation.ts index d61190cc5..7e9fcfab7 100644 --- a/apps/frontend/src/hooks/useStepBackNavigation.ts +++ b/apps/frontend/src/hooks/useStepBackNavigation.ts @@ -2,13 +2,21 @@ import { useNavigate, useSearch } from "@tanstack/react-router"; import { useSelector } from "@xstate/react"; import { useEffect, useRef } from "react"; import { useFiatAccountActor, useFiatAccountSelector } from "../contexts/FiatAccountMachineContext"; -import { useAveniaKycActor, useAveniaKycSelector, useRampActor } from "../contexts/rampState"; +import { + useAlfredpayKycActor, + useAlfredpayKycSelector, + useAveniaKycActor, + useAveniaKycSelector, + useRampActor +} from "../contexts/rampState"; export const useStepBackNavigation = () => { const navigate = useNavigate(); const rampActor = useRampActor(); const aveniaKycActor = useAveniaKycActor(); const aveniaState = useAveniaKycSelector(); + const alfredpayKycActor = useAlfredpayKycActor(); + const alfredpayKycState = useAlfredpayKycSelector(); const fiatAccountActor = useFiatAccountActor(); const showFiatAccountRegistration = useFiatAccountSelector(s => s.matches("Open")); @@ -50,6 +58,13 @@ export const useStepBackNavigation = () => { return; } + if (alfredpayKycActor && alfredpayKycState) { + if (alfredpayKycState.stateValue === "UploadingDocuments") { + alfredpayKycActor.send({ type: "GO_BACK" }); + return; + } + } + if (aveniaKycActor && aveniaState) { const childState = aveniaState.stateValue; if (childState === "DocumentUpload") { diff --git a/apps/frontend/src/machines/alfredpayKyc.machine.ts b/apps/frontend/src/machines/alfredpayKyc.machine.ts index b63416666..f4ceedb3f 100644 --- a/apps/frontend/src/machines/alfredpayKyc.machine.ts +++ b/apps/frontend/src/machines/alfredpayKyc.machine.ts @@ -1,4 +1,4 @@ -import { AlfredPayStatus, AlfredpayCustomerType, AlfredpayKycFileType } from "@vortexfi/shared"; +import { AlfredPayStatus, AlfredpayColombiaDocumentType, AlfredpayCustomerType, AlfredpayKycFileType } from "@vortexfi/shared"; import { assign, fromPromise, setup } from "xstate"; import { AlfredpayService } from "../services/api/alfredpay.service"; import { AlfredpayKycContext } from "./kyc.states"; @@ -7,12 +7,15 @@ export interface MxnKycFormData { firstName: string; lastName: string; dateOfBirth: string; - email: string; + email?: string; city: string; state: string; zipCode: string; address: string; dni: string; + documentType?: string; // MXN + typeDocumentCol?: AlfredpayColombiaDocumentType; + phoneNumber?: string; // Colombia } export interface MxnKycFiles { @@ -85,7 +88,11 @@ export const alfredpayKycMachine = setup({ country, input.business ? AlfredpayCustomerType.BUSINESS : AlfredpayCustomerType.INDIVIDUAL ); - if (response.status === AlfredPayStatus.Success || response.status === AlfredPayStatus.Failed) { + if ( + response.status === AlfredPayStatus.Success || + response.status === AlfredPayStatus.Failed || + response.status === AlfredPayStatus.UpdateRequired + ) { return response; } } catch (e) { @@ -120,16 +127,14 @@ export const alfredpayKycMachine = setup({ async ({ input }: { input: AlfredpayKycContext & { mxnFormData?: MxnKycFormData; mxnFiles?: MxnKycFiles } }) => { const country = input.country || "MX"; if (!input.submissionId) throw new Error("Submission ID missing"); - if (!input.mxnFiles) throw new Error("MXN KYC files missing"); + if (!input.mxnFiles) throw new Error("KYC files missing"); await AlfredpayService.submitKycFile(country, input.submissionId, AlfredpayKycFileType.FRONT, input.mxnFiles.front); - if (input.mxnFiles.back && input.mxnFormData?.documentType !== "Passport") { - await AlfredpayService.submitKycFile(country, input.submissionId, AlfredpayKycFileType.BACK, input.mxnFiles.back); - } + await AlfredpayService.submitKycFile(country, input.submissionId, AlfredpayKycFileType.BACK, input.mxnFiles.back); } ), submitKycInfo: fromPromise(async ({ input }: { input: AlfredpayKycContext & { mxnFormData?: MxnKycFormData } }) => { const country = input.country || "MX"; - if (!input.mxnFormData) throw new Error("MXN KYC form data missing"); + if (!input.mxnFormData) throw new Error("KYC form data missing"); return AlfredpayService.submitKycInformation(country, input.mxnFormData); }), @@ -148,7 +153,8 @@ export const alfredpayKycMachine = setup({ if ( status.status === AlfredPayStatus.Verifying || status.status === AlfredPayStatus.Success || - status.status === AlfredPayStatus.Failed + status.status === AlfredPayStatus.Failed || + status.status === AlfredPayStatus.UpdateRequired ) { return status; } @@ -181,6 +187,7 @@ export const alfredpayKycMachine = setup({ | { type: "CANCEL_PROCESS" } | { type: "USER_RETRY" } | { type: "USER_CANCEL" } + | { type: "GO_BACK" } | { type: "SUBMIT_FORM"; data: MxnKycFormData } | { type: "SUBMIT_FILES"; files: MxnKycFiles }, input: {} as AlfredpayKycContext, @@ -215,12 +222,13 @@ export const alfredpayKycMachine = setup({ AlfredpayKycMachineErrorType.UnknownError ) }), - guard: ({ event }) => event.output.status === AlfredPayStatus.Failed, + guard: ({ event }) => + event.output.status === AlfredPayStatus.Failed || event.output.status === AlfredPayStatus.UpdateRequired, target: "FailureKyc" }, { - // MXN uses API-based form, not iFrame link - guard: ({ context }) => context.country === "MX", + // MXN and CO use API-based form, not iFrame link + guard: ({ context }) => context.country === "MX" || context.country === "CO", target: "FillingKycForm" }, { @@ -230,9 +238,9 @@ export const alfredpayKycMachine = setup({ ], onError: [ { - // MXN: no customer → skip CustomerDefinition, always individual + // MXN/CO: no customer → skip CustomerDefinition, always individual guard: ({ context, event }) => - context.country === "MX" && + (context.country === "MX" || context.country === "CO") && ((event.error as Error).message.includes("404") || (event.error as Error).message.includes("Not Found")), target: "CreatingCustomer" }, @@ -258,7 +266,7 @@ export const alfredpayKycMachine = setup({ input: ({ context }) => context, onDone: [ { - guard: ({ context }) => context.country === "MX", + guard: ({ context }) => context.country === "MX" || context.country === "CO", target: "FillingKycForm" }, { @@ -338,10 +346,18 @@ export const alfredpayKycMachine = setup({ FillingKycForm: { on: { - SUBMIT_FORM: { - actions: assign({ mxnFormData: ({ event }) => event.data }), - target: "SubmittingKycInfo" - } + SUBMIT_FORM: [ + { + actions: assign({ mxnFormData: ({ event }) => event.data }), + // submissionId exists → user returned from doc upload, skip re-submission + guard: ({ context }) => !!context.submissionId, + target: "UploadingDocuments" + }, + { + actions: assign({ mxnFormData: ({ event }) => event.data }), + target: "SubmittingKycInfo" + } + ] } }, FinishingFilling: { @@ -425,7 +441,8 @@ export const alfredpayKycMachine = setup({ AlfredpayKycMachineErrorType.UnknownError ) }), - guard: ({ event }) => event.output.status === AlfredPayStatus.Failed, + guard: ({ event }) => + event.output.status === AlfredPayStatus.Failed || event.output.status === AlfredPayStatus.UpdateRequired, target: "FailureKyc" } ], @@ -436,9 +453,15 @@ export const alfredpayKycMachine = setup({ invoke: { id: "retryKyc", input: ({ context }) => context, - onDone: { - target: "GettingKycLink" - }, + onDone: [ + { + guard: ({ context }) => context.country === "MX" || context.country === "CO", + target: "FillingKycForm" + }, + { + target: "GettingKycLink" + } + ], onError: { actions: assign({ error: ({ context }) => @@ -510,6 +533,7 @@ export const alfredpayKycMachine = setup({ UploadingDocuments: { on: { + GO_BACK: { target: "FillingKycForm" }, SUBMIT_FILES: { actions: assign({ mxnFiles: ({ event }) => event.files }), target: "SubmittingFiles" From 69b1528560b8a7dd41d7d46c9c326f71b26942ba Mon Sep 17 00:00:00 2001 From: Kacper Szarkiewicz Date: Tue, 7 Apr 2026 10:21:11 +0200 Subject: [PATCH 020/117] add Colombia KYC form and ACH fiat account registration --- .../components/Alfredpay/AlfredpayKycFlow.tsx | 10 +++- .../components/Alfredpay/ColKycFormScreen.tsx | 50 +++++++++------- .../components/Alfredpay/MxnKycFormScreen.tsx | 18 ++++++ .../SummaryStep/COPOnrampDetails.tsx | 60 +++++++++++++++++++ .../SummaryStep/FiatAccountSelector.tsx | 9 ++- .../SummaryStep/MXNOnrampDetails.tsx | 60 +++++++++++++++++++ .../SummaryStep/TransactionTokensDisplay.tsx | 4 ++ apps/frontend/src/config/tokenAvailability.ts | 42 +++++-------- .../src/constants/fiatAccountForms.ts | 22 +++++++ .../src/constants/fiatAccountMethods.ts | 33 +++++++--- apps/frontend/src/machines/kyc.states.ts | 7 ++- .../AccountCardDeck.tsx | 27 ++++++--- .../RegisteredAccountsList.tsx | 12 +++- .../FiatAccountRegistration/index.tsx | 1 + apps/frontend/src/translations/en.json | 45 +++++++++++++- apps/frontend/src/translations/pt.json | 45 +++++++++++++- 16 files changed, 366 insertions(+), 79 deletions(-) create mode 100644 apps/frontend/src/components/widget-steps/SummaryStep/COPOnrampDetails.tsx create mode 100644 apps/frontend/src/components/widget-steps/SummaryStep/MXNOnrampDetails.tsx diff --git a/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx b/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx index 2f1000faf..377715fbc 100644 --- a/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx +++ b/apps/frontend/src/components/Alfredpay/AlfredpayKycFlow.tsx @@ -1,5 +1,6 @@ import { useCallback } from "react"; import { useAlfredpayKycActor, useAlfredpayKycSelector } from "../../contexts/rampState"; +import { ColKycFormScreen } from "./ColKycFormScreen"; import { CustomerDefinitionScreen } from "./CustomerDefinitionScreen"; import { DoneScreen } from "./DoneScreen"; import { FailureKycScreen } from "./FailureKycScreen"; @@ -39,6 +40,7 @@ export const AlfredpayKycFlow = () => { const { stateValue, context } = state; const kycOrKyb = context.business ? "KYB" : "KYC"; const isMxn = context.country === "MX"; + const isCo = context.country === "CO"; if ( stateValue === "CheckingStatus" || @@ -56,7 +58,11 @@ export const AlfredpayKycFlow = () => { return ; } - if (stateValue === "UploadingDocuments" && isMxn) { + if (stateValue === "FillingKycForm" && isCo) { + return ; + } + + if (stateValue === "UploadingDocuments" && (isMxn || isCo)) { return ; } @@ -102,7 +108,7 @@ export const AlfredpayKycFlow = () => { return ; } - if (stateValue === "CustomerDefinition" && !isMxn) { + if (stateValue === "CustomerDefinition" && !isMxn && !isCo) { return ( { - if (data.documentType === "CC" && data.dni.length !== 10) { + if (data.typeDocumentCol === "CC" && data.dni.length !== 10) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "CC must be exactly 10 digits", path: ["dni"] }); } }); @@ -40,7 +43,7 @@ export function ColKycFormScreen({ onSubmit }: ColKycFormScreenProps) { watch } = useForm({ resolver: zodResolver(schema) }); - const documentType = watch("documentType"); + const documentType = watch("typeDocumentCol"); const inputClass = (hasError: boolean) => `input-vortex-primary input-ghost w-full rounded-lg border p-2 text-base ${hasError ? "border-error" : "border-neutral-300"}`; @@ -96,35 +99,20 @@ export function ColKycFormScreen({ onSubmit }: ColKycFormScreenProps) { {errors.dateOfBirth && {errors.dateOfBirth.message}}
-
- - - {errors.email && {errors.email.message}} -
-
- {errors.documentType && {errors.documentType.message}} + {errors.typeDocumentCol && {errors.typeDocumentCol.message}}
@@ -144,6 +132,22 @@ export function ColKycFormScreen({ onSubmit }: ColKycFormScreenProps) { {errors.dni && {errors.dni.message}}
+
+ + + {errors.phoneNumber && {errors.phoneNumber.message}} +
+
+
+ + + {errors.documentType && {errors.documentType.message}} +
+