@@ -31,14 +31,16 @@ import { type FakeWorld, installFakeWorld } from "../../test-utils/fake-world";
3131import { installFakeSupabaseAuth , testUserToken } from "../../test-utils/fake-world/fake-auth" ;
3232import { startTestApp , type TestApp } from "../../test-utils/test-app" ;
3333
34- const USDT_ON_ARBITRUM = evmTokenConfig [ Networks . Arbitrum ] [ EvmToken . USDT ] ?. erc20AddressSourceChain as `0x${ string } ` ;
35- if ( ! USDT_ON_ARBITRUM ) {
34+ const USDT_ON_ARBITRUM_CONFIG = evmTokenConfig [ Networks . Arbitrum ] [ EvmToken . USDT ] ;
35+ if ( ! USDT_ON_ARBITRUM_CONFIG ?. erc20AddressSourceChain ) {
3636 throw new Error ( "USDT token config missing for Arbitrum" ) ;
3737}
38- const USDT_ON_BSC = evmTokenConfig [ Networks . BSC ] [ EvmToken . USDT ] ?. erc20AddressSourceChain as `0x${string } `;
39- if ( ! USDT_ON_BSC ) {
38+ const USDT_ON_ARBITRUM = USDT_ON_ARBITRUM_CONFIG . erc20AddressSourceChain as `0x${string } `;
39+ const USDT_ON_BSC_CONFIG = evmTokenConfig [ Networks . BSC ] [ EvmToken . USDT ] ;
40+ if ( ! USDT_ON_BSC_CONFIG ?. erc20AddressSourceChain ) {
4041 throw new Error ( "USDT token config missing for BSC" ) ;
4142}
43+ const USDT_ON_BSC = USDT_ON_BSC_CONFIG . erc20AddressSourceChain as `0x${string } `;
4244
4345const CHAIN_IDS : Partial < Record < Networks , number > > = {
4446 [ Networks . Arbitrum ] : 42161 ,
@@ -156,6 +158,35 @@ const CROSS_CHAIN_OFFRAMP_CASES: CurrencyCase[] = [
156158 }
157159] ;
158160
161+ interface CrossChainOfframpSource {
162+ chainId : string ;
163+ label : "Arbitrum" | "BSC" ;
164+ network : typeof Networks . Arbitrum | typeof Networks . BSC ;
165+ token : `0x${string } `;
166+ tokenDecimals : number ;
167+ }
168+
169+ const ARBITRUM_OFFRAMP_SOURCE = {
170+ chainId : "42161" ,
171+ label : "Arbitrum" ,
172+ network : Networks . Arbitrum ,
173+ token : USDT_ON_ARBITRUM ,
174+ tokenDecimals : USDT_ON_ARBITRUM_CONFIG . decimals
175+ } satisfies CrossChainOfframpSource ;
176+
177+ const BSC_OFFRAMP_SOURCE = {
178+ chainId : "56" ,
179+ label : "BSC" ,
180+ network : Networks . BSC ,
181+ token : USDT_ON_BSC ,
182+ tokenDecimals : USDT_ON_BSC_CONFIG . decimals
183+ } satisfies CrossChainOfframpSource ;
184+
185+ const CROSS_CHAIN_OFFRAMP_TEST_CASES = [
186+ ...CROSS_CHAIN_OFFRAMP_CASES . map ( currency => ( { currency, source : ARBITRUM_OFFRAMP_SOURCE } ) ) ,
187+ { currency : CURRENCY_CASES [ 0 ] , source : BSC_OFFRAMP_SOURCE }
188+ ] ;
189+
159190/**
160191 * Parameterized scenarios for the Alfredpay corridors beyond MXN: USD (ach),
161192 * COP (ach) and ARS (cbu), each in both directions. The deeper security and
@@ -166,8 +197,9 @@ const CROSS_CHAIN_OFFRAMP_CASES: CurrencyCase[] = [
166197 * The cross-chain legs run here per currency too: BUY bridges the Polygon mint
167198 * to Arbitrum via squid (mirroring the MXN cross-chain corridor) and SELL
168199 * takes the no-permit cross-chain fallback (user-broadcast squid approve+swap
169- * on BSC, verified by hash before the Polygon deposit transfer) — the
170- * latter including MXN, whose own files only cover the direct Polygon path.
200+ * on Arbitrum, verified by hash before the Polygon deposit transfer) — the
201+ * latter including MXN, whose own files only cover the direct Polygon path —
202+ * plus a focused BSC case for its 18-to-6-decimal permit-probe regression.
171203 */
172204describe ( "Alfredpay currency corridors (USD/COP/ARS, on- and offramp)" , ( ) => {
173205 let world : FakeWorld ;
@@ -199,6 +231,7 @@ describe("Alfredpay currency corridors (USD/COP/ARS, on- and offramp)", () => {
199231 world . alfredpay . offrampDepositAddress = privateKeyToAccount ( generatePrivateKey ( ) ) . address . toLowerCase ( ) ;
200232 // Both direct and cross-chain Alfredpay SELL simulations price a
201233 // Squid-delivered Polygon USDT settlement leg.
234+ world . squidRouter . computeToAmount = params => params . fromAmount ;
202235 world . squidRouter . toTokenDecimals = 6 ;
203236 world . squidRouter . bridgeStatus = "success" ;
204237 } ) ;
@@ -618,15 +651,20 @@ describe("Alfredpay currency corridors (USD/COP/ARS, on- and offramp)", () => {
618651 /**
619652 * Cross-chain SELL setup via the HTTP API on the no-permit fallback (the
620653 * Alfredpay analog of the BRL cross-chain offramp's squid-hash flow): the
621- * user broadcasts the squid approve + swap from their own wallet on BSC ,
654+ * user broadcasts the squid approve + swap from their own wallet on the source chain ,
622655 * the hashes are reported through /v1/ramp/update together with
623656 * the presigned Polygon deposit transfer, and squidRouterPermitExecute
624657 * verifies them against the blueprints before any ephemeral funds move.
625658 */
626- async function setUpCrossChainOfframpRamp ( currency : CurrencyCase ) : Promise < CrossChainOfframpSetup > {
659+ async function setUpCrossChainOfframpRamp (
660+ currency : CurrencyCase ,
661+ source : CrossChainOfframpSource
662+ ) : Promise < CrossChainOfframpSetup > {
627663 world . alfredpay . offrampRate = currency . offrampRate ;
628- // The user's squid leg swaps 18-decimal BSC USDT into 6-decimal Polygon
629- // USDT; the fake route must report destination decimals.
664+ // The fake route is a decimal 1:1 swap, so convert source raw units into
665+ // 6-decimal Polygon USDT raw units instead of re-labelling them.
666+ world . squidRouter . computeToAmount = params =>
667+ ( BigInt ( params . fromAmount ) / 10n ** BigInt ( source . tokenDecimals - ALFREDPAY_ERC20_DECIMALS ) ) . toString ( ) ;
630668 world . squidRouter . toTokenDecimals = 6 ;
631669 const ephemeral = privateKeyToAccount ( generatePrivateKey ( ) ) ;
632670 const userWallet = privateKeyToAccount ( generatePrivateKey ( ) ) ;
@@ -636,10 +674,10 @@ describe("Alfredpay currency corridors (USD/COP/ARS, on- and offramp)", () => {
636674 const user = await createTestUser ( ) ;
637675 await createTestAlfredpayCustomer ( user . id , { country : currency . country } ) ;
638676 const quote = await createQuoteViaApi ( {
639- from : Networks . BSC ,
677+ from : source . network ,
640678 inputAmount : currency . offrampInputAmount ,
641679 inputCurrency : EvmToken . USDT ,
642- network : Networks . BSC ,
680+ network : source . network ,
643681 outputCurrency : currency . fiat ,
644682 rampType : RampDirection . SELL ,
645683 to : currency . rail
@@ -651,9 +689,21 @@ describe("Alfredpay currency corridors (USD/COP/ARS, on- and offramp)", () => {
651689
652690 const persistedQuote = await QuoteTicket . findByPk ( quote . id ) ;
653691 const metadata = persistedQuote ?. metadata as unknown as
654- | { blocks : { alfredpayOfframp ?: { inputAmountRaw ?: string } } }
692+ | {
693+ blocks : {
694+ alfredpayOfframp ?: {
695+ bridgeInputAmountRaw ?: string ;
696+ bridgeOutputAmountRaw ?: string ;
697+ inputAmountRaw ?: string ;
698+ } ;
699+ } ;
700+ }
655701 | undefined ;
702+ const bridgeInputAmountRaw = BigInt ( metadata ?. blocks . alfredpayOfframp ?. bridgeInputAmountRaw ?? "0" ) ;
703+ const bridgeOutputAmountRaw = BigInt ( metadata ?. blocks . alfredpayOfframp ?. bridgeOutputAmountRaw ?? "0" ) ;
656704 const inputAmountRaw = BigInt ( metadata ?. blocks . alfredpayOfframp ?. inputAmountRaw ?? "0" ) ;
705+ expect ( bridgeInputAmountRaw ) . toBe ( parseUnits ( currency . offrampInputAmount , source . tokenDecimals ) ) ;
706+ expect ( bridgeOutputAmountRaw ) . toBe ( parseUnits ( currency . offrampInputAmount , ALFREDPAY_ERC20_DECIMALS ) ) ;
657707 expect ( inputAmountRaw ) . toBeGreaterThan ( 0n ) ;
658708
659709 const registered = await RampState . findByPk ( ramp . id ) ;
@@ -664,8 +714,8 @@ describe("Alfredpay currency corridors (USD/COP/ARS, on- and offramp)", () => {
664714 const approveBlueprint = blueprintOf ( allUnsignedTxs , "squidRouterNoPermitApprove" ) ;
665715 const swapBlueprint = blueprintOf ( allUnsignedTxs , "squidRouterNoPermitSwap" ) ;
666716 const offrampTransferBlueprint = blueprintOf ( allUnsignedTxs , "alfredpayOfframpTransfer" ) ;
667- expect ( approveBlueprint . network ) . toBe ( Networks . BSC ) ;
668- expect ( swapBlueprint . network ) . toBe ( Networks . BSC ) ;
717+ expect ( approveBlueprint . network ) . toBe ( source . network ) ;
718+ expect ( swapBlueprint . network ) . toBe ( source . network ) ;
669719 expect ( approveBlueprint . signer . toLowerCase ( ) ) . toBe ( userWallet . address . toLowerCase ( ) ) ;
670720 expect ( swapBlueprint . signer . toLowerCase ( ) ) . toBe ( userWallet . address . toLowerCase ( ) ) ;
671721
@@ -864,23 +914,26 @@ describe("Alfredpay currency corridors (USD/COP/ARS, on- and offramp)", () => {
864914 ) ;
865915 }
866916
867- for ( const currency of CROSS_CHAIN_OFFRAMP_CASES ) {
917+ for ( const { currency, source } of CROSS_CHAIN_OFFRAMP_TEST_CASES ) {
868918 it (
869- `${ currency . fiat } cross-chain offramp (USDT on BSC → squid → Polygon → ${ currency . rail } ) verifies the user's squid txs and completes` ,
919+ `${ currency . fiat } cross-chain offramp (USDT on ${ source . label } → squid → Polygon → ${ currency . rail } ) verifies the user's squid txs and completes` ,
870920 async ( ) => {
871921 const offrampOrdersBefore = world . alfredpay . offrampOrders . length ;
872- const setup = await setUpCrossChainOfframpRamp ( currency ) ;
922+ const setup = await setUpCrossChainOfframpRamp ( currency , source ) ;
873923
874- // Registration requested a BSC USDT → Polygon USDT route from
924+ // Registration requested a source-chain USDT → Polygon USDT route from
875925 // the user's wallet, delivering to the ephemeral.
876926 const registrationRoute = world . squidRouter . requestedRoutes . find (
877927 route =>
878- route . fromToken . toLowerCase ( ) === USDT_ON_BSC . toLowerCase ( ) &&
928+ route . fromToken . toLowerCase ( ) === source . token . toLowerCase ( ) &&
879929 route . toToken . toLowerCase ( ) === ALFREDPAY_ERC20_TOKEN . toLowerCase ( ) &&
880930 route . toAddress ?. toLowerCase ( ) === setup . ephemeralAddress . toLowerCase ( )
881931 ) ;
882- expect ( registrationRoute , "registration should request a BSC→Polygon USDT route to the ephemeral" ) . toBeDefined ( ) ;
883- expect ( registrationRoute ?. fromChain ) . toBe ( "56" ) ;
932+ expect (
933+ registrationRoute ,
934+ `registration should request a ${ source . label } →Polygon USDT route to the ephemeral`
935+ ) . toBeDefined ( ) ;
936+ expect ( registrationRoute ?. fromChain ) . toBe ( source . chainId ) ;
884937 expect ( registrationRoute ?. toChain ) . toBe ( "137" ) ;
885938 expect ( registrationRoute ?. fromAddress . toLowerCase ( ) ) . toBe ( setup . userWalletAddress . toLowerCase ( ) ) ;
886939
0 commit comments