@atxp/polygon 0.10.2 → 0.10.4

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.
@@ -0,0 +1,21 @@
1
+ const USDC_CONTRACT_ADDRESS_POLYGON_MAINNET = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"; // Native USDC on Polygon mainnet
2
+ const USDC_CONTRACT_ADDRESS_POLYGON_AMOY = "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582"; // USDC on Polygon Amoy testnet
3
+ /**
4
+ * Get USDC contract address for Polygon by chain ID
5
+ * @param chainId - Chain ID (137 for mainnet, 80002 for Amoy testnet)
6
+ * @returns USDC contract address
7
+ * @throws Error if chain ID is not supported
8
+ */
9
+ const getPolygonUSDCAddress = (chainId) => {
10
+ switch (chainId) {
11
+ case 137:
12
+ return USDC_CONTRACT_ADDRESS_POLYGON_MAINNET;
13
+ case 80002:
14
+ return USDC_CONTRACT_ADDRESS_POLYGON_AMOY;
15
+ default:
16
+ throw new Error(`Unsupported Polygon Chain ID: ${chainId}. Supported chains: 137 (mainnet), 80002 (Amoy testnet)`);
17
+ }
18
+ };
19
+
20
+ export { USDC_CONTRACT_ADDRESS_POLYGON_AMOY, USDC_CONTRACT_ADDRESS_POLYGON_MAINNET, getPolygonUSDCAddress };
21
+ //# sourceMappingURL=polygonConstants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygonConstants.js","sources":["../../../../atxp-client/dist/polygonConstants.js"],"sourcesContent":["const USDC_CONTRACT_ADDRESS_POLYGON_MAINNET = \"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359\"; // Native USDC on Polygon mainnet\nconst USDC_CONTRACT_ADDRESS_POLYGON_AMOY = \"0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582\"; // USDC on Polygon Amoy testnet\n// Polygon Mainnet (Chain ID: 137)\n// Note: Native currency upgraded from MATIC to POL on September 4, 2024\nconst POLYGON_MAINNET = {\n id: 137,\n name: 'Polygon',\n nativeCurrency: { name: 'POL', symbol: 'POL', decimals: 18 },\n rpcUrls: {\n default: { http: ['https://polygon-rpc.com'] }\n },\n blockExplorers: {\n default: { name: 'PolygonScan', url: 'https://polygonscan.com' }\n }\n};\n// Polygon Amoy Testnet (Chain ID: 80002)\n// Note: Amoy testnet also uses POL as native currency (following mainnet upgrade)\nconst POLYGON_AMOY = {\n id: 80002,\n name: 'Polygon Amoy',\n nativeCurrency: { name: 'POL', symbol: 'POL', decimals: 18 },\n rpcUrls: {\n default: { http: ['https://rpc-amoy.polygon.technology'] }\n },\n blockExplorers: {\n default: { name: 'PolygonScan Amoy', url: 'https://amoy.polygonscan.com' }\n },\n testnet: true\n};\n/**\n * Get Polygon Mainnet configuration with custom RPC URL (e.g., with API key)\n * @param rpcUrl - Custom RPC URL, e.g., 'https://polygon-mainnet.g.alchemy.com/v2/YOUR_API_KEY'\n */\nconst getPolygonMainnetWithRPC = (rpcUrl) => ({\n ...POLYGON_MAINNET,\n rpcUrls: {\n default: { http: [rpcUrl] }\n }\n});\n/**\n * Get Polygon Amoy Testnet configuration with custom RPC URL (e.g., with API key)\n * @param rpcUrl - Custom RPC URL, e.g., 'https://polygon-amoy.g.alchemy.com/v2/YOUR_API_KEY'\n */\nconst getPolygonAmoyWithRPC = (rpcUrl) => ({\n ...POLYGON_AMOY,\n rpcUrls: {\n default: { http: [rpcUrl] }\n }\n});\n/**\n * Get Polygon Chain configuration by chain ID\n * @param chainId - Chain ID (137 for mainnet, 80002 for Amoy testnet)\n * @returns Polygon Chain configuration\n * @throws Error if chain ID is not supported\n */\nconst getPolygonByChainId = (chainId) => {\n switch (chainId) {\n case 137:\n return POLYGON_MAINNET;\n case 80002:\n return POLYGON_AMOY;\n default:\n throw new Error(`Unsupported Polygon Chain ID: ${chainId}. Supported chains: 137 (mainnet), 80002 (Amoy testnet)`);\n }\n};\n/**\n * Get USDC contract address for Polygon by chain ID\n * @param chainId - Chain ID (137 for mainnet, 80002 for Amoy testnet)\n * @returns USDC contract address\n * @throws Error if chain ID is not supported\n */\nconst getPolygonUSDCAddress = (chainId) => {\n switch (chainId) {\n case 137:\n return USDC_CONTRACT_ADDRESS_POLYGON_MAINNET;\n case 80002:\n return USDC_CONTRACT_ADDRESS_POLYGON_AMOY;\n default:\n throw new Error(`Unsupported Polygon Chain ID: ${chainId}. Supported chains: 137 (mainnet), 80002 (Amoy testnet)`);\n }\n};\n\nexport { POLYGON_AMOY, POLYGON_MAINNET, USDC_CONTRACT_ADDRESS_POLYGON_AMOY, USDC_CONTRACT_ADDRESS_POLYGON_MAINNET, getPolygonAmoyWithRPC, getPolygonByChainId, getPolygonMainnetWithRPC, getPolygonUSDCAddress };\n//# sourceMappingURL=polygonConstants.js.map\n"],"names":[],"mappings":"AAAK,MAAC,qCAAqC,GAAG,6CAA6C;AACtF,MAAC,kCAAkC,GAAG,6CAA6C;AAgExF;AACA;AACA;AACA;AACA;AACA;AACK,MAAC,qBAAqB,GAAG,CAAC,OAAO,KAAK;AAC3C,IAAI,QAAQ,OAAO;AACnB,QAAQ,KAAK,GAAG;AAChB,YAAY,OAAO,qCAAqC;AACxD,QAAQ,KAAK,KAAK;AAClB,YAAY,OAAO,kCAAkC;AACrD,QAAQ;AACR,YAAY,MAAM,IAAI,KAAK,CAAC,CAAC,8BAA8B,EAAE,OAAO,CAAC,uDAAuD,CAAC,CAAC;AAC9H;AACA;;;;"}
@@ -0,0 +1,19 @@
1
+ import { SpendPermission } from './types.js';
2
+ import { Hex } from '@atxp/client';
3
+ import { type ICache, JsonCache, BrowserCache, MemoryCache } from '@atxp/common';
4
+ /**
5
+ * Stored permission data structure
6
+ */
7
+ export interface Intermediary {
8
+ /** Ephemeral wallet private key */
9
+ privateKey: Hex;
10
+ /** Spend permission from Polygon */
11
+ permission: SpendPermission;
12
+ }
13
+ /**
14
+ * Type-safe cache wrapper for permission data
15
+ */
16
+ export declare class IntermediaryCache extends JsonCache<Intermediary> {
17
+ }
18
+ export { type ICache, BrowserCache, MemoryCache };
19
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,KAAK,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mCAAmC;IACnC,UAAU,EAAE,GAAG,CAAC;IAChB,oCAAoC;IACpC,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,SAAS,CAAC,YAAY,CAAC;CAAG;AAGjE,OAAO,EAAE,KAAK,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC"}
package/dist/cache.js ADDED
@@ -0,0 +1,11 @@
1
+ import { JsonCache } from '@atxp/common';
2
+ export { BrowserCache, MemoryCache } from '@atxp/common';
3
+
4
+ /**
5
+ * Type-safe cache wrapper for permission data
6
+ */
7
+ class IntermediaryCache extends JsonCache {
8
+ }
9
+
10
+ export { IntermediaryCache };
11
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sources":["../src/cache.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAcA;;AAEG;AACG,MAAO,iBAAkB,SAAQ,SAAuB,CAAA;AAAG;;;;"}
@@ -0,0 +1,18 @@
1
+ import { type Account, type Address, type Hex } from 'viem';
2
+ import { type BundlerClient, type SmartAccount } from 'viem/account-abstraction';
3
+ export interface EphemeralSmartWallet {
4
+ address: Address;
5
+ client: BundlerClient;
6
+ account: SmartAccount;
7
+ signer: Account;
8
+ }
9
+ /**
10
+ * Creates an ephemeral smart wallet with paymaster support
11
+ * @param privateKey - Private key for the wallet signer
12
+ * @param chainId - Chain ID (defaults to 137 for Polygon mainnet, or 80002 for Amoy testnet)
13
+ *
14
+ * NOTE: This implementation assumes Coinbase CDP supports Polygon.
15
+ * Verify support and correct endpoint URLs before using in production.
16
+ */
17
+ export declare function toEphemeralSmartWallet(privateKey: Hex, chainId?: number): Promise<EphemeralSmartWallet>;
18
+ //# sourceMappingURL=smartWalletHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smartWalletHelpers.d.ts","sourceRoot":"","sources":["../src/smartWalletHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,OAAO,EACZ,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AAId,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,0BAA0B,CAAC;AAiDlC,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,GAAG,EACf,OAAO,GAAE,MAAmB,GAC3B,OAAO,CAAC,oBAAoB,CAAC,CAqC/B"}
@@ -0,0 +1,93 @@
1
+ import { createPublicClient, http } from 'viem';
2
+ import { polygon, polygonAmoy } from 'viem/chains';
3
+ import { privateKeyToAccount } from 'viem/accounts';
4
+ import { toCoinbaseSmartAccount, createBundlerClient } from 'viem/account-abstraction';
5
+
6
+ // Coinbase CDP API Key
7
+ const COINBASE_API_KEY = 'snPdXqIzOGhRkGNJvEHM5bl9Hm3yRO3m';
8
+ /**
9
+ * Get Coinbase CDP Bundler URL for a given chain
10
+ * NOTE: Verify Coinbase CDP support for Polygon before using in production
11
+ */
12
+ function getCoinbaseBundlerUrl(chainId) {
13
+ switch (chainId) {
14
+ case 137: // Polygon mainnet
15
+ return 'https://api.developer.coinbase.com/rpc/v1/polygon-mainnet';
16
+ case 80002: // Polygon Amoy testnet
17
+ return 'https://api.developer.coinbase.com/rpc/v1/polygon-amoy';
18
+ default:
19
+ throw new Error(`Unsupported chain ID for Coinbase bundler: ${chainId}. Supported: 137 (mainnet), 80002 (Amoy testnet)`);
20
+ }
21
+ }
22
+ /**
23
+ * Get Coinbase CDP Paymaster URL for a given chain
24
+ * NOTE: Verify Coinbase CDP support for Polygon before using in production
25
+ */
26
+ function getCoinbasePaymasterUrl(chainId) {
27
+ switch (chainId) {
28
+ case 137: // Polygon mainnet
29
+ return 'https://api.developer.coinbase.com/rpc/v1/polygon-mainnet';
30
+ case 80002: // Polygon Amoy testnet
31
+ return 'https://api.developer.coinbase.com/rpc/v1/polygon-amoy';
32
+ default:
33
+ throw new Error(`Unsupported chain ID for Coinbase paymaster: ${chainId}. Supported: 137 (mainnet), 80002 (Amoy testnet)`);
34
+ }
35
+ }
36
+ /**
37
+ * Get Polygon chain configuration by chain ID
38
+ */
39
+ function getPolygonChain(chainId) {
40
+ switch (chainId) {
41
+ case 137:
42
+ return polygon;
43
+ case 80002:
44
+ return polygonAmoy;
45
+ default:
46
+ throw new Error(`Unsupported Polygon chain ID: ${chainId}. Supported: 137 (mainnet), 80002 (Amoy testnet)`);
47
+ }
48
+ }
49
+ /**
50
+ * Creates an ephemeral smart wallet with paymaster support
51
+ * @param privateKey - Private key for the wallet signer
52
+ * @param chainId - Chain ID (defaults to 137 for Polygon mainnet, or 80002 for Amoy testnet)
53
+ *
54
+ * NOTE: This implementation assumes Coinbase CDP supports Polygon.
55
+ * Verify support and correct endpoint URLs before using in production.
56
+ */
57
+ async function toEphemeralSmartWallet(privateKey, chainId = polygon.id) {
58
+ const apiKey = COINBASE_API_KEY;
59
+ const signer = privateKeyToAccount(privateKey);
60
+ const chain = getPolygonChain(chainId);
61
+ const bundlerUrl = getCoinbaseBundlerUrl(chainId);
62
+ const paymasterUrl = getCoinbasePaymasterUrl(chainId);
63
+ const publicClient = createPublicClient({
64
+ chain,
65
+ transport: http(`${bundlerUrl}/${apiKey}`)
66
+ });
67
+ // Create the Coinbase smart wallet
68
+ const account = await toCoinbaseSmartAccount({
69
+ client: publicClient,
70
+ owners: [signer],
71
+ version: '1'
72
+ });
73
+ // Create bundler client with paymaster support
74
+ const bundlerClient = createBundlerClient({
75
+ account,
76
+ client: publicClient,
77
+ transport: http(`${bundlerUrl}/${apiKey}`),
78
+ chain,
79
+ paymaster: true, // Enable paymaster sponsorship
80
+ paymasterContext: {
81
+ transport: http(`${paymasterUrl}/${apiKey}`)
82
+ }
83
+ });
84
+ return {
85
+ address: account.address,
86
+ client: bundlerClient,
87
+ account,
88
+ signer,
89
+ };
90
+ }
91
+
92
+ export { toEphemeralSmartWallet };
93
+ //# sourceMappingURL=smartWalletHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smartWalletHelpers.js","sources":["../src/smartWalletHelpers.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;AAiBA;AACA,MAAM,gBAAgB,GAAG,kCAAkC;AAE3D;;;AAGG;AACH,SAAS,qBAAqB,CAAC,OAAe,EAAA;IAC5C,QAAQ,OAAO;QACb,KAAK,GAAG;AACN,YAAA,OAAO,2DAA2D;QACpE,KAAK,KAAK;AACR,YAAA,OAAO,wDAAwD;AACjE,QAAA;AACE,YAAA,MAAM,IAAI,KAAK,CAAC,8CAA8C,OAAO,CAAA,gDAAA,CAAkD,CAAC;;AAE9H;AAEA;;;AAGG;AACH,SAAS,uBAAuB,CAAC,OAAe,EAAA;IAC9C,QAAQ,OAAO;QACb,KAAK,GAAG;AACN,YAAA,OAAO,2DAA2D;QACpE,KAAK,KAAK;AACR,YAAA,OAAO,wDAAwD;AACjE,QAAA;AACE,YAAA,MAAM,IAAI,KAAK,CAAC,gDAAgD,OAAO,CAAA,gDAAA,CAAkD,CAAC;;AAEhI;AAEA;;AAEG;AACH,SAAS,eAAe,CAAC,OAAe,EAAA;IACtC,QAAQ,OAAO;AACb,QAAA,KAAK,GAAG;AACN,YAAA,OAAO,OAAO;AAChB,QAAA,KAAK,KAAK;AACR,YAAA,OAAO,WAAW;AACpB,QAAA;AACE,YAAA,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,CAAA,gDAAA,CAAkD,CAAC;;AAEjH;AASA;;;;;;;AAOG;AACI,eAAe,sBAAsB,CAC1C,UAAe,EACf,OAAA,GAAkB,OAAO,CAAC,EAAE,EAAA;IAE5B,MAAM,MAAM,GAAG,gBAAgB;AAC/B,IAAA,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,CAAC;AAC9C,IAAA,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC;AACtC,IAAA,MAAM,UAAU,GAAG,qBAAqB,CAAC,OAAO,CAAC;AACjD,IAAA,MAAM,YAAY,GAAG,uBAAuB,CAAC,OAAO,CAAC;IAErD,MAAM,YAAY,GAAG,kBAAkB,CAAC;QACtC,KAAK;QACL,SAAS,EAAE,IAAI,CAAC,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,MAAM,EAAE;AAC1C,KAAA,CAAC;;AAGF,IAAA,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAAC;AAC3C,QAAA,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,CAAC,MAAM,CAAC;AAChB,QAAA,OAAO,EAAE;AACV,KAAA,CAAC;;IAGF,MAAM,aAAa,GAAG,mBAAmB,CAAC;QACxC,OAAO;AACP,QAAA,MAAM,EAAE,YAAY;QACpB,SAAS,EAAE,IAAI,CAAC,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,MAAM,EAAE,CAAC;QAC1C,KAAK;QACL,SAAS,EAAE,IAAI;AACf,QAAA,gBAAgB,EAAE;YAChB,SAAS,EAAE,IAAI,CAAC,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,MAAM,EAAE;AAC5C;AACF,KAAA,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;AACxB,QAAA,MAAM,EAAE,aAAa;QACrB,OAAO;QACP,MAAM;KACP;AACH;;;;"}
@@ -0,0 +1,29 @@
1
+ import { Logger, Currency, PaymentMaker, AccountId, PaymentIdentifier, Destination } from '@atxp/common';
2
+ import BigNumber from 'bignumber.js';
3
+ import { SpendPermission } from './types.js';
4
+ import { type EphemeralSmartWallet } from './smartWalletHelpers.js';
5
+ /**
6
+ * Browser-based payment maker using ephemeral smart wallets with account abstraction.
7
+ * Uses Coinbase CDP for gasless transactions and spend permissions.
8
+ */
9
+ export declare class SmartWalletPaymentMaker implements PaymentMaker {
10
+ private logger;
11
+ private spendPermission;
12
+ private smartWallet;
13
+ private chainId;
14
+ private usdcAddress;
15
+ constructor(spendPermission: SpendPermission, smartWallet: EphemeralSmartWallet, logger?: Logger, chainId?: number);
16
+ getSourceAddress(_params: {
17
+ amount: BigNumber;
18
+ currency: Currency;
19
+ receiver: string;
20
+ memo: string;
21
+ }): string;
22
+ generateJWT({ paymentRequestId, codeChallenge, accountId }: {
23
+ paymentRequestId: string;
24
+ codeChallenge: string;
25
+ accountId?: AccountId | null;
26
+ }): Promise<string>;
27
+ makePayment(destinations: Destination[], memo: string, _paymentRequestId?: string): Promise<PaymentIdentifier | null>;
28
+ }
29
+ //# sourceMappingURL=smartWalletPaymentMaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smartWalletPaymentMaker.d.ts","sourceRoot":"","sources":["../src/smartWalletPaymentMaker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAiB,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExH,OAAO,SAAS,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAiDpE;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,YAAY;IAC1D,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;gBAG1B,eAAe,EAAE,eAAe,EAChC,WAAW,EAAE,oBAAoB,EACjC,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE,MAAmB;IAe9B,gBAAgB,CAAC,OAAO,EAAE;QAAC,MAAM,EAAE,SAAS,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAIpG,WAAW,CAAC,EAAC,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAC,EAAE;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;KAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAqC3J,WAAW,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;CA6F5H"}
@@ -0,0 +1,172 @@
1
+ import { getPolygonUSDCAddress } from '@atxp/client';
2
+ import { polygon } from 'viem/chains';
3
+ import { ConsoleLogger, constructEIP1271Message, createEIP1271AuthData, createEIP1271JWT } from '@atxp/common';
4
+ import { encodeFunctionData, parseEther } from 'viem';
5
+ import { prepareSpendCallData } from './spendPermissionShim.js';
6
+
7
+ const USDC_DECIMALS = 6;
8
+ // Minimal ERC20 ABI for transfer function
9
+ const ERC20_ABI = [
10
+ {
11
+ inputs: [
12
+ { name: 'to', type: 'address' },
13
+ { name: 'amount', type: 'uint256' }
14
+ ],
15
+ name: 'transfer',
16
+ outputs: [{ name: '', type: 'bool' }],
17
+ stateMutability: 'nonpayable',
18
+ type: 'function'
19
+ }
20
+ ];
21
+ async function waitForTransactionConfirmations(smartWallet, txHash, confirmations, logger) {
22
+ try {
23
+ const publicClient = smartWallet.client.account?.client;
24
+ if (publicClient && 'waitForTransactionReceipt' in publicClient) {
25
+ logger.info(`Waiting for ${confirmations} confirmations...`);
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ await publicClient.waitForTransactionReceipt({
28
+ hash: txHash,
29
+ confirmations: confirmations
30
+ });
31
+ logger.info(`Transaction confirmed with ${confirmations} confirmations`);
32
+ }
33
+ else {
34
+ logger.warn('Unable to wait for confirmations: client does not support waitForTransactionReceipt');
35
+ }
36
+ }
37
+ catch (error) {
38
+ logger.warn(`Could not wait for additional confirmations: ${error}`);
39
+ // Continue anyway - the transaction is already mined
40
+ }
41
+ }
42
+ /**
43
+ * Browser-based payment maker using ephemeral smart wallets with account abstraction.
44
+ * Uses Coinbase CDP for gasless transactions and spend permissions.
45
+ */
46
+ class SmartWalletPaymentMaker {
47
+ constructor(spendPermission, smartWallet, logger, chainId = polygon.id) {
48
+ if (!spendPermission) {
49
+ throw new Error('Spend permission is required');
50
+ }
51
+ if (!smartWallet) {
52
+ throw new Error('Smart wallet is required');
53
+ }
54
+ this.logger = logger ?? new ConsoleLogger();
55
+ this.spendPermission = spendPermission;
56
+ this.smartWallet = smartWallet;
57
+ this.chainId = chainId;
58
+ this.usdcAddress = getPolygonUSDCAddress(chainId);
59
+ }
60
+ getSourceAddress(_params) {
61
+ return this.smartWallet.account.address;
62
+ }
63
+ async generateJWT({ paymentRequestId, codeChallenge, accountId }) {
64
+ // Generate EIP-1271 auth data for smart wallet authentication
65
+ const timestamp = Math.floor(Date.now() / 1000);
66
+ const message = constructEIP1271Message({
67
+ walletAddress: this.smartWallet.account.address,
68
+ timestamp,
69
+ codeChallenge,
70
+ paymentRequestId,
71
+ ...(accountId ? { accountId } : {}),
72
+ });
73
+ // Sign the message - this will return an ABI-encoded signature from the smart wallet
74
+ const signature = await this.smartWallet.account.signMessage({
75
+ message: message
76
+ });
77
+ const authData = createEIP1271AuthData({
78
+ walletAddress: this.smartWallet.account.address,
79
+ message,
80
+ signature,
81
+ timestamp,
82
+ codeChallenge,
83
+ paymentRequestId,
84
+ ...(accountId ? { accountId } : {}),
85
+ });
86
+ const jwtToken = createEIP1271JWT(authData);
87
+ this.logger.info(`codeChallenge: ${codeChallenge}`);
88
+ this.logger.info(`paymentRequestId: ${paymentRequestId}`);
89
+ this.logger.info(`walletAddress: ${this.smartWallet.account.address}`);
90
+ this.logger.info(`Generated EIP-1271 JWT: ${jwtToken}`);
91
+ return jwtToken;
92
+ }
93
+ async makePayment(destinations, memo, _paymentRequestId) {
94
+ // Filter to polygon chain destinations
95
+ const polygonDestinations = destinations.filter(d => d.chain === 'polygon');
96
+ if (polygonDestinations.length === 0) {
97
+ this.logger.debug('PolygonPaymentMaker: No polygon destinations found, cannot handle payment');
98
+ return null; // Cannot handle these destinations
99
+ }
100
+ // Pick first polygon destination
101
+ const dest = polygonDestinations[0];
102
+ const amount = dest.amount;
103
+ const currency = dest.currency;
104
+ const receiver = dest.address;
105
+ if (currency !== 'USDC') {
106
+ throw new Error('Only usdc currency is supported; received ' + currency);
107
+ }
108
+ this.logger.info(`Making spendPermission payment of ${amount} ${currency} to ${receiver} on Polygon with memo: ${memo}`);
109
+ // Convert amount to USDC units (6 decimals) as BigInt for spendPermission
110
+ const amountInUSDCUnits = BigInt(amount.multipliedBy(10 ** USDC_DECIMALS).toFixed(0));
111
+ const spendCalls = await prepareSpendCallData({ permission: this.spendPermission, amount: amountInUSDCUnits });
112
+ // Add a second call to transfer USDC from the smart wallet to the receiver
113
+ let transferCallData = encodeFunctionData({
114
+ abi: ERC20_ABI,
115
+ functionName: "transfer",
116
+ args: [receiver, amountInUSDCUnits],
117
+ });
118
+ // Append memo to transfer call data if present
119
+ // This works because the EVM ignores extra calldata beyond what a function expects.
120
+ // The ERC20 transfer() function only reads the first 68 bytes (4-byte selector + 32-byte address + 32-byte amount).
121
+ // Any additional data appended after those 68 bytes is safely ignored by the USDC contract
122
+ // but remains accessible in the transaction data for payment verification.
123
+ // This is a well-established pattern used by OpenSea, Uniswap, and other major protocols.
124
+ if (memo && memo.trim()) {
125
+ const memoHex = Buffer.from(memo.trim(), 'utf8').toString('hex');
126
+ transferCallData = (transferCallData + memoHex);
127
+ this.logger.info(`Added memo "${memo.trim()}" to transfer call`);
128
+ }
129
+ const transferCall = {
130
+ to: this.usdcAddress,
131
+ data: transferCallData,
132
+ value: '0x0'
133
+ };
134
+ // Combine spend permission calls with the transfer call
135
+ const allCalls = [...spendCalls, transferCall];
136
+ this.logger.info(`Executing ${allCalls.length} calls (${spendCalls.length} spend permission + 1 transfer)`);
137
+ const hash = await this.smartWallet.client.sendUserOperation({
138
+ account: this.smartWallet.account,
139
+ calls: allCalls.map(call => {
140
+ return {
141
+ to: call.to,
142
+ data: call.data,
143
+ value: BigInt(call.value || '0x0')
144
+ };
145
+ }),
146
+ maxPriorityFeePerGas: parseEther('0.000000001')
147
+ });
148
+ const receipt = await this.smartWallet.client.waitForUserOperationReceipt({ hash });
149
+ if (!receipt) {
150
+ throw new Error('User operation failed');
151
+ }
152
+ // The receipt contains the actual transaction hash that was mined on chain
153
+ const txHash = receipt.receipt.transactionHash;
154
+ if (!txHash) {
155
+ throw new Error('User operation was executed but no transaction hash was returned. This should not happen.');
156
+ }
157
+ this.logger.info(`Spend permission executed successfully. UserOp: ${receipt.userOpHash}, TxHash: ${txHash}`);
158
+ // Wait for additional confirmations to ensure the transaction is well-propagated
159
+ // This helps avoid the "Transaction receipt could not be found" error
160
+ await waitForTransactionConfirmations(this.smartWallet, txHash, 2, this.logger);
161
+ // Return payment result with chain and currency
162
+ return {
163
+ transactionId: txHash,
164
+ transactionSubId: receipt.userOpHash,
165
+ chain: 'polygon',
166
+ currency: 'USDC'
167
+ };
168
+ }
169
+ }
170
+
171
+ export { SmartWalletPaymentMaker };
172
+ //# sourceMappingURL=smartWalletPaymentMaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smartWalletPaymentMaker.js","sources":["../src/smartWalletPaymentMaker.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { Eip1193Provider, SpendPermission } from "./types.js";
2
+ export declare function requestSpendPermission(params: {
3
+ account: string;
4
+ spender: string;
5
+ token: string;
6
+ chainId: number;
7
+ allowance: bigint;
8
+ periodInDays: number;
9
+ provider: Eip1193Provider;
10
+ }): Promise<SpendPermission>;
11
+ export declare function prepareSpendCallData(params: {
12
+ permission: SpendPermission;
13
+ amount: bigint;
14
+ }): Promise<{
15
+ to: string;
16
+ data: string;
17
+ value: bigint;
18
+ }[]>;
19
+ //# sourceMappingURL=spendPermissionShim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spendPermissionShim.d.ts","sourceRoot":"","sources":["../src/spendPermissionShim.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqF9D,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;CAC3B,GAAG,OAAO,CAAC,eAAe,CAAC,CAkC3B;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,UAAU,EAAE,eAAe,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAczD"}
@@ -0,0 +1,129 @@
1
+ import { createWalletClient, custom, encodeFunctionData } from 'viem';
2
+ import { polygon } from 'viem/chains';
3
+
4
+ /*
5
+ This shim uses ERC20 approvals for spend permissions on Polygon.
6
+
7
+ The upside is that it will work with any Polygon wallet/connector (MetaMask, WalletConnect, etc.).
8
+
9
+ The downside is that it's a worse user experience (the user might not be familiar with ERC20 approvals,
10
+ and their wallet might not explain it to them), and worse security (rather than a bounded recurring limit,
11
+ the user needs to grant a single fixed amount up-front—renewing that amount requires a new approval).
12
+ */
13
+ // TODO: this version of the shim will only work for the initial approval. we need logic that can conditionally
14
+ // require new approvals when the old one runs out. (this will require changing the API for this module, or at
15
+ // least introducting a new function)
16
+ // Minimal ERC20 ABI for approve and transferFrom functions
17
+ const ERC20_ABI = [
18
+ {
19
+ "constant": false,
20
+ "inputs": [
21
+ {
22
+ "name": "_spender",
23
+ "type": "address"
24
+ },
25
+ {
26
+ "name": "_value",
27
+ "type": "uint256"
28
+ }
29
+ ],
30
+ "name": "approve",
31
+ "outputs": [
32
+ {
33
+ "name": "",
34
+ "type": "bool"
35
+ }
36
+ ],
37
+ "payable": false,
38
+ "stateMutability": "nonpayable",
39
+ "type": "function"
40
+ },
41
+ {
42
+ "constant": false,
43
+ "inputs": [
44
+ {
45
+ "name": "_from",
46
+ "type": "address"
47
+ },
48
+ {
49
+ "name": "_to",
50
+ "type": "address"
51
+ },
52
+ {
53
+ "name": "_value",
54
+ "type": "uint256"
55
+ }
56
+ ],
57
+ "name": "transferFrom",
58
+ "outputs": [
59
+ {
60
+ "name": "",
61
+ "type": "bool"
62
+ }
63
+ ],
64
+ "payable": false,
65
+ "stateMutability": "nonpayable",
66
+ "type": "function"
67
+ }
68
+ ];
69
+ /**
70
+ * Get Polygon chain configuration by chain ID
71
+ */
72
+ function getPolygonChainConfig(chainId) {
73
+ switch (chainId) {
74
+ case 137: // Polygon mainnet
75
+ return polygon;
76
+ default:
77
+ throw new Error(`Unsupported Polygon Chain ID: ${chainId}. Supported chains: 137 (mainnet)`);
78
+ }
79
+ }
80
+ async function requestSpendPermission(params) {
81
+ // Validate chain ID and get chain config
82
+ const chainConfig = getPolygonChainConfig(params.chainId);
83
+ const client = createWalletClient({
84
+ chain: chainConfig,
85
+ transport: custom(params.provider)
86
+ });
87
+ // Use the client
88
+ const hash = await client.sendTransaction({
89
+ account: params.account,
90
+ to: params.token,
91
+ data: encodeFunctionData({
92
+ abi: ERC20_ABI,
93
+ functionName: "approve",
94
+ args: [params.spender, params.allowance]
95
+ })
96
+ });
97
+ return {
98
+ permission: {
99
+ account: params.account,
100
+ spender: params.spender,
101
+ token: params.token,
102
+ allowance: params.allowance.toString(),
103
+ period: params.periodInDays * 24 * 60 * 60,
104
+ start: Math.floor(Date.now() / 1000),
105
+ end: Math.floor(Date.now() / 1000) + params.periodInDays * 24 * 60 * 60,
106
+ salt: '0x0',
107
+ extraData: '0x0'
108
+ },
109
+ signature: hash
110
+ };
111
+ }
112
+ async function prepareSpendCallData(params) {
113
+ // this introduces an extra layer of indirection: user wallet -> ephemeral wallet -> receiver
114
+ // but the reason for this is that we can't sign JWTs from the user wallet directly
115
+ return [
116
+ {
117
+ to: params.permission.permission.token,
118
+ data: encodeFunctionData({
119
+ abi: ERC20_ABI,
120
+ functionName: 'transferFrom',
121
+ args: [params.permission.permission.account, params.permission.permission.spender, params.amount]
122
+ }),
123
+ value: BigInt(0)
124
+ }
125
+ ];
126
+ }
127
+
128
+ export { prepareSpendCallData, requestSpendPermission };
129
+ //# sourceMappingURL=spendPermissionShim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spendPermissionShim.js","sources":["../src/spendPermissionShim.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -8,10 +8,10 @@ export declare const TEST_WALLET_ADDRESS: Hex;
8
8
  export declare const TEST_RECEIVER_ADDRESS: Hex;
9
9
  export declare const TEST_PRIVATE_KEY: Hex;
10
10
  export declare function mockLogger(): {
11
- info: Mock<(...args: any[]) => any>;
12
- warn: Mock<(...args: any[]) => any>;
13
- error: Mock<(...args: any[]) => any>;
14
- debug: Mock<(...args: any[]) => any>;
11
+ info: Mock<import("@vitest/spy").Procedure>;
12
+ warn: Mock<import("@vitest/spy").Procedure>;
13
+ error: Mock<import("@vitest/spy").Procedure>;
14
+ debug: Mock<import("@vitest/spy").Procedure>;
15
15
  };
16
16
  export declare function mockProvider(overrides?: Partial<MockEip1193Provider>): MockEip1193Provider;
17
17
  //# sourceMappingURL=testHelpers.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atxp/polygon",
3
- "version": "0.10.2",
3
+ "version": "0.10.4",
4
4
  "description": "ATXP for Polygon",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,23 +35,23 @@
35
35
  "pack:dry": "npm pack --dry-run"
36
36
  },
37
37
  "dependencies": {
38
- "@atxp/client": "0.10.2",
39
- "@atxp/common": "0.10.2",
38
+ "@atxp/client": "0.10.4",
39
+ "@atxp/common": "0.10.4",
40
40
  "bignumber.js": "^9.3.0",
41
41
  "viem": "^2.34.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/node": "^22.13.0",
44
+ "@types/node": "^25.0.3",
45
45
  "@types/supertest": "^6.0.3",
46
- "@typescript-eslint/eslint-plugin": "^8.38.0",
47
- "@typescript-eslint/parser": "^8.38.0",
46
+ "@typescript-eslint/eslint-plugin": "^8.51.0",
47
+ "@typescript-eslint/parser": "^8.51.0",
48
48
  "eslint": "^9.32.0",
49
49
  "fetch-mock": "^12.5.2",
50
50
  "happy-dom": "^20.0.11",
51
- "jsdom": "^25.0.1",
51
+ "jsdom": "^27.4.0",
52
52
  "supertest": "^7.1.4",
53
53
  "typescript": "^5.7.3",
54
54
  "viem": "^2.34.0",
55
- "vitest": "^3.0.9"
55
+ "vitest": "^4.0.16"
56
56
  }
57
57
  }