@zkp2p/pay-shared 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,6 @@
1
+ Copyright (c) 2026 ZKP2P
2
+
3
+ All rights reserved.
4
+
5
+ This software and associated documentation files (the "Software") are proprietary and confidential.
6
+ Unauthorized copying, modification, distribution, sublicensing, or use of the Software, via any medium, is strictly prohibited without prior written permission from ZKP2P.
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # @zkp2p/pay-shared
2
+
3
+ Shared TypeScript types, enums, and chain utilities used by ZKP2P Pay API, SDK, and frontend apps.
4
+
5
+ - Package: `@zkp2p/pay-shared`
6
+ - Module format: ESM
7
+ - Contains runtime utilities and compile-time types
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @zkp2p/pay-shared@1.0.0
13
+ ```
14
+
15
+ ## Published artifacts
16
+
17
+ - Includes compiled ESM JavaScript and `.d.ts` type declarations.
18
+ - Does not publish declaration maps (`.d.ts.map`) or JavaScript source maps (`.js.map`).
19
+
20
+ ## What This Package Includes
21
+
22
+ - Checkout API types (`CreateOrderRequest`, `CheckoutOrder`, `CheckoutPayment`, `CheckoutAggregate`, etc.)
23
+ - Canonical constants (`PaymentPlatform`, `FeePayer`, `CheckoutOrderStatus`, `CheckoutPaymentStatus`, `OrderErrorCode`)
24
+ - Merchant model types and environment constants (`Merchant`, `MerchantEnvironment`)
25
+ - Central chain/token helpers for supported destination chains and token aliases
26
+
27
+ ## Usage
28
+
29
+ ### Shared API Types
30
+
31
+ ```ts
32
+ import type { CreateOrderRequest, CheckoutOrder } from '@zkp2p/pay-shared';
33
+
34
+ const request: CreateOrderRequest = {
35
+ requestedUsdcAmount: '25.00',
36
+ destinationChainId: 8453,
37
+ destinationToken: 'USDC',
38
+ destinationAddress: '0xYourRecipientAddress',
39
+ };
40
+
41
+ function readOrder(order: CheckoutOrder) {
42
+ console.log(order.status, order.requestedUsdcAmount, order.remainingUsdcAmount);
43
+ }
44
+ ```
45
+
46
+ ### Constants and Enums
47
+
48
+ ```ts
49
+ import { FeePayer, PaymentPlatform, CheckoutOrderStatus } from '@zkp2p/pay-shared';
50
+
51
+ console.log(FeePayer.MERCHANT); // "MERCHANT"
52
+ console.log(PaymentPlatform.VENMO); // "venmo"
53
+ console.log(CheckoutOrderStatus.CREATED); // "CREATED"
54
+ ```
55
+
56
+ ### Chain and Token Utilities
57
+
58
+ ```ts
59
+ import {
60
+ BASE_CHAIN_ID,
61
+ getSupportedChainIds,
62
+ parseSupportedChainSelection,
63
+ resolveDestinationTokenAddress,
64
+ getSupportedDestinationTokenAliasesForChain,
65
+ } from '@zkp2p/pay-shared';
66
+
67
+ const chainId = parseSupportedChainSelection('polygon'); // 137
68
+ const usdc = resolveDestinationTokenAddress('USDC', 137); // Chain-specific USDC address
69
+ const supportedAliases = getSupportedDestinationTokenAliasesForChain(BASE_CHAIN_ID); // ["USDC"]
70
+
71
+ console.log(getSupportedChainIds(), chainId, usdc, supportedAliases);
72
+ ```
73
+
74
+ ## Key Exports
75
+
76
+ Core type exports:
77
+
78
+ - `CreateOrderRequest`
79
+ - `CreateOrderResponse`
80
+ - `CreatePaymentRequest`
81
+ - `CheckoutOrder`
82
+ - `CheckoutPayment`
83
+ - `CheckoutAggregate`
84
+ - `CheckoutQuotes`
85
+ - `MerchantProfile`
86
+
87
+ Core constants:
88
+
89
+ - `PaymentPlatform`
90
+ - `FeePayer`
91
+ - `CheckoutOrderStatus`
92
+ - `CheckoutPaymentStatus`
93
+ - `OrderStatus`
94
+ - `ProofAttemptStatus`
95
+ - `OrderErrorCode`
96
+ - `MerchantEnvironment`
97
+
98
+ Chain constants and helpers:
99
+
100
+ - `BASE_CHAIN_ID`
101
+ - `HYPEREVM_CHAIN_ID`
102
+ - `SOLANA_CHAIN_ID`
103
+ - `SUPPORTED_DESTINATION_TOKEN_ALIASES`
104
+ - `parseSupportedChainSelection(...)`
105
+ - `resolveDestinationTokenAddress(...)`
106
+ - `getChainConfig(...)`
107
+ - `getSupportedChainIds(...)`
108
+ - `getDestinationChainIds(...)`
109
+ - `getEvmChainIds(...)`
110
+ - `getNonEvmChainIds(...)`
111
+
112
+ ## Notes
113
+
114
+ - Amount fields are strings to preserve precision across APIs and clients.
115
+ - Canonical order/payment amounts are available on `CheckoutOrder` and `CheckoutPayment` (for example `requestedUsdcAmount`, `remainingUsdcAmount`, `netSettledUsdcAmount`).
116
+ - This package is ESM-only.
@@ -0,0 +1 @@
1
+ export declare function isValidBitcoinAddress(value: string): boolean;
@@ -0,0 +1,13 @@
1
+ const BITCOIN_BASE58_ADDRESS_REGEX = /^[13][1-9A-HJ-NP-Za-km-z]{25,34}$/;
2
+ const BITCOIN_BECH32_ADDRESS_REGEX = /^(bc1)[ac-hj-np-z02-9]{11,71}$/i;
3
+ export function isValidBitcoinAddress(value) {
4
+ const trimmed = value.trim();
5
+ if (!trimmed) {
6
+ return false;
7
+ }
8
+ if (trimmed.toLowerCase().startsWith('bc1')) {
9
+ const isUniformCase = trimmed === trimmed.toLowerCase() || trimmed === trimmed.toUpperCase();
10
+ return isUniformCase && BITCOIN_BECH32_ADDRESS_REGEX.test(trimmed);
11
+ }
12
+ return BITCOIN_BASE58_ADDRESS_REGEX.test(trimmed);
13
+ }
package/dist/chains.d.ts CHANGED
@@ -6,15 +6,14 @@
6
6
  */
7
7
  export declare const BASE_CHAIN_ID = 8453;
8
8
  export declare const HYPEREVM_CHAIN_ID = 999;
9
- export declare const SOLANA_CHAIN_ID = 34268394551451;
9
+ export declare const SOLANA_CHAIN_ID = 792703809;
10
10
  export declare const SUPPORTED_DESTINATION_TOKEN_ALIASES: readonly ["USDC", "USDT"];
11
11
  export type DestinationTokenAlias = (typeof SUPPORTED_DESTINATION_TOKEN_ALIASES)[number];
12
12
  export declare const DEFAULT_DESTINATION_TOKEN_ALIAS: DestinationTokenAlias;
13
13
  /**
14
14
  * Chain configuration interface.
15
15
  *
16
- * Note: We don't store spokePoolAddress for each chain because bridging
17
- * always originates from Base, and the hook contract handles the Base SpokePool.
16
+ * Bridging always originates from Base settlement and is routed through Relay.
18
17
  */
19
18
  export interface ChainConfig {
20
19
  chainId: number;
@@ -76,6 +75,21 @@ export declare function getUsdcAddress(chainId: number): string | undefined;
76
75
  * - fallback: return token string as provided (for explicit token addresses)
77
76
  */
78
77
  export declare function resolveDestinationTokenAddress(destinationToken: string, destinationChainId: number): string | null;
78
+ /**
79
+ * Check whether the final payout destination is native Base USDC.
80
+ * Any other token or chain requires a Relay / Privy payout conversion step.
81
+ */
82
+ export declare function isBaseUsdcDestination(destinationChainId: number | bigint | null | undefined, destinationToken: string | null | undefined): boolean;
83
+ /**
84
+ * Determine whether a payout needs Relay / Privy after Base settlement.
85
+ * This is true for every destination except native Base USDC.
86
+ */
87
+ export declare function requiresRelayPayout(destinationChainId: number | bigint | null | undefined, destinationToken: string | null | undefined): boolean;
88
+ /**
89
+ * Resolve a destination token value into its canonical symbol for display.
90
+ * Known aliases and configured chain token addresses map to USDC/USDT.
91
+ */
92
+ export declare function resolveDestinationTokenSymbol(destinationToken: string | null | undefined, destinationChainId?: number | bigint | null): string;
79
93
  /**
80
94
  * Get supported destination token aliases for a destination chain.
81
95
  * Token support is derived from resolvable token addresses for the chain.
@@ -134,4 +148,3 @@ export declare const DESTINATION_CHAINS: {
134
148
  * Mapping of chain ID to name for backward compatibility.
135
149
  */
136
150
  export declare const SupportedChainsMap: Record<number, string>;
137
- //# sourceMappingURL=chains.d.ts.map
package/dist/chains.js CHANGED
@@ -7,7 +7,7 @@
7
7
  // Chain IDs
8
8
  export const BASE_CHAIN_ID = 8453;
9
9
  export const HYPEREVM_CHAIN_ID = 999;
10
- export const SOLANA_CHAIN_ID = 34268394551451;
10
+ export const SOLANA_CHAIN_ID = 792703809;
11
11
  export const SUPPORTED_DESTINATION_TOKEN_ALIASES = ['USDC', 'USDT'];
12
12
  export const DEFAULT_DESTINATION_TOKEN_ALIAS = 'USDC';
13
13
  // Mainnet chain configurations
@@ -120,8 +120,8 @@ const CHAIN_SELECTION_ALIASES = {
120
120
  hyperliquid: 999,
121
121
  hyperevm: 999,
122
122
  hl: 999,
123
- solana: 34268394551451,
124
- sol: 34268394551451,
123
+ solana: 792703809,
124
+ sol: 792703809,
125
125
  };
126
126
  for (const chainId of SUPPORTED_CHAIN_IDS) {
127
127
  const chainConfig = MAINNET_CHAINS[chainId];
@@ -265,6 +265,63 @@ export function resolveDestinationTokenAddress(destinationToken, destinationChai
265
265
  }
266
266
  return token;
267
267
  }
268
+ /**
269
+ * Check whether the final payout destination is native Base USDC.
270
+ * Any other token or chain requires a Relay / Privy payout conversion step.
271
+ */
272
+ export function isBaseUsdcDestination(destinationChainId, destinationToken) {
273
+ if (destinationChainId === null || destinationChainId === undefined) {
274
+ return false;
275
+ }
276
+ const chainId = Number(destinationChainId);
277
+ const token = destinationToken?.trim();
278
+ if (!token) {
279
+ return false;
280
+ }
281
+ if (chainId !== BASE_CHAIN_ID) {
282
+ return false;
283
+ }
284
+ const resolvedTokenAddress = resolveDestinationTokenAddress(token, chainId);
285
+ const baseUsdcAddress = getUsdcAddress(BASE_CHAIN_ID);
286
+ return Boolean(resolvedTokenAddress &&
287
+ baseUsdcAddress &&
288
+ resolvedTokenAddress.toLowerCase() === baseUsdcAddress.toLowerCase());
289
+ }
290
+ /**
291
+ * Determine whether a payout needs Relay / Privy after Base settlement.
292
+ * This is true for every destination except native Base USDC.
293
+ */
294
+ export function requiresRelayPayout(destinationChainId, destinationToken) {
295
+ return !isBaseUsdcDestination(destinationChainId, destinationToken);
296
+ }
297
+ /**
298
+ * Resolve a destination token value into its canonical symbol for display.
299
+ * Known aliases and configured chain token addresses map to USDC/USDT.
300
+ */
301
+ export function resolveDestinationTokenSymbol(destinationToken, destinationChainId) {
302
+ const token = destinationToken?.trim();
303
+ if (!token) {
304
+ return DEFAULT_DESTINATION_TOKEN_ALIAS;
305
+ }
306
+ const tokenAlias = normalizeDestinationTokenAlias(token);
307
+ if (tokenAlias) {
308
+ return tokenAlias;
309
+ }
310
+ const chainId = destinationChainId === null || destinationChainId === undefined
311
+ ? null
312
+ : Number(destinationChainId);
313
+ if (chainId !== null) {
314
+ const usdcAddress = getUsdcAddress(chainId);
315
+ if (usdcAddress && usdcAddress.toLowerCase() === token.toLowerCase()) {
316
+ return 'USDC';
317
+ }
318
+ const usdtAddress = DESTINATION_TOKEN_ADDRESSES[chainId]?.usdt;
319
+ if (usdtAddress && usdtAddress.toLowerCase() === token.toLowerCase()) {
320
+ return 'USDT';
321
+ }
322
+ }
323
+ return token.toUpperCase();
324
+ }
268
325
  /**
269
326
  * Get supported destination token aliases for a destination chain.
270
327
  * Token support is derived from resolvable token addresses for the chain.
@@ -0,0 +1,34 @@
1
+ export declare const BITCOIN_CHAIN_ID = 8253038;
2
+ export declare const TRON_CHAIN_ID = 728126428;
3
+ export declare const PAY_CRYPTO_TOKEN_SYMBOLS: readonly ["BTC", "USDC", "USDT", "ETH", "PYUSD", "SOL", "BNB", "HYPE", "WBTC", "USDH"];
4
+ export type PayCryptoTokenSymbol = (typeof PAY_CRYPTO_TOKEN_SYMBOLS)[number];
5
+ export declare const DEFAULT_ENABLED_PAY_CRYPTO_TOKENS: PayCryptoTokenSymbol[];
6
+ export declare const DEFAULT_ENABLED_DESTINATION_TOKENS: PayCryptoTokenSymbol[];
7
+ export declare const STABLECOIN_SYMBOLS: Set<"USDC" | "USDT" | "ETH" | "BNB" | "SOL" | "BTC" | "PYUSD" | "HYPE" | "WBTC" | "USDH">;
8
+ export interface SupportedCryptoTokenConfig {
9
+ chainId: number;
10
+ chainName: string;
11
+ chainShortName: string;
12
+ symbol: PayCryptoTokenSymbol;
13
+ address: string;
14
+ decimals: number;
15
+ isNative: boolean;
16
+ }
17
+ export declare function normalizePayCryptoTokenSymbol(value: string | null | undefined): PayCryptoTokenSymbol | null;
18
+ export declare function isStablecoinSymbol(symbol: string | null | undefined): boolean;
19
+ export declare function getSupportedPayCryptoTokenConfigsForChain(chainId: number, enabledSymbols?: readonly string[] | null): SupportedCryptoTokenConfig[];
20
+ export declare function getSupportedPayCryptoChainIds(enabledSymbols?: readonly string[] | null): number[];
21
+ export declare function resolvePayCryptoTokenConfig(chainId: number, symbol: string | null | undefined): SupportedCryptoTokenConfig | null;
22
+ /**
23
+ * Reverse lookup of a token config by contract address on a specific chain.
24
+ * Address comparison is case-insensitive. Returns null if the chain is unknown
25
+ * or if no token at that address is registered for the chain.
26
+ *
27
+ * Used by the crypto fulfillment resolver to translate a Relay request's inTx
28
+ * tokenAddress (lowercased, chain-qualified) into a human-readable symbol and
29
+ * decimals, so payment.currency and payment.paymentAmount can be written
30
+ * correctly for whatever token the customer actually deposited.
31
+ */
32
+ export declare function resolvePayCryptoTokenConfigByAddress(chainId: number, address: string | null | undefined): SupportedCryptoTokenConfig | null;
33
+ export declare function getSupportedDestinationBalanceTokenConfigsForChain(chainId: number, enabledSymbols?: readonly string[] | null): SupportedCryptoTokenConfig[];
34
+ export declare function resolveDestinationBalanceTokenConfig(chainId: number, symbol: string | null | undefined): SupportedCryptoTokenConfig | null;
package/dist/crypto.js ADDED
@@ -0,0 +1,226 @@
1
+ import { MAINNET_CHAINS, } from './chains.js';
2
+ export const BITCOIN_CHAIN_ID = 8253038;
3
+ export const TRON_CHAIN_ID = 728126428;
4
+ export const PAY_CRYPTO_TOKEN_SYMBOLS = [
5
+ 'BTC', // Kept in symbols for DB compatibility with existing sessions
6
+ 'USDC',
7
+ 'USDT',
8
+ 'ETH',
9
+ 'PYUSD',
10
+ 'SOL',
11
+ 'BNB',
12
+ 'HYPE',
13
+ 'WBTC',
14
+ 'USDH',
15
+ ];
16
+ export const DEFAULT_ENABLED_PAY_CRYPTO_TOKENS = [
17
+ 'BTC',
18
+ 'USDC',
19
+ 'USDT',
20
+ 'ETH',
21
+ 'PYUSD',
22
+ 'SOL',
23
+ 'BNB',
24
+ 'HYPE',
25
+ 'WBTC',
26
+ 'USDH',
27
+ ];
28
+ export const DEFAULT_ENABLED_DESTINATION_TOKENS = [
29
+ 'USDC',
30
+ 'USDT',
31
+ ];
32
+ export const STABLECOIN_SYMBOLS = new Set([
33
+ 'USDC',
34
+ 'USDT',
35
+ 'PYUSD',
36
+ 'USDH',
37
+ ]);
38
+ const NATIVE_ETH_ADDRESS = '0x0000000000000000000000000000000000000000';
39
+ const NATIVE_SOL_ADDRESS = '11111111111111111111111111111111';
40
+ const NATIVE_BTC_ADDRESS = 'bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8';
41
+ const PAY_CRYPTO_CHAIN_CONFIGS = {
42
+ ...MAINNET_CHAINS,
43
+ [BITCOIN_CHAIN_ID]: {
44
+ chainId: BITCOIN_CHAIN_ID,
45
+ name: 'Bitcoin',
46
+ shortName: 'BTC',
47
+ },
48
+ [TRON_CHAIN_ID]: {
49
+ chainId: TRON_CHAIN_ID,
50
+ name: 'Tron',
51
+ shortName: 'TRON',
52
+ },
53
+ };
54
+ const CHAIN_TOKEN_CONFIGS = {
55
+ [BITCOIN_CHAIN_ID]: {
56
+ BTC: { address: NATIVE_BTC_ADDRESS, decimals: 8, isNative: true },
57
+ },
58
+ 1: {
59
+ ETH: { address: NATIVE_ETH_ADDRESS, decimals: 18, isNative: true },
60
+ USDC: { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', decimals: 6, isNative: false },
61
+ USDT: { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', decimals: 6, isNative: false },
62
+ PYUSD: { address: '0x6c3ea9036406852006290770bedfcaba0e23a0e8', decimals: 6, isNative: false },
63
+ WBTC: { address: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', decimals: 8, isNative: false },
64
+ },
65
+ 10: {
66
+ ETH: { address: NATIVE_ETH_ADDRESS, decimals: 18, isNative: true },
67
+ USDC: { address: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', decimals: 6, isNative: false },
68
+ USDT: { address: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', decimals: 6, isNative: false },
69
+ },
70
+ 56: {
71
+ BNB: { address: NATIVE_ETH_ADDRESS, decimals: 18, isNative: true },
72
+ USDC: { address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', decimals: 18, isNative: false },
73
+ USDT: { address: '0x55d398326f99059fF775485246999027B3197955', decimals: 18, isNative: false },
74
+ WBTC: { address: '0x0555e30da8f98308edb960aa94c0db47230d2b9c', decimals: 8, isNative: false },
75
+ },
76
+ 137: {
77
+ USDC: { address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359', decimals: 6, isNative: false },
78
+ USDT: { address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', decimals: 6, isNative: false },
79
+ WBTC: { address: '0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6', decimals: 8, isNative: false },
80
+ },
81
+ 480: {
82
+ ETH: { address: NATIVE_ETH_ADDRESS, decimals: 18, isNative: true },
83
+ USDC: { address: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1', decimals: 6, isNative: false },
84
+ },
85
+ 999: {
86
+ HYPE: { address: NATIVE_ETH_ADDRESS, decimals: 18, isNative: true },
87
+ USDC: { address: '0xb88339CB7199b77E23DB6E890353E22632Ba630f', decimals: 6, isNative: false },
88
+ USDH: { address: '0x111111a1a0667d36bd57c0a9f569b98057111111', decimals: 6, isNative: false },
89
+ },
90
+ 8453: {
91
+ ETH: { address: NATIVE_ETH_ADDRESS, decimals: 18, isNative: true },
92
+ USDC: { address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', decimals: 6, isNative: false },
93
+ USDT: { address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2', decimals: 6, isNative: false },
94
+ SOL: { address: '0x311935cd80b76769bf2ecc9d8ab7635b2139cf82', decimals: 9, isNative: false },
95
+ WBTC: { address: '0x0555e30da8f98308edb960aa94c0db47230d2b9c', decimals: 8, isNative: false },
96
+ },
97
+ 42161: {
98
+ ETH: { address: NATIVE_ETH_ADDRESS, decimals: 18, isNative: true },
99
+ USDC: { address: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', decimals: 6, isNative: false },
100
+ USDT: { address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', decimals: 6, isNative: false },
101
+ WBTC: { address: '0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f', decimals: 8, isNative: false },
102
+ },
103
+ [TRON_CHAIN_ID]: {
104
+ USDT: { address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', decimals: 6, isNative: false },
105
+ },
106
+ 792703809: {
107
+ SOL: { address: NATIVE_SOL_ADDRESS, decimals: 9, isNative: true },
108
+ USDC: { address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', decimals: 6, isNative: false },
109
+ USDT: { address: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', decimals: 6, isNative: false },
110
+ PYUSD: { address: '2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo', decimals: 6, isNative: false },
111
+ },
112
+ };
113
+ function isPayCryptoTokenSymbol(value) {
114
+ return PAY_CRYPTO_TOKEN_SYMBOLS.includes(value);
115
+ }
116
+ export function normalizePayCryptoTokenSymbol(value) {
117
+ const normalized = value?.trim().toUpperCase();
118
+ if (!normalized) {
119
+ return null;
120
+ }
121
+ return isPayCryptoTokenSymbol(normalized) ? normalized : null;
122
+ }
123
+ export function isStablecoinSymbol(symbol) {
124
+ const normalizedSymbol = normalizePayCryptoTokenSymbol(symbol);
125
+ return Boolean(normalizedSymbol && STABLECOIN_SYMBOLS.has(normalizedSymbol));
126
+ }
127
+ function normalizeEnabledSymbols(enabledSymbols, fallback) {
128
+ const normalized = (enabledSymbols ?? [])
129
+ .map((value) => normalizePayCryptoTokenSymbol(value))
130
+ .filter((value) => value !== null);
131
+ return normalized.length > 0 ? normalized : [...fallback];
132
+ }
133
+ function buildSupportedCryptoTokenConfig(chain, symbol) {
134
+ const config = CHAIN_TOKEN_CONFIGS[chain.chainId]?.[symbol];
135
+ if (!config) {
136
+ return null;
137
+ }
138
+ return {
139
+ chainId: chain.chainId,
140
+ chainName: chain.name,
141
+ chainShortName: chain.shortName,
142
+ symbol,
143
+ address: config.address,
144
+ decimals: config.decimals,
145
+ isNative: config.isNative,
146
+ };
147
+ }
148
+ export function getSupportedPayCryptoTokenConfigsForChain(chainId, enabledSymbols) {
149
+ const chain = PAY_CRYPTO_CHAIN_CONFIGS[chainId];
150
+ if (!chain) {
151
+ return [];
152
+ }
153
+ const allowedSymbols = normalizeEnabledSymbols(enabledSymbols, DEFAULT_ENABLED_PAY_CRYPTO_TOKENS);
154
+ return allowedSymbols
155
+ .map((symbol) => buildSupportedCryptoTokenConfig(chain, symbol))
156
+ .filter((value) => value !== null);
157
+ }
158
+ export function getSupportedPayCryptoChainIds(enabledSymbols) {
159
+ return Object.keys(PAY_CRYPTO_CHAIN_CONFIGS)
160
+ .map(Number)
161
+ .filter((chainId) => getSupportedPayCryptoTokenConfigsForChain(chainId, enabledSymbols).length > 0);
162
+ }
163
+ export function resolvePayCryptoTokenConfig(chainId, symbol) {
164
+ const normalizedSymbol = normalizePayCryptoTokenSymbol(symbol);
165
+ if (!normalizedSymbol) {
166
+ return null;
167
+ }
168
+ const chain = PAY_CRYPTO_CHAIN_CONFIGS[chainId];
169
+ if (!chain) {
170
+ return null;
171
+ }
172
+ return buildSupportedCryptoTokenConfig(chain, normalizedSymbol);
173
+ }
174
+ /**
175
+ * Reverse lookup of a token config by contract address on a specific chain.
176
+ * Address comparison is case-insensitive. Returns null if the chain is unknown
177
+ * or if no token at that address is registered for the chain.
178
+ *
179
+ * Used by the crypto fulfillment resolver to translate a Relay request's inTx
180
+ * tokenAddress (lowercased, chain-qualified) into a human-readable symbol and
181
+ * decimals, so payment.currency and payment.paymentAmount can be written
182
+ * correctly for whatever token the customer actually deposited.
183
+ */
184
+ export function resolvePayCryptoTokenConfigByAddress(chainId, address) {
185
+ if (typeof address !== 'string')
186
+ return null;
187
+ const needle = address.trim().toLowerCase();
188
+ if (needle === '')
189
+ return null;
190
+ const chainTokens = CHAIN_TOKEN_CONFIGS[chainId];
191
+ if (chainTokens === undefined)
192
+ return null;
193
+ const chain = PAY_CRYPTO_CHAIN_CONFIGS[chainId];
194
+ if (chain === undefined)
195
+ return null;
196
+ for (const symbolKey of Object.keys(chainTokens)) {
197
+ const cfg = chainTokens[symbolKey];
198
+ if (cfg === undefined)
199
+ continue;
200
+ if (cfg.address.toLowerCase() === needle) {
201
+ return {
202
+ chainId: chain.chainId,
203
+ chainName: chain.name,
204
+ chainShortName: chain.shortName,
205
+ symbol: symbolKey,
206
+ address: cfg.address,
207
+ decimals: cfg.decimals,
208
+ isNative: cfg.isNative,
209
+ };
210
+ }
211
+ }
212
+ return null;
213
+ }
214
+ export function getSupportedDestinationBalanceTokenConfigsForChain(chainId, enabledSymbols) {
215
+ const chain = MAINNET_CHAINS[chainId];
216
+ if (!chain) {
217
+ return [];
218
+ }
219
+ const allowedSymbols = normalizeEnabledSymbols(enabledSymbols, DEFAULT_ENABLED_DESTINATION_TOKENS);
220
+ return allowedSymbols
221
+ .map((symbol) => buildSupportedCryptoTokenConfig(chain, symbol))
222
+ .filter((value) => value !== null);
223
+ }
224
+ export function resolveDestinationBalanceTokenConfig(chainId, symbol) {
225
+ return resolvePayCryptoTokenConfig(chainId, symbol);
226
+ }
package/dist/fees.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { FeeTranche, MaxFeeConfig, ReferralFeeConfig } from './types.js';
2
+ declare const TRANCHE_SCALE_BY_CURRENCY: {
3
+ readonly USD: 2;
4
+ readonly USDC: 2;
5
+ };
6
+ type TrancheCurrency = keyof typeof TRANCHE_SCALE_BY_CURRENCY;
7
+ export type FeeSource = 'default' | 'merchant' | 'exempt';
8
+ export declare function parseBoundaryUnits(raw: number, currency: TrancheCurrency): bigint;
9
+ export declare function parseLookupUnits(raw: string, currency: TrancheCurrency): bigint;
10
+ export declare function parseUsdcUnits(raw: string): bigint;
11
+ export declare function formatUsdcUnits(units: bigint): string;
12
+ export declare function calculateGrossFromNetUnits(netAmountUnits: bigint, feeBps: number): bigint;
13
+ export declare function validateTranches(tranches: FeeTranche[], currency: TrancheCurrency): void;
14
+ export declare function getMatchingTrancheIndex(tranches: FeeTranche[], amount: string, currency: TrancheCurrency): number;
15
+ export declare function resolveReferralFeeConfig(config: ReferralFeeConfig, amountUsdc: string, options?: {
16
+ defaultFeeBps?: number;
17
+ }): {
18
+ feeSource: FeeSource;
19
+ referralFeeBps: number;
20
+ };
21
+ export declare function resolveExactTokenGrossAmountUsdc(config: ReferralFeeConfig, requestedNetAmountUsdc: string, options?: {
22
+ defaultFeeBps?: number;
23
+ }): string;
24
+ export declare function resolveMaxFeeConfig(config: MaxFeeConfig, amountUsd: string): {
25
+ maxFeePercentage: number;
26
+ };
27
+ export {};