@net-protocol/relay 0.1.0 → 0.1.2

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/dist/index.d.mts CHANGED
@@ -275,10 +275,10 @@ declare function retryFailedTransactions(params: RetryFailedTransactionsParams):
275
275
  * Storage transactions can be large due to:
276
276
  * - Large args arrays (chunk data)
277
277
  * - Hex-encoded data in args
278
- * - ABI structure overhead
278
+ * - Full ABI included in each transaction (can be 2-3KB)
279
279
  *
280
- * We use a conservative estimate of 100KB per transaction to ensure we stay under the 1MB limit.
281
- * With 100KB per transaction, we can fit ~9 transactions per batch (900KB / 100KB).
280
+ * The entire transaction object is serialized to JSON, including the ABI,
281
+ * so we must account for all fields.
282
282
  */
283
283
  declare function estimateTransactionSize(tx: WriteTransactionConfig): number;
284
284
  /**
@@ -451,7 +451,8 @@ declare const MAX_TRANSACTIONS_PER_BATCH = 100;
451
451
  declare const MAX_BATCH_SIZE_BYTES: number;
452
452
  /**
453
453
  * Maximum size per transaction in bytes
454
- * Storage transactions can include large data chunks, so we assume up to 100KB per transaction
454
+ * Storage transactions can include large data chunks (up to ~200KB per transaction)
455
+ * This cap prevents a single malformed transaction from blocking the entire batch
455
456
  */
456
457
  declare const MAX_TRANSACTION_SIZE_BYTES: number;
457
458
 
package/dist/index.d.ts CHANGED
@@ -275,10 +275,10 @@ declare function retryFailedTransactions(params: RetryFailedTransactionsParams):
275
275
  * Storage transactions can be large due to:
276
276
  * - Large args arrays (chunk data)
277
277
  * - Hex-encoded data in args
278
- * - ABI structure overhead
278
+ * - Full ABI included in each transaction (can be 2-3KB)
279
279
  *
280
- * We use a conservative estimate of 100KB per transaction to ensure we stay under the 1MB limit.
281
- * With 100KB per transaction, we can fit ~9 transactions per batch (900KB / 100KB).
280
+ * The entire transaction object is serialized to JSON, including the ABI,
281
+ * so we must account for all fields.
282
282
  */
283
283
  declare function estimateTransactionSize(tx: WriteTransactionConfig): number;
284
284
  /**
@@ -451,7 +451,8 @@ declare const MAX_TRANSACTIONS_PER_BATCH = 100;
451
451
  declare const MAX_BATCH_SIZE_BYTES: number;
452
452
  /**
453
453
  * Maximum size per transaction in bytes
454
- * Storage transactions can include large data chunks, so we assume up to 100KB per transaction
454
+ * Storage transactions can include large data chunks (up to ~200KB per transaction)
455
+ * This cap prevents a single malformed transaction from blocking the entire batch
455
456
  */
456
457
  declare const MAX_TRANSACTION_SIZE_BYTES: number;
457
458
 
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ var DEFAULT_CONFIRMATIONS = 1;
27
27
  var DEFAULT_TIMEOUT = 6e4;
28
28
  var MAX_TRANSACTIONS_PER_BATCH = 100;
29
29
  var MAX_BATCH_SIZE_BYTES = 900 * 1024;
30
- var MAX_TRANSACTION_SIZE_BYTES = 100 * 1024;
30
+ var MAX_TRANSACTION_SIZE_BYTES = 250 * 1024;
31
31
 
32
32
  // src/session.ts
33
33
  async function createRelaySession(params) {
@@ -138,6 +138,46 @@ function extractPaymentTxHash(response, httpClient) {
138
138
  return null;
139
139
  }
140
140
  }
141
+ function isRetryableVerifyError(statusCode, errorMessage) {
142
+ if (statusCode >= 500) return true;
143
+ if (statusCode >= 400 && statusCode < 500) {
144
+ const msg = errorMessage.toLowerCase();
145
+ return msg.includes("failed to fetch payment transaction") || msg.includes("treasury wallet has insufficient balance") || msg.includes("transferfailed");
146
+ }
147
+ return false;
148
+ }
149
+ async function verifyFundWithRetry(apiUrl, paymentTxHash, operatorAddress, secretKey, chainId) {
150
+ const maxRetries = 3;
151
+ const initialDelayMs = 2e3;
152
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
153
+ const response = await fetch(`${apiUrl}/api/relay/fund/verify`, {
154
+ method: "POST",
155
+ headers: { "Content-Type": "application/json" },
156
+ body: JSON.stringify({
157
+ chainId,
158
+ paymentTxHash,
159
+ operatorAddress,
160
+ secretKey
161
+ })
162
+ });
163
+ const data = await response.json();
164
+ if (response.ok && data.success) {
165
+ return data;
166
+ }
167
+ const errorMessage = data.error || "Unknown error";
168
+ if (!isRetryableVerifyError(response.status, errorMessage)) {
169
+ throw new Error(`Fund verify failed: ${response.status} ${errorMessage}`);
170
+ }
171
+ if (attempt === maxRetries) {
172
+ throw new Error(
173
+ `Fund verify failed after ${maxRetries + 1} attempts: ${errorMessage}`
174
+ );
175
+ }
176
+ const delayMs = initialDelayMs * Math.pow(2, attempt);
177
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
178
+ }
179
+ throw new Error("Verify failed after all retries");
180
+ }
141
181
  async function fundBackendWallet(params) {
142
182
  const {
143
183
  apiUrl,
@@ -196,33 +236,16 @@ async function fundBackendWallet(params) {
196
236
  );
197
237
  }
198
238
  await new Promise((resolve) => setTimeout(resolve, 2e3));
199
- const verifyFundResponse = await fetch(`${apiUrl}/api/relay/fund/verify`, {
200
- method: "POST",
201
- headers: {
202
- "Content-Type": "application/json"
203
- },
204
- body: JSON.stringify({
205
- chainId,
206
- paymentTxHash,
207
- operatorAddress,
208
- secretKey
209
- })
210
- });
211
- if (!verifyFundResponse.ok) {
212
- const errorData = await verifyFundResponse.json();
213
- throw new Error(
214
- `Fund verify endpoint failed: ${verifyFundResponse.status} ${JSON.stringify(errorData)}`
215
- );
216
- }
217
- const verifyData = await verifyFundResponse.json();
239
+ const verifyData = await verifyFundWithRetry(
240
+ apiUrl,
241
+ paymentTxHash,
242
+ operatorAddress,
243
+ secretKey,
244
+ chainId
245
+ );
218
246
  console.log("\u2713 Payment verified and backend wallet funded", {
219
247
  backendWalletAddress: verifyData.backendWalletAddress
220
248
  });
221
- if (!verifyData.success) {
222
- throw new Error(
223
- `Fund verify failed: ${verifyData.error || "Unknown error"}`
224
- );
225
- }
226
249
  if (!verifyData.backendWalletAddress) {
227
250
  throw new Error("Backend wallet address not found in verify response");
228
251
  }
@@ -384,9 +407,10 @@ async function retryFailedTransactions(params) {
384
407
  // src/batch.ts
385
408
  function estimateTransactionSize(tx) {
386
409
  const argsSize = tx.args ? JSON.stringify(tx.args).length : 0;
410
+ const abiSize = tx.abi ? JSON.stringify(tx.abi).length : 0;
411
+ const overhead = 200;
387
412
  return Math.min(
388
- argsSize + 1024,
389
- // args + overhead
413
+ argsSize + abiSize + overhead,
390
414
  MAX_TRANSACTION_SIZE_BYTES
391
415
  );
392
416
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/session.ts","../src/balance.ts","../src/fund.ts","../src/submit.ts","../src/retry.ts","../src/batch.ts","../src/confirmations.ts","../src/client/x402Client.ts","../src/client/RelayClient.ts"],"names":["keccak256","toBytes","waitForTransactionReceipt","client","x402Client","registerExactEvmScheme","wrapFetchWithPayment","x402HTTPClient"],"mappings":"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","file":"index.js","sourcesContent":["import type { RetryConfig } from \"./types\";\n\n/**\n * EIP-712 domain name for relay session signing\n */\nexport const RELAY_DOMAIN_NAME = \"Net Relay Service\";\n\n/**\n * EIP-712 domain version for relay session signing\n */\nexport const RELAY_DOMAIN_VERSION = \"1\";\n\n/**\n * EIP-712 types for relay session signing\n */\nexport const RELAY_SESSION_TYPES = {\n RelaySession: [\n { name: \"operatorAddress\", type: \"address\" },\n { name: \"secretKeyHash\", type: \"bytes32\" },\n { name: \"expiresAt\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * Default retry configuration\n */\nexport const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\n/**\n * Default number of confirmations to wait for\n */\nexport const DEFAULT_CONFIRMATIONS = 1;\n\n/**\n * Default timeout for waiting for transaction confirmations (milliseconds)\n */\nexport const DEFAULT_TIMEOUT = 60000; // 60 seconds\n\n/**\n * Maximum transactions per batch (matches server limit)\n */\nexport const MAX_TRANSACTIONS_PER_BATCH = 100;\n\n/**\n * Maximum request size in bytes (slightly under 1MB for safety margin)\n */\nexport const MAX_BATCH_SIZE_BYTES = 900 * 1024; // 900KB\n\n/**\n * Maximum size per transaction in bytes\n * Storage transactions can include large data chunks, so we assume up to 100KB per transaction\n */\nexport const MAX_TRANSACTION_SIZE_BYTES = 100 * 1024; // 100KB\n\n","import { keccak256, toBytes } from \"viem\";\nimport type { LocalAccount, Address } from \"viem/accounts\";\nimport {\n RELAY_DOMAIN_NAME,\n RELAY_DOMAIN_VERSION,\n RELAY_SESSION_TYPES,\n} from \"./constants\";\nimport type { CreateSessionResponse, ErrorResponse } from \"./types\";\n\n/**\n * Create a relay session token\n *\n * Signs an EIP-712 message proving ownership of operatorAddress\n * and receives a sessionToken that can be reused for multiple batch requests.\n *\n * @param params - Session creation parameters\n * @returns Session token and expiration timestamp\n * @throws Error if session creation fails\n */\nexport async function createRelaySession(params: {\n apiUrl: string;\n chainId: number;\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number; // seconds, default 3600\n}): Promise<{ sessionToken: string; expiresAt: number }> {\n const { apiUrl, chainId, operatorAddress, secretKey, account, expiresIn } =\n params;\n\n const expiresInSeconds = expiresIn || 3600; // Default 1 hour\n const expiresAt = Math.floor(Date.now() / 1000) + expiresInSeconds;\n const secretKeyHash = keccak256(toBytes(secretKey));\n\n const domain = {\n name: RELAY_DOMAIN_NAME,\n version: RELAY_DOMAIN_VERSION,\n chainId,\n };\n\n const message = {\n operatorAddress,\n secretKeyHash,\n expiresAt: BigInt(expiresAt),\n };\n\n // Sign the typed data using account's signTypedData method\n const signature = await account.signTypedData({\n domain,\n types: RELAY_SESSION_TYPES,\n primaryType: \"RelaySession\",\n message,\n });\n\n // Call session endpoint (send expiresAt - the exact value that was signed)\n const response = await fetch(`${apiUrl}/api/relay/session`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n signature,\n expiresAt, // Send the exact expiresAt that was signed\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Session creation failed: ${response.status} ${\n errorData.error || response.statusText\n }`\n );\n }\n\n const result = (await response.json()) as\n | CreateSessionResponse\n | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Session creation failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n if (!result.sessionToken || !result.expiresAt) {\n throw new Error(\n \"Session creation failed: Missing sessionToken or expiresAt in response\"\n );\n }\n\n return {\n sessionToken: result.sessionToken,\n expiresAt: result.expiresAt,\n };\n}\n\n","import type {\n CheckBackendWalletBalanceParams,\n CheckBalanceResult,\n BalanceResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Check backend wallet balance via relay service\n *\n * This function:\n * 1. Calls /api/relay/balance with operatorAddress and secretKey\n * 2. Returns balance information including sufficientBalance flag\n *\n * @param params - Balance check parameters\n * @returns Result with balance information\n * @throws Error if balance check fails\n */\nexport async function checkBackendWalletBalance(\n params: CheckBackendWalletBalanceParams\n): Promise<CheckBalanceResult> {\n const { apiUrl, chainId, operatorAddress, secretKey } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/balance`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Balance check endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as BalanceResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Balance check failed: ${(\"error\" in result ? result.error : null) || \"Unknown error\"}`\n );\n }\n\n return {\n backendWalletAddress: result.backendWalletAddress,\n balanceWei: result.balanceWei,\n balanceEth: result.balanceEth,\n sufficientBalance: result.sufficientBalance,\n minRequiredWei: result.minRequiredWei,\n minRequiredEth: result.minRequiredEth,\n };\n}\n\n","import type { Hash } from \"viem\";\nimport type {\n FundBackendWalletParams,\n RelayFundResult,\n FundResponse,\n VerifyFundResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Extract payment transaction hash from response headers\n */\nfunction extractPaymentTxHash(\n response: Response,\n httpClient: FundBackendWalletParams[\"httpClient\"]\n): string | null {\n try {\n const paymentResponse = httpClient.getPaymentSettleResponse(\n (name: string) => response.headers.get(name)\n );\n return paymentResponse?.transaction || paymentResponse?.txHash || null;\n } catch (error) {\n console.error(\"Failed to extract payment transaction hash:\", error);\n return null;\n }\n}\n\n/**\n * Fund backend wallet via x402 relay service\n *\n * This function:\n * 1. Calls /api/relay/[chainId]/fund with x402 payment (using fetchWithPayment)\n * 2. Extracts paymentTxHash from X-PAYMENT-RESPONSE header\n * 3. Waits for payment confirmation (2 seconds)\n * 4. Calls /api/relay/fund/verify to get backendWalletAddress\n * 5. Returns { paymentTxHash, backendWalletAddress }\n *\n * @param params - Funding parameters\n * @returns Result with paymentTxHash and backendWalletAddress\n * @throws Error if funding fails\n */\nexport async function fundBackendWallet(\n params: FundBackendWalletParams\n): Promise<RelayFundResult> {\n const {\n apiUrl,\n operatorAddress,\n secretKey,\n fetchWithPayment,\n httpClient,\n chainId,\n } = params;\n\n const fundUrl = `${apiUrl}/api/relay/${chainId}/fund`;\n\n console.log(\"💰 Funding backend wallet\", {\n url: fundUrl,\n chainId,\n operatorAddress,\n facilitator:\n chainId === 8453\n ? \"Coinbase CDP (Base Mainnet)\"\n : chainId === 84532\n ? \"x402.org (Base Sepolia)\"\n : \"unknown\",\n });\n\n // Step 1: Call /api/relay/[chainId]/fund (Payment)\n let fundResponse: Response;\n try {\n fundResponse = await fetchWithPayment(fundUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n } catch (error) {\n console.error(\"❌ Fund request failed\", {\n error: error instanceof Error ? error.message : String(error),\n chainId,\n url: fundUrl,\n });\n throw error;\n }\n\n const fundData = (await fundResponse.json()) as FundResponse | ErrorResponse;\n\n // Handle 402 Payment Required\n if (fundResponse.status === 402) {\n // Check if payment was actually processed despite 402\n if (\"payer\" in fundData && fundData.payer) {\n // Payment appears to have been processed\n } else if (\"success\" in fundData && fundData.success) {\n // Payment appears to have been processed\n } else {\n throw new Error(\n `Fund endpoint returned 402 Payment Required: ${JSON.stringify(\n fundData\n )}`\n );\n }\n } else if (!fundResponse.ok) {\n throw new Error(\n `Fund endpoint failed: ${fundResponse.status} ${JSON.stringify(fundData)}`\n );\n }\n\n // Extract payment transaction hash from response headers\n const paymentTxHash = extractPaymentTxHash(fundResponse, httpClient);\n\n if (!paymentTxHash) {\n throw new Error(\n \"Failed to extract payment transaction hash from payment response headers\"\n );\n }\n\n // Step 2: Wait for payment confirmation\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Step 3: Call /api/relay/fund/verify (Verification & Funding)\n const verifyFundResponse = await fetch(`${apiUrl}/api/relay/fund/verify`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n paymentTxHash: paymentTxHash as Hash,\n operatorAddress,\n secretKey,\n }),\n });\n\n if (!verifyFundResponse.ok) {\n const errorData = (await verifyFundResponse.json()) as ErrorResponse;\n throw new Error(\n `Fund verify endpoint failed: ${\n verifyFundResponse.status\n } ${JSON.stringify(errorData)}`\n );\n }\n\n const verifyData = (await verifyFundResponse.json()) as VerifyFundResponse;\n console.log(\"✓ Payment verified and backend wallet funded\", {\n backendWalletAddress: verifyData.backendWalletAddress,\n });\n\n if (!verifyData.success) {\n throw new Error(\n `Fund verify failed: ${verifyData.error || \"Unknown error\"}`\n );\n }\n\n if (!verifyData.backendWalletAddress) {\n throw new Error(\"Backend wallet address not found in verify response\");\n }\n\n return {\n paymentTxHash: paymentTxHash as Hash,\n backendWalletAddress: verifyData.backendWalletAddress,\n };\n}\n\n","import type { Hash, Address } from \"viem\";\nimport type {\n SubmitTransactionsViaRelayParams,\n RelaySubmitResult,\n SubmitResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Submit transactions via relay service\n *\n * Calls /api/relay/submit with transactions and returns result\n * with success/failure tracking by index.\n *\n * @param params - Submission parameters\n * @returns Result with transaction hashes and success/failure tracking\n * @throws Error if submission fails\n */\nexport async function submitTransactionsViaRelay(\n params: SubmitTransactionsViaRelayParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions,\n sessionToken,\n } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/submit`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n transactions: transactions.map((tx) => ({\n ...tx,\n // Only include value if it exists and is > 0\n ...(tx.value !== undefined && tx.value > BigInt(0)\n ? { value: tx.value.toString() }\n : {}),\n })),\n sessionToken,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Relay submit endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as SubmitResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Relay submit failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n return {\n transactionHashes: result.transactionHashes.map((h: string) => h as Hash),\n successfulIndexes: result.successfulIndexes || [],\n failedIndexes: result.failedIndexes || [],\n errors: result.errors || [],\n backendWalletAddress: result.backendWalletAddress as Address,\n appFeeTransactionHash: result.appFeeTransactionHash as Hash,\n };\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport type { Address } from \"viem\";\nimport type {\n RetryFailedTransactionsParams,\n RetryConfig,\n RelaySubmitResult,\n} from \"./types\";\nimport { DEFAULT_RETRY_CONFIG } from \"./constants\";\nimport { submitTransactionsViaRelay } from \"./submit\";\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for exponential backoff\n */\nfunction calculateDelay(\n attempt: number,\n config: Required<RetryConfig>\n): number {\n const delay =\n config.initialDelay * Math.pow(config.backoffMultiplier, attempt);\n return Math.min(delay, config.maxDelay);\n}\n\n/**\n * Retry failed transactions with exponential backoff\n *\n * This function:\n * 1. Extracts failed transactions by index from RelaySubmitResult\n * 2. Optionally re-checks on-chain before retry (via recheckFunction)\n * 3. Retries with exponential backoff\n * 4. Handles nested retries\n *\n * @param params - Retry parameters\n * @returns Final success/failure status after retries\n */\nexport async function retryFailedTransactions(\n params: RetryFailedTransactionsParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n failedIndexes: initialFailedIndexes,\n originalTransactions,\n backendWalletAddress,\n config = {},\n sessionToken,\n recheckFunction,\n } = params;\n\n const retryConfig: Required<RetryConfig> = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let failedIndexes = initialFailedIndexes;\n let attempt = 0;\n let lastResult: RelaySubmitResult | null = null;\n\n while (failedIndexes.length > 0 && attempt < retryConfig.maxRetries) {\n attempt++;\n\n // Re-check on-chain before retry (if recheckFunction provided)\n if (recheckFunction) {\n failedIndexes = await recheckFunction(\n failedIndexes,\n originalTransactions,\n backendWalletAddress\n );\n }\n\n if (failedIndexes.length === 0) {\n // All transactions have succeeded\n break;\n }\n\n // Calculate delay for exponential backoff\n const delay = calculateDelay(attempt - 1, retryConfig);\n if (attempt > 1) {\n // Don't delay on first attempt\n await sleep(delay);\n }\n\n // Extract failed transactions\n const failedTransactions = failedIndexes.map(\n (idx) => originalTransactions[idx]\n );\n\n // Retry failed transactions\n try {\n const retryResult = await submitTransactionsViaRelay({\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions: failedTransactions,\n sessionToken,\n });\n\n // Merge results\n if (lastResult) {\n // Combine transaction hashes\n lastResult.transactionHashes.push(...retryResult.transactionHashes);\n // Combine successful indexes (adjust for original index)\n lastResult.successfulIndexes.push(\n ...retryResult.successfulIndexes.map((idx) => failedIndexes[idx])\n );\n // Update failed indexes\n lastResult.failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n // Combine errors\n lastResult.errors.push(\n ...retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n }))\n );\n } else {\n lastResult = {\n ...retryResult,\n successfulIndexes: retryResult.successfulIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n failedIndexes: retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n errors: retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n })),\n };\n }\n\n // Update failed indexes for next iteration\n failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n } catch (error) {\n // Retry failed, keep current failed indexes\n console.error(`Retry attempt ${attempt} failed:`, error);\n }\n }\n\n if (!lastResult) {\n throw new Error(\"Retry failed: No result after retries\");\n }\n\n return lastResult;\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport {\n MAX_TRANSACTIONS_PER_BATCH,\n MAX_BATCH_SIZE_BYTES,\n MAX_TRANSACTION_SIZE_BYTES,\n} from \"./constants\";\n\n/**\n * Estimate the size of a serialized transaction config in bytes\n *\n * Storage transactions can be large due to:\n * - Large args arrays (chunk data)\n * - Hex-encoded data in args\n * - ABI structure overhead\n *\n * We use a conservative estimate of 100KB per transaction to ensure we stay under the 1MB limit.\n * With 100KB per transaction, we can fit ~9 transactions per batch (900KB / 100KB).\n */\nexport function estimateTransactionSize(tx: WriteTransactionConfig): number {\n // Estimate based on args size\n // Args can contain large hex-encoded data (chunks), so we assume up to 100KB\n // Add overhead for JSON structure, ABI, function name, etc. (~1KB)\n const argsSize = tx.args ? JSON.stringify(tx.args).length : 0;\n\n // Use the larger of: actual args size or conservative estimate\n // Cap at MAX_TRANSACTION_SIZE_BYTES to prevent single transaction from exceeding batch limit\n return Math.min(\n argsSize + 1024, // args + overhead\n MAX_TRANSACTION_SIZE_BYTES\n );\n}\n\n/**\n * Estimate the total request size for a batch of transactions\n */\nexport function estimateRequestSize(\n transactions: WriteTransactionConfig[]\n): number {\n // Base overhead: operatorAddress (~42 bytes),\n // secretKey (~50-200 bytes), JSON structure (~100 bytes)\n const baseOverhead = 300;\n const transactionsSize = transactions.reduce(\n (sum, tx) => sum + estimateTransactionSize(tx),\n 0\n );\n return baseOverhead + transactionsSize;\n}\n\n/**\n * Batch transactions into groups that respect count and size limits\n *\n * With 100KB per transaction estimate:\n * - Size limit: ~9 transactions per batch (900KB / 100KB)\n * - Count limit: 100 transactions per batch\n * - Size limit is the constraining factor for large transactions\n */\nexport function batchTransactions(\n transactions: WriteTransactionConfig[]\n): WriteTransactionConfig[][] {\n const batches: WriteTransactionConfig[][] = [];\n let currentBatch: WriteTransactionConfig[] = [];\n\n for (const tx of transactions) {\n // Calculate what the batch size would be with this transaction added\n const batchWithTx = [...currentBatch, tx];\n const estimatedSize = estimateRequestSize(batchWithTx);\n\n // Check if adding this transaction would exceed limits\n // Size limit is typically the constraining factor (9 transactions @ 100KB each)\n if (\n currentBatch.length >= MAX_TRANSACTIONS_PER_BATCH ||\n estimatedSize > MAX_BATCH_SIZE_BYTES\n ) {\n // Start a new batch\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n }\n }\n\n // If a single transaction exceeds the batch size limit, we still add it\n // (it will be its own batch, and the server will reject it with a clear error)\n currentBatch.push(tx);\n }\n\n // Add the last batch if it has transactions\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n","import { waitForTransactionReceipt } from \"viem/actions\";\nimport type { Hash } from \"viem\";\nimport type {\n WaitForConfirmationsParams,\n ConfirmationResult,\n} from \"./types\";\nimport { DEFAULT_CONFIRMATIONS, DEFAULT_TIMEOUT } from \"./constants\";\n\n/**\n * Wait for transaction confirmations\n *\n * Uses waitForTransactionReceipt() from viem/actions to wait for\n * multiple transactions in parallel. Handles timeouts and tracks progress.\n *\n * @param params - Confirmation parameters\n * @returns Array of transaction receipts\n * @throws Error if timeout occurs or transaction fails\n */\nexport async function waitForConfirmations(\n params: WaitForConfirmationsParams\n): Promise<ConfirmationResult[]> {\n const {\n publicClient,\n transactionHashes,\n confirmations = DEFAULT_CONFIRMATIONS,\n timeout = DEFAULT_TIMEOUT,\n onProgress,\n } = params;\n\n if (transactionHashes.length === 0) {\n return [];\n }\n\n const results: ConfirmationResult[] = [];\n let confirmed = 0;\n\n // Wait for all transactions in parallel\n const promises = transactionHashes.map(async (hash) => {\n try {\n const receipt = await waitForTransactionReceipt(publicClient, {\n hash,\n confirmations,\n timeout,\n });\n\n confirmed++;\n if (onProgress) {\n onProgress(confirmed, transactionHashes.length);\n }\n\n return { hash, receipt };\n } catch (error) {\n // Transaction failed or timed out\n throw new Error(\n `Transaction ${hash} failed or timed out: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n });\n\n // Wait for all promises\n const receipts = await Promise.all(promises);\n\n return receipts;\n}\n\n","import { x402Client, wrapFetchWithPayment, x402HTTPClient } from \"@x402/fetch\";\nimport { registerExactEvmScheme } from \"@x402/evm/exact/client\";\nimport type { LocalAccount } from \"viem/accounts\";\nimport type { X402ClientResult } from \"../types\";\n\n/**\n * Create x402 client for relay payments\n *\n * Sets up x402Client with user's account, registers EVM scheme,\n * and returns wrapped fetch function and HTTP client for header extraction.\n *\n * @param account - User's local account (from privateKeyToAccount)\n * @param chainId - Chain ID (optional, for logging purposes)\n * @returns Object with fetchWithPayment and httpClient\n */\nexport function createRelayX402Client(\n account: LocalAccount,\n chainId?: number\n): X402ClientResult {\n const client = new x402Client();\n registerExactEvmScheme(client, { signer: account });\n const fetchWithPayment = wrapFetchWithPayment(fetch, client);\n const httpClient = new x402HTTPClient(client);\n\n return { fetchWithPayment, httpClient };\n}\n\n","import type { LocalAccount, Address } from \"viem/accounts\";\nimport type { PublicClient, Hash } from \"viem\";\nimport type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport { createRelaySession } from \"../session\";\nimport { checkBackendWalletBalance } from \"../balance\";\nimport { fundBackendWallet } from \"../fund\";\nimport { submitTransactionsViaRelay } from \"../submit\";\nimport { retryFailedTransactions } from \"../retry\";\nimport { createRelayX402Client } from \"./x402Client\";\nimport type {\n CheckBalanceResult,\n RelayFundResult,\n RelaySubmitResult,\n RetryFailedTransactionsParams,\n RetryConfig,\n FundBackendWalletParams,\n SubmitTransactionsViaRelayParams,\n} from \"../types\";\n\n/**\n * High-level client for Net Relay Service\n *\n * Provides a convenient class-based API that stores apiUrl and chainId,\n * reducing boilerplate when making multiple relay calls.\n */\nexport class RelayClient {\n private apiUrl: string;\n private chainId: number;\n\n constructor(options: { apiUrl: string; chainId: number }) {\n this.apiUrl = options.apiUrl;\n this.chainId = options.chainId;\n }\n\n /**\n * Create a relay session token\n *\n * @param params - Session creation parameters (apiUrl and chainId are already set)\n * @returns Session token and expiration timestamp\n */\n async createSession(params: {\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number;\n }): Promise<{ sessionToken: string; expiresAt: number }> {\n return createRelaySession({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Check backend wallet balance\n *\n * @param params - Balance check parameters (apiUrl and chainId are already set)\n * @returns Result with balance information\n */\n async checkBalance(params: {\n operatorAddress: Address;\n secretKey: string;\n }): Promise<CheckBalanceResult> {\n return checkBackendWalletBalance({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Fund backend wallet via x402 payment\n *\n * @param params - Funding parameters (apiUrl and chainId are already set)\n * @returns Result with paymentTxHash and backendWalletAddress\n */\n async fundBackendWallet(params: {\n operatorAddress: Address;\n secretKey: string;\n fetchWithPayment: typeof fetch;\n httpClient: FundBackendWalletParams[\"httpClient\"];\n }): Promise<RelayFundResult> {\n return fundBackendWallet({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Submit transactions via relay\n *\n * @param params - Submission parameters (apiUrl and chainId are already set)\n * @returns Result with transaction hashes and success/failure tracking\n */\n async submitTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n transactions: WriteTransactionConfig[];\n sessionToken: string;\n }): Promise<RelaySubmitResult> {\n return submitTransactionsViaRelay({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Retry failed transactions with exponential backoff\n *\n * @param params - Retry parameters (apiUrl and chainId are already set)\n * @returns Final success/failure status after retries\n */\n async retryFailedTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n failedIndexes: number[];\n originalTransactions: WriteTransactionConfig[];\n backendWalletAddress: Address;\n config?: RetryConfig;\n sessionToken: string;\n recheckFunction?: RetryFailedTransactionsParams[\"recheckFunction\"];\n }): Promise<RelaySubmitResult> {\n return retryFailedTransactions({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Create x402 client for relay payments\n *\n * @param account - User's local account\n * @returns Object with fetchWithPayment and httpClient\n */\n createX402Client(account: LocalAccount) {\n return createRelayX402Client(account, this.chainId);\n }\n}\n\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/session.ts","../src/balance.ts","../src/fund.ts","../src/submit.ts","../src/retry.ts","../src/batch.ts","../src/confirmations.ts","../src/client/x402Client.ts","../src/client/RelayClient.ts"],"names":["keccak256","toBytes","waitForTransactionReceipt","client","x402Client","registerExactEvmScheme","wrapFetchWithPayment","x402HTTPClient"],"mappings":"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","file":"index.js","sourcesContent":["import type { RetryConfig } from \"./types\";\n\n/**\n * EIP-712 domain name for relay session signing\n */\nexport const RELAY_DOMAIN_NAME = \"Net Relay Service\";\n\n/**\n * EIP-712 domain version for relay session signing\n */\nexport const RELAY_DOMAIN_VERSION = \"1\";\n\n/**\n * EIP-712 types for relay session signing\n */\nexport const RELAY_SESSION_TYPES = {\n RelaySession: [\n { name: \"operatorAddress\", type: \"address\" },\n { name: \"secretKeyHash\", type: \"bytes32\" },\n { name: \"expiresAt\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * Default retry configuration\n */\nexport const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\n/**\n * Default number of confirmations to wait for\n */\nexport const DEFAULT_CONFIRMATIONS = 1;\n\n/**\n * Default timeout for waiting for transaction confirmations (milliseconds)\n */\nexport const DEFAULT_TIMEOUT = 60000; // 60 seconds\n\n/**\n * Maximum transactions per batch (matches server limit)\n */\nexport const MAX_TRANSACTIONS_PER_BATCH = 100;\n\n/**\n * Maximum request size in bytes (slightly under 1MB for safety margin)\n */\nexport const MAX_BATCH_SIZE_BYTES = 900 * 1024; // 900KB\n\n/**\n * Maximum size per transaction in bytes\n * Storage transactions can include large data chunks (up to ~200KB per transaction)\n * This cap prevents a single malformed transaction from blocking the entire batch\n */\nexport const MAX_TRANSACTION_SIZE_BYTES = 250 * 1024; // 250KB\n\n","import { keccak256, toBytes } from \"viem\";\nimport type { LocalAccount, Address } from \"viem/accounts\";\nimport {\n RELAY_DOMAIN_NAME,\n RELAY_DOMAIN_VERSION,\n RELAY_SESSION_TYPES,\n} from \"./constants\";\nimport type { CreateSessionResponse, ErrorResponse } from \"./types\";\n\n/**\n * Create a relay session token\n *\n * Signs an EIP-712 message proving ownership of operatorAddress\n * and receives a sessionToken that can be reused for multiple batch requests.\n *\n * @param params - Session creation parameters\n * @returns Session token and expiration timestamp\n * @throws Error if session creation fails\n */\nexport async function createRelaySession(params: {\n apiUrl: string;\n chainId: number;\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number; // seconds, default 3600\n}): Promise<{ sessionToken: string; expiresAt: number }> {\n const { apiUrl, chainId, operatorAddress, secretKey, account, expiresIn } =\n params;\n\n const expiresInSeconds = expiresIn || 3600; // Default 1 hour\n const expiresAt = Math.floor(Date.now() / 1000) + expiresInSeconds;\n const secretKeyHash = keccak256(toBytes(secretKey));\n\n const domain = {\n name: RELAY_DOMAIN_NAME,\n version: RELAY_DOMAIN_VERSION,\n chainId,\n };\n\n const message = {\n operatorAddress,\n secretKeyHash,\n expiresAt: BigInt(expiresAt),\n };\n\n // Sign the typed data using account's signTypedData method\n const signature = await account.signTypedData({\n domain,\n types: RELAY_SESSION_TYPES,\n primaryType: \"RelaySession\",\n message,\n });\n\n // Call session endpoint (send expiresAt - the exact value that was signed)\n const response = await fetch(`${apiUrl}/api/relay/session`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n signature,\n expiresAt, // Send the exact expiresAt that was signed\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Session creation failed: ${response.status} ${\n errorData.error || response.statusText\n }`\n );\n }\n\n const result = (await response.json()) as\n | CreateSessionResponse\n | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Session creation failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n if (!result.sessionToken || !result.expiresAt) {\n throw new Error(\n \"Session creation failed: Missing sessionToken or expiresAt in response\"\n );\n }\n\n return {\n sessionToken: result.sessionToken,\n expiresAt: result.expiresAt,\n };\n}\n\n","import type {\n CheckBackendWalletBalanceParams,\n CheckBalanceResult,\n BalanceResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Check backend wallet balance via relay service\n *\n * This function:\n * 1. Calls /api/relay/balance with operatorAddress and secretKey\n * 2. Returns balance information including sufficientBalance flag\n *\n * @param params - Balance check parameters\n * @returns Result with balance information\n * @throws Error if balance check fails\n */\nexport async function checkBackendWalletBalance(\n params: CheckBackendWalletBalanceParams\n): Promise<CheckBalanceResult> {\n const { apiUrl, chainId, operatorAddress, secretKey } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/balance`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Balance check endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as BalanceResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Balance check failed: ${(\"error\" in result ? result.error : null) || \"Unknown error\"}`\n );\n }\n\n return {\n backendWalletAddress: result.backendWalletAddress,\n balanceWei: result.balanceWei,\n balanceEth: result.balanceEth,\n sufficientBalance: result.sufficientBalance,\n minRequiredWei: result.minRequiredWei,\n minRequiredEth: result.minRequiredEth,\n };\n}\n\n","import type { Hash } from \"viem\";\nimport type {\n FundBackendWalletParams,\n RelayFundResult,\n FundResponse,\n VerifyFundResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Extract payment transaction hash from response headers\n */\nfunction extractPaymentTxHash(\n response: Response,\n httpClient: FundBackendWalletParams[\"httpClient\"]\n): string | null {\n try {\n const paymentResponse = httpClient.getPaymentSettleResponse(\n (name: string) => response.headers.get(name)\n );\n return paymentResponse?.transaction || paymentResponse?.txHash || null;\n } catch (error) {\n console.error(\"Failed to extract payment transaction hash:\", error);\n return null;\n }\n}\n\n/**\n * Determine if a verify error is retryable based on HTTP status and error message\n */\nfunction isRetryableVerifyError(\n statusCode: number,\n errorMessage: string\n): boolean {\n // 5xx = always retryable\n if (statusCode >= 500) return true;\n\n // 4xx = check for retryable patterns\n if (statusCode >= 400 && statusCode < 500) {\n const msg = errorMessage.toLowerCase();\n return (\n msg.includes(\"failed to fetch payment transaction\") ||\n msg.includes(\"treasury wallet has insufficient balance\") ||\n msg.includes(\"transferfailed\")\n );\n }\n\n return false;\n}\n\n/**\n * Retry /fund/verify with exponential backoff\n */\nasync function verifyFundWithRetry(\n apiUrl: string,\n paymentTxHash: Hash,\n operatorAddress: string,\n secretKey: string,\n chainId: number\n): Promise<VerifyFundResponse> {\n const maxRetries = 3;\n const initialDelayMs = 2000;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(`${apiUrl}/api/relay/fund/verify`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n chainId,\n paymentTxHash,\n operatorAddress,\n secretKey,\n }),\n });\n\n const data = (await response.json()) as VerifyFundResponse | ErrorResponse;\n\n if (response.ok && data.success) {\n return data as VerifyFundResponse;\n }\n\n const errorMessage = (data as ErrorResponse).error || \"Unknown error\";\n\n // Don't retry non-retryable errors\n if (!isRetryableVerifyError(response.status, errorMessage)) {\n throw new Error(`Fund verify failed: ${response.status} ${errorMessage}`);\n }\n\n // Last attempt failed\n if (attempt === maxRetries) {\n throw new Error(\n `Fund verify failed after ${maxRetries + 1} attempts: ${errorMessage}`\n );\n }\n\n // Wait before retry (exponential backoff)\n const delayMs = initialDelayMs * Math.pow(2, attempt);\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n\n throw new Error(\"Verify failed after all retries\");\n}\n\n/**\n * Fund backend wallet via x402 relay service\n *\n * This function:\n * 1. Calls /api/relay/[chainId]/fund with x402 payment (using fetchWithPayment)\n * 2. Extracts paymentTxHash from X-PAYMENT-RESPONSE header\n * 3. Waits for payment confirmation (2 seconds)\n * 4. Calls /api/relay/fund/verify to get backendWalletAddress\n * 5. Returns { paymentTxHash, backendWalletAddress }\n *\n * @param params - Funding parameters\n * @returns Result with paymentTxHash and backendWalletAddress\n * @throws Error if funding fails\n */\nexport async function fundBackendWallet(\n params: FundBackendWalletParams\n): Promise<RelayFundResult> {\n const {\n apiUrl,\n operatorAddress,\n secretKey,\n fetchWithPayment,\n httpClient,\n chainId,\n } = params;\n\n const fundUrl = `${apiUrl}/api/relay/${chainId}/fund`;\n\n console.log(\"💰 Funding backend wallet\", {\n url: fundUrl,\n chainId,\n operatorAddress,\n facilitator:\n chainId === 8453\n ? \"Coinbase CDP (Base Mainnet)\"\n : chainId === 84532\n ? \"x402.org (Base Sepolia)\"\n : \"unknown\",\n });\n\n // Step 1: Call /api/relay/[chainId]/fund (Payment)\n let fundResponse: Response;\n try {\n fundResponse = await fetchWithPayment(fundUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n } catch (error) {\n console.error(\"❌ Fund request failed\", {\n error: error instanceof Error ? error.message : String(error),\n chainId,\n url: fundUrl,\n });\n throw error;\n }\n\n const fundData = (await fundResponse.json()) as FundResponse | ErrorResponse;\n\n // Handle 402 Payment Required\n if (fundResponse.status === 402) {\n // Check if payment was actually processed despite 402\n if (\"payer\" in fundData && fundData.payer) {\n // Payment appears to have been processed\n } else if (\"success\" in fundData && fundData.success) {\n // Payment appears to have been processed\n } else {\n throw new Error(\n `Fund endpoint returned 402 Payment Required: ${JSON.stringify(\n fundData\n )}`\n );\n }\n } else if (!fundResponse.ok) {\n throw new Error(\n `Fund endpoint failed: ${fundResponse.status} ${JSON.stringify(fundData)}`\n );\n }\n\n // Extract payment transaction hash from response headers\n const paymentTxHash = extractPaymentTxHash(fundResponse, httpClient);\n\n if (!paymentTxHash) {\n throw new Error(\n \"Failed to extract payment transaction hash from payment response headers\"\n );\n }\n\n // Step 2: Wait for payment confirmation\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Step 3: Call /api/relay/fund/verify with retry logic\n const verifyData = await verifyFundWithRetry(\n apiUrl,\n paymentTxHash as Hash,\n operatorAddress,\n secretKey,\n chainId\n );\n\n console.log(\"✓ Payment verified and backend wallet funded\", {\n backendWalletAddress: verifyData.backendWalletAddress,\n });\n\n if (!verifyData.backendWalletAddress) {\n throw new Error(\"Backend wallet address not found in verify response\");\n }\n\n return {\n paymentTxHash: paymentTxHash as Hash,\n backendWalletAddress: verifyData.backendWalletAddress,\n };\n}\n","import type { Hash, Address } from \"viem\";\nimport type {\n SubmitTransactionsViaRelayParams,\n RelaySubmitResult,\n SubmitResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Submit transactions via relay service\n *\n * Calls /api/relay/submit with transactions and returns result\n * with success/failure tracking by index.\n *\n * @param params - Submission parameters\n * @returns Result with transaction hashes and success/failure tracking\n * @throws Error if submission fails\n */\nexport async function submitTransactionsViaRelay(\n params: SubmitTransactionsViaRelayParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions,\n sessionToken,\n } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/submit`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n transactions: transactions.map((tx) => ({\n ...tx,\n // Only include value if it exists and is > 0\n ...(tx.value !== undefined && tx.value > BigInt(0)\n ? { value: tx.value.toString() }\n : {}),\n })),\n sessionToken,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Relay submit endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as SubmitResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Relay submit failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n return {\n transactionHashes: result.transactionHashes.map((h: string) => h as Hash),\n successfulIndexes: result.successfulIndexes || [],\n failedIndexes: result.failedIndexes || [],\n errors: result.errors || [],\n backendWalletAddress: result.backendWalletAddress as Address,\n appFeeTransactionHash: result.appFeeTransactionHash as Hash,\n };\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport type { Address } from \"viem\";\nimport type {\n RetryFailedTransactionsParams,\n RetryConfig,\n RelaySubmitResult,\n} from \"./types\";\nimport { DEFAULT_RETRY_CONFIG } from \"./constants\";\nimport { submitTransactionsViaRelay } from \"./submit\";\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for exponential backoff\n */\nfunction calculateDelay(\n attempt: number,\n config: Required<RetryConfig>\n): number {\n const delay =\n config.initialDelay * Math.pow(config.backoffMultiplier, attempt);\n return Math.min(delay, config.maxDelay);\n}\n\n/**\n * Retry failed transactions with exponential backoff\n *\n * This function:\n * 1. Extracts failed transactions by index from RelaySubmitResult\n * 2. Optionally re-checks on-chain before retry (via recheckFunction)\n * 3. Retries with exponential backoff\n * 4. Handles nested retries\n *\n * @param params - Retry parameters\n * @returns Final success/failure status after retries\n */\nexport async function retryFailedTransactions(\n params: RetryFailedTransactionsParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n failedIndexes: initialFailedIndexes,\n originalTransactions,\n backendWalletAddress,\n config = {},\n sessionToken,\n recheckFunction,\n } = params;\n\n const retryConfig: Required<RetryConfig> = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let failedIndexes = initialFailedIndexes;\n let attempt = 0;\n let lastResult: RelaySubmitResult | null = null;\n\n while (failedIndexes.length > 0 && attempt < retryConfig.maxRetries) {\n attempt++;\n\n // Re-check on-chain before retry (if recheckFunction provided)\n if (recheckFunction) {\n failedIndexes = await recheckFunction(\n failedIndexes,\n originalTransactions,\n backendWalletAddress\n );\n }\n\n if (failedIndexes.length === 0) {\n // All transactions have succeeded\n break;\n }\n\n // Calculate delay for exponential backoff\n const delay = calculateDelay(attempt - 1, retryConfig);\n if (attempt > 1) {\n // Don't delay on first attempt\n await sleep(delay);\n }\n\n // Extract failed transactions\n const failedTransactions = failedIndexes.map(\n (idx) => originalTransactions[idx]\n );\n\n // Retry failed transactions\n try {\n const retryResult = await submitTransactionsViaRelay({\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions: failedTransactions,\n sessionToken,\n });\n\n // Merge results\n if (lastResult) {\n // Combine transaction hashes\n lastResult.transactionHashes.push(...retryResult.transactionHashes);\n // Combine successful indexes (adjust for original index)\n lastResult.successfulIndexes.push(\n ...retryResult.successfulIndexes.map((idx) => failedIndexes[idx])\n );\n // Update failed indexes\n lastResult.failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n // Combine errors\n lastResult.errors.push(\n ...retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n }))\n );\n } else {\n lastResult = {\n ...retryResult,\n successfulIndexes: retryResult.successfulIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n failedIndexes: retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n errors: retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n })),\n };\n }\n\n // Update failed indexes for next iteration\n failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n } catch (error) {\n // Retry failed, keep current failed indexes\n console.error(`Retry attempt ${attempt} failed:`, error);\n }\n }\n\n if (!lastResult) {\n throw new Error(\"Retry failed: No result after retries\");\n }\n\n return lastResult;\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport {\n MAX_TRANSACTIONS_PER_BATCH,\n MAX_BATCH_SIZE_BYTES,\n MAX_TRANSACTION_SIZE_BYTES,\n} from \"./constants\";\n\n/**\n * Estimate the size of a serialized transaction config in bytes\n *\n * Storage transactions can be large due to:\n * - Large args arrays (chunk data)\n * - Hex-encoded data in args\n * - Full ABI included in each transaction (can be 2-3KB)\n *\n * The entire transaction object is serialized to JSON, including the ABI,\n * so we must account for all fields.\n */\nexport function estimateTransactionSize(tx: WriteTransactionConfig): number {\n // Measure actual sizes of serialized fields\n const argsSize = tx.args ? JSON.stringify(tx.args).length : 0;\n const abiSize = tx.abi ? JSON.stringify(tx.abi).length : 0;\n \n // Add overhead for: to (~44 bytes), functionName (~20 bytes), \n // JSON structure/keys (~100 bytes)\n const overhead = 200;\n\n // Cap at MAX_TRANSACTION_SIZE_BYTES to prevent single transaction from exceeding batch limit\n return Math.min(\n argsSize + abiSize + overhead,\n MAX_TRANSACTION_SIZE_BYTES\n );\n}\n\n/**\n * Estimate the total request size for a batch of transactions\n */\nexport function estimateRequestSize(\n transactions: WriteTransactionConfig[]\n): number {\n // Base overhead: operatorAddress (~42 bytes),\n // secretKey (~50-200 bytes), JSON structure (~100 bytes)\n const baseOverhead = 300;\n const transactionsSize = transactions.reduce(\n (sum, tx) => sum + estimateTransactionSize(tx),\n 0\n );\n return baseOverhead + transactionsSize;\n}\n\n/**\n * Batch transactions into groups that respect count and size limits\n *\n * With 100KB per transaction estimate:\n * - Size limit: ~9 transactions per batch (900KB / 100KB)\n * - Count limit: 100 transactions per batch\n * - Size limit is the constraining factor for large transactions\n */\nexport function batchTransactions(\n transactions: WriteTransactionConfig[]\n): WriteTransactionConfig[][] {\n const batches: WriteTransactionConfig[][] = [];\n let currentBatch: WriteTransactionConfig[] = [];\n\n for (const tx of transactions) {\n // Calculate what the batch size would be with this transaction added\n const batchWithTx = [...currentBatch, tx];\n const estimatedSize = estimateRequestSize(batchWithTx);\n\n // Check if adding this transaction would exceed limits\n // Size limit is typically the constraining factor (9 transactions @ 100KB each)\n if (\n currentBatch.length >= MAX_TRANSACTIONS_PER_BATCH ||\n estimatedSize > MAX_BATCH_SIZE_BYTES\n ) {\n // Start a new batch\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n }\n }\n\n // If a single transaction exceeds the batch size limit, we still add it\n // (it will be its own batch, and the server will reject it with a clear error)\n currentBatch.push(tx);\n }\n\n // Add the last batch if it has transactions\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n","import { waitForTransactionReceipt } from \"viem/actions\";\nimport type { Hash } from \"viem\";\nimport type {\n WaitForConfirmationsParams,\n ConfirmationResult,\n} from \"./types\";\nimport { DEFAULT_CONFIRMATIONS, DEFAULT_TIMEOUT } from \"./constants\";\n\n/**\n * Wait for transaction confirmations\n *\n * Uses waitForTransactionReceipt() from viem/actions to wait for\n * multiple transactions in parallel. Handles timeouts and tracks progress.\n *\n * @param params - Confirmation parameters\n * @returns Array of transaction receipts\n * @throws Error if timeout occurs or transaction fails\n */\nexport async function waitForConfirmations(\n params: WaitForConfirmationsParams\n): Promise<ConfirmationResult[]> {\n const {\n publicClient,\n transactionHashes,\n confirmations = DEFAULT_CONFIRMATIONS,\n timeout = DEFAULT_TIMEOUT,\n onProgress,\n } = params;\n\n if (transactionHashes.length === 0) {\n return [];\n }\n\n const results: ConfirmationResult[] = [];\n let confirmed = 0;\n\n // Wait for all transactions in parallel\n const promises = transactionHashes.map(async (hash) => {\n try {\n const receipt = await waitForTransactionReceipt(publicClient, {\n hash,\n confirmations,\n timeout,\n });\n\n confirmed++;\n if (onProgress) {\n onProgress(confirmed, transactionHashes.length);\n }\n\n return { hash, receipt };\n } catch (error) {\n // Transaction failed or timed out\n throw new Error(\n `Transaction ${hash} failed or timed out: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n });\n\n // Wait for all promises\n const receipts = await Promise.all(promises);\n\n return receipts;\n}\n\n","import { x402Client, wrapFetchWithPayment, x402HTTPClient } from \"@x402/fetch\";\nimport { registerExactEvmScheme } from \"@x402/evm/exact/client\";\nimport type { LocalAccount } from \"viem/accounts\";\nimport type { X402ClientResult } from \"../types\";\n\n/**\n * Create x402 client for relay payments\n *\n * Sets up x402Client with user's account, registers EVM scheme,\n * and returns wrapped fetch function and HTTP client for header extraction.\n *\n * @param account - User's local account (from privateKeyToAccount)\n * @param chainId - Chain ID (optional, for logging purposes)\n * @returns Object with fetchWithPayment and httpClient\n */\nexport function createRelayX402Client(\n account: LocalAccount,\n chainId?: number\n): X402ClientResult {\n const client = new x402Client();\n registerExactEvmScheme(client, { signer: account });\n const fetchWithPayment = wrapFetchWithPayment(fetch, client);\n const httpClient = new x402HTTPClient(client);\n\n return { fetchWithPayment, httpClient };\n}\n\n","import type { LocalAccount, Address } from \"viem/accounts\";\nimport type { PublicClient, Hash } from \"viem\";\nimport type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport { createRelaySession } from \"../session\";\nimport { checkBackendWalletBalance } from \"../balance\";\nimport { fundBackendWallet } from \"../fund\";\nimport { submitTransactionsViaRelay } from \"../submit\";\nimport { retryFailedTransactions } from \"../retry\";\nimport { createRelayX402Client } from \"./x402Client\";\nimport type {\n CheckBalanceResult,\n RelayFundResult,\n RelaySubmitResult,\n RetryFailedTransactionsParams,\n RetryConfig,\n FundBackendWalletParams,\n SubmitTransactionsViaRelayParams,\n} from \"../types\";\n\n/**\n * High-level client for Net Relay Service\n *\n * Provides a convenient class-based API that stores apiUrl and chainId,\n * reducing boilerplate when making multiple relay calls.\n */\nexport class RelayClient {\n private apiUrl: string;\n private chainId: number;\n\n constructor(options: { apiUrl: string; chainId: number }) {\n this.apiUrl = options.apiUrl;\n this.chainId = options.chainId;\n }\n\n /**\n * Create a relay session token\n *\n * @param params - Session creation parameters (apiUrl and chainId are already set)\n * @returns Session token and expiration timestamp\n */\n async createSession(params: {\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number;\n }): Promise<{ sessionToken: string; expiresAt: number }> {\n return createRelaySession({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Check backend wallet balance\n *\n * @param params - Balance check parameters (apiUrl and chainId are already set)\n * @returns Result with balance information\n */\n async checkBalance(params: {\n operatorAddress: Address;\n secretKey: string;\n }): Promise<CheckBalanceResult> {\n return checkBackendWalletBalance({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Fund backend wallet via x402 payment\n *\n * @param params - Funding parameters (apiUrl and chainId are already set)\n * @returns Result with paymentTxHash and backendWalletAddress\n */\n async fundBackendWallet(params: {\n operatorAddress: Address;\n secretKey: string;\n fetchWithPayment: typeof fetch;\n httpClient: FundBackendWalletParams[\"httpClient\"];\n }): Promise<RelayFundResult> {\n return fundBackendWallet({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Submit transactions via relay\n *\n * @param params - Submission parameters (apiUrl and chainId are already set)\n * @returns Result with transaction hashes and success/failure tracking\n */\n async submitTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n transactions: WriteTransactionConfig[];\n sessionToken: string;\n }): Promise<RelaySubmitResult> {\n return submitTransactionsViaRelay({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Retry failed transactions with exponential backoff\n *\n * @param params - Retry parameters (apiUrl and chainId are already set)\n * @returns Final success/failure status after retries\n */\n async retryFailedTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n failedIndexes: number[];\n originalTransactions: WriteTransactionConfig[];\n backendWalletAddress: Address;\n config?: RetryConfig;\n sessionToken: string;\n recheckFunction?: RetryFailedTransactionsParams[\"recheckFunction\"];\n }): Promise<RelaySubmitResult> {\n return retryFailedTransactions({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Create x402 client for relay payments\n *\n * @param account - User's local account\n * @returns Object with fetchWithPayment and httpClient\n */\n createX402Client(account: LocalAccount) {\n return createRelayX402Client(account, this.chainId);\n }\n}\n\n"]}
package/dist/index.mjs CHANGED
@@ -25,7 +25,7 @@ var DEFAULT_CONFIRMATIONS = 1;
25
25
  var DEFAULT_TIMEOUT = 6e4;
26
26
  var MAX_TRANSACTIONS_PER_BATCH = 100;
27
27
  var MAX_BATCH_SIZE_BYTES = 900 * 1024;
28
- var MAX_TRANSACTION_SIZE_BYTES = 100 * 1024;
28
+ var MAX_TRANSACTION_SIZE_BYTES = 250 * 1024;
29
29
 
30
30
  // src/session.ts
31
31
  async function createRelaySession(params) {
@@ -136,6 +136,46 @@ function extractPaymentTxHash(response, httpClient) {
136
136
  return null;
137
137
  }
138
138
  }
139
+ function isRetryableVerifyError(statusCode, errorMessage) {
140
+ if (statusCode >= 500) return true;
141
+ if (statusCode >= 400 && statusCode < 500) {
142
+ const msg = errorMessage.toLowerCase();
143
+ return msg.includes("failed to fetch payment transaction") || msg.includes("treasury wallet has insufficient balance") || msg.includes("transferfailed");
144
+ }
145
+ return false;
146
+ }
147
+ async function verifyFundWithRetry(apiUrl, paymentTxHash, operatorAddress, secretKey, chainId) {
148
+ const maxRetries = 3;
149
+ const initialDelayMs = 2e3;
150
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
151
+ const response = await fetch(`${apiUrl}/api/relay/fund/verify`, {
152
+ method: "POST",
153
+ headers: { "Content-Type": "application/json" },
154
+ body: JSON.stringify({
155
+ chainId,
156
+ paymentTxHash,
157
+ operatorAddress,
158
+ secretKey
159
+ })
160
+ });
161
+ const data = await response.json();
162
+ if (response.ok && data.success) {
163
+ return data;
164
+ }
165
+ const errorMessage = data.error || "Unknown error";
166
+ if (!isRetryableVerifyError(response.status, errorMessage)) {
167
+ throw new Error(`Fund verify failed: ${response.status} ${errorMessage}`);
168
+ }
169
+ if (attempt === maxRetries) {
170
+ throw new Error(
171
+ `Fund verify failed after ${maxRetries + 1} attempts: ${errorMessage}`
172
+ );
173
+ }
174
+ const delayMs = initialDelayMs * Math.pow(2, attempt);
175
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
176
+ }
177
+ throw new Error("Verify failed after all retries");
178
+ }
139
179
  async function fundBackendWallet(params) {
140
180
  const {
141
181
  apiUrl,
@@ -194,33 +234,16 @@ async function fundBackendWallet(params) {
194
234
  );
195
235
  }
196
236
  await new Promise((resolve) => setTimeout(resolve, 2e3));
197
- const verifyFundResponse = await fetch(`${apiUrl}/api/relay/fund/verify`, {
198
- method: "POST",
199
- headers: {
200
- "Content-Type": "application/json"
201
- },
202
- body: JSON.stringify({
203
- chainId,
204
- paymentTxHash,
205
- operatorAddress,
206
- secretKey
207
- })
208
- });
209
- if (!verifyFundResponse.ok) {
210
- const errorData = await verifyFundResponse.json();
211
- throw new Error(
212
- `Fund verify endpoint failed: ${verifyFundResponse.status} ${JSON.stringify(errorData)}`
213
- );
214
- }
215
- const verifyData = await verifyFundResponse.json();
237
+ const verifyData = await verifyFundWithRetry(
238
+ apiUrl,
239
+ paymentTxHash,
240
+ operatorAddress,
241
+ secretKey,
242
+ chainId
243
+ );
216
244
  console.log("\u2713 Payment verified and backend wallet funded", {
217
245
  backendWalletAddress: verifyData.backendWalletAddress
218
246
  });
219
- if (!verifyData.success) {
220
- throw new Error(
221
- `Fund verify failed: ${verifyData.error || "Unknown error"}`
222
- );
223
- }
224
247
  if (!verifyData.backendWalletAddress) {
225
248
  throw new Error("Backend wallet address not found in verify response");
226
249
  }
@@ -382,9 +405,10 @@ async function retryFailedTransactions(params) {
382
405
  // src/batch.ts
383
406
  function estimateTransactionSize(tx) {
384
407
  const argsSize = tx.args ? JSON.stringify(tx.args).length : 0;
408
+ const abiSize = tx.abi ? JSON.stringify(tx.abi).length : 0;
409
+ const overhead = 200;
385
410
  return Math.min(
386
- argsSize + 1024,
387
- // args + overhead
411
+ argsSize + abiSize + overhead,
388
412
  MAX_TRANSACTION_SIZE_BYTES
389
413
  );
390
414
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/session.ts","../src/balance.ts","../src/fund.ts","../src/submit.ts","../src/retry.ts","../src/batch.ts","../src/confirmations.ts","../src/client/x402Client.ts","../src/client/RelayClient.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { RetryConfig } from \"./types\";\n\n/**\n * EIP-712 domain name for relay session signing\n */\nexport const RELAY_DOMAIN_NAME = \"Net Relay Service\";\n\n/**\n * EIP-712 domain version for relay session signing\n */\nexport const RELAY_DOMAIN_VERSION = \"1\";\n\n/**\n * EIP-712 types for relay session signing\n */\nexport const RELAY_SESSION_TYPES = {\n RelaySession: [\n { name: \"operatorAddress\", type: \"address\" },\n { name: \"secretKeyHash\", type: \"bytes32\" },\n { name: \"expiresAt\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * Default retry configuration\n */\nexport const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\n/**\n * Default number of confirmations to wait for\n */\nexport const DEFAULT_CONFIRMATIONS = 1;\n\n/**\n * Default timeout for waiting for transaction confirmations (milliseconds)\n */\nexport const DEFAULT_TIMEOUT = 60000; // 60 seconds\n\n/**\n * Maximum transactions per batch (matches server limit)\n */\nexport const MAX_TRANSACTIONS_PER_BATCH = 100;\n\n/**\n * Maximum request size in bytes (slightly under 1MB for safety margin)\n */\nexport const MAX_BATCH_SIZE_BYTES = 900 * 1024; // 900KB\n\n/**\n * Maximum size per transaction in bytes\n * Storage transactions can include large data chunks, so we assume up to 100KB per transaction\n */\nexport const MAX_TRANSACTION_SIZE_BYTES = 100 * 1024; // 100KB\n\n","import { keccak256, toBytes } from \"viem\";\nimport type { LocalAccount, Address } from \"viem/accounts\";\nimport {\n RELAY_DOMAIN_NAME,\n RELAY_DOMAIN_VERSION,\n RELAY_SESSION_TYPES,\n} from \"./constants\";\nimport type { CreateSessionResponse, ErrorResponse } from \"./types\";\n\n/**\n * Create a relay session token\n *\n * Signs an EIP-712 message proving ownership of operatorAddress\n * and receives a sessionToken that can be reused for multiple batch requests.\n *\n * @param params - Session creation parameters\n * @returns Session token and expiration timestamp\n * @throws Error if session creation fails\n */\nexport async function createRelaySession(params: {\n apiUrl: string;\n chainId: number;\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number; // seconds, default 3600\n}): Promise<{ sessionToken: string; expiresAt: number }> {\n const { apiUrl, chainId, operatorAddress, secretKey, account, expiresIn } =\n params;\n\n const expiresInSeconds = expiresIn || 3600; // Default 1 hour\n const expiresAt = Math.floor(Date.now() / 1000) + expiresInSeconds;\n const secretKeyHash = keccak256(toBytes(secretKey));\n\n const domain = {\n name: RELAY_DOMAIN_NAME,\n version: RELAY_DOMAIN_VERSION,\n chainId,\n };\n\n const message = {\n operatorAddress,\n secretKeyHash,\n expiresAt: BigInt(expiresAt),\n };\n\n // Sign the typed data using account's signTypedData method\n const signature = await account.signTypedData({\n domain,\n types: RELAY_SESSION_TYPES,\n primaryType: \"RelaySession\",\n message,\n });\n\n // Call session endpoint (send expiresAt - the exact value that was signed)\n const response = await fetch(`${apiUrl}/api/relay/session`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n signature,\n expiresAt, // Send the exact expiresAt that was signed\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Session creation failed: ${response.status} ${\n errorData.error || response.statusText\n }`\n );\n }\n\n const result = (await response.json()) as\n | CreateSessionResponse\n | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Session creation failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n if (!result.sessionToken || !result.expiresAt) {\n throw new Error(\n \"Session creation failed: Missing sessionToken or expiresAt in response\"\n );\n }\n\n return {\n sessionToken: result.sessionToken,\n expiresAt: result.expiresAt,\n };\n}\n\n","import type {\n CheckBackendWalletBalanceParams,\n CheckBalanceResult,\n BalanceResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Check backend wallet balance via relay service\n *\n * This function:\n * 1. Calls /api/relay/balance with operatorAddress and secretKey\n * 2. Returns balance information including sufficientBalance flag\n *\n * @param params - Balance check parameters\n * @returns Result with balance information\n * @throws Error if balance check fails\n */\nexport async function checkBackendWalletBalance(\n params: CheckBackendWalletBalanceParams\n): Promise<CheckBalanceResult> {\n const { apiUrl, chainId, operatorAddress, secretKey } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/balance`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Balance check endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as BalanceResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Balance check failed: ${(\"error\" in result ? result.error : null) || \"Unknown error\"}`\n );\n }\n\n return {\n backendWalletAddress: result.backendWalletAddress,\n balanceWei: result.balanceWei,\n balanceEth: result.balanceEth,\n sufficientBalance: result.sufficientBalance,\n minRequiredWei: result.minRequiredWei,\n minRequiredEth: result.minRequiredEth,\n };\n}\n\n","import type { Hash } from \"viem\";\nimport type {\n FundBackendWalletParams,\n RelayFundResult,\n FundResponse,\n VerifyFundResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Extract payment transaction hash from response headers\n */\nfunction extractPaymentTxHash(\n response: Response,\n httpClient: FundBackendWalletParams[\"httpClient\"]\n): string | null {\n try {\n const paymentResponse = httpClient.getPaymentSettleResponse(\n (name: string) => response.headers.get(name)\n );\n return paymentResponse?.transaction || paymentResponse?.txHash || null;\n } catch (error) {\n console.error(\"Failed to extract payment transaction hash:\", error);\n return null;\n }\n}\n\n/**\n * Fund backend wallet via x402 relay service\n *\n * This function:\n * 1. Calls /api/relay/[chainId]/fund with x402 payment (using fetchWithPayment)\n * 2. Extracts paymentTxHash from X-PAYMENT-RESPONSE header\n * 3. Waits for payment confirmation (2 seconds)\n * 4. Calls /api/relay/fund/verify to get backendWalletAddress\n * 5. Returns { paymentTxHash, backendWalletAddress }\n *\n * @param params - Funding parameters\n * @returns Result with paymentTxHash and backendWalletAddress\n * @throws Error if funding fails\n */\nexport async function fundBackendWallet(\n params: FundBackendWalletParams\n): Promise<RelayFundResult> {\n const {\n apiUrl,\n operatorAddress,\n secretKey,\n fetchWithPayment,\n httpClient,\n chainId,\n } = params;\n\n const fundUrl = `${apiUrl}/api/relay/${chainId}/fund`;\n\n console.log(\"💰 Funding backend wallet\", {\n url: fundUrl,\n chainId,\n operatorAddress,\n facilitator:\n chainId === 8453\n ? \"Coinbase CDP (Base Mainnet)\"\n : chainId === 84532\n ? \"x402.org (Base Sepolia)\"\n : \"unknown\",\n });\n\n // Step 1: Call /api/relay/[chainId]/fund (Payment)\n let fundResponse: Response;\n try {\n fundResponse = await fetchWithPayment(fundUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n } catch (error) {\n console.error(\"❌ Fund request failed\", {\n error: error instanceof Error ? error.message : String(error),\n chainId,\n url: fundUrl,\n });\n throw error;\n }\n\n const fundData = (await fundResponse.json()) as FundResponse | ErrorResponse;\n\n // Handle 402 Payment Required\n if (fundResponse.status === 402) {\n // Check if payment was actually processed despite 402\n if (\"payer\" in fundData && fundData.payer) {\n // Payment appears to have been processed\n } else if (\"success\" in fundData && fundData.success) {\n // Payment appears to have been processed\n } else {\n throw new Error(\n `Fund endpoint returned 402 Payment Required: ${JSON.stringify(\n fundData\n )}`\n );\n }\n } else if (!fundResponse.ok) {\n throw new Error(\n `Fund endpoint failed: ${fundResponse.status} ${JSON.stringify(fundData)}`\n );\n }\n\n // Extract payment transaction hash from response headers\n const paymentTxHash = extractPaymentTxHash(fundResponse, httpClient);\n\n if (!paymentTxHash) {\n throw new Error(\n \"Failed to extract payment transaction hash from payment response headers\"\n );\n }\n\n // Step 2: Wait for payment confirmation\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Step 3: Call /api/relay/fund/verify (Verification & Funding)\n const verifyFundResponse = await fetch(`${apiUrl}/api/relay/fund/verify`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n paymentTxHash: paymentTxHash as Hash,\n operatorAddress,\n secretKey,\n }),\n });\n\n if (!verifyFundResponse.ok) {\n const errorData = (await verifyFundResponse.json()) as ErrorResponse;\n throw new Error(\n `Fund verify endpoint failed: ${\n verifyFundResponse.status\n } ${JSON.stringify(errorData)}`\n );\n }\n\n const verifyData = (await verifyFundResponse.json()) as VerifyFundResponse;\n console.log(\"✓ Payment verified and backend wallet funded\", {\n backendWalletAddress: verifyData.backendWalletAddress,\n });\n\n if (!verifyData.success) {\n throw new Error(\n `Fund verify failed: ${verifyData.error || \"Unknown error\"}`\n );\n }\n\n if (!verifyData.backendWalletAddress) {\n throw new Error(\"Backend wallet address not found in verify response\");\n }\n\n return {\n paymentTxHash: paymentTxHash as Hash,\n backendWalletAddress: verifyData.backendWalletAddress,\n };\n}\n\n","import type { Hash, Address } from \"viem\";\nimport type {\n SubmitTransactionsViaRelayParams,\n RelaySubmitResult,\n SubmitResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Submit transactions via relay service\n *\n * Calls /api/relay/submit with transactions and returns result\n * with success/failure tracking by index.\n *\n * @param params - Submission parameters\n * @returns Result with transaction hashes and success/failure tracking\n * @throws Error if submission fails\n */\nexport async function submitTransactionsViaRelay(\n params: SubmitTransactionsViaRelayParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions,\n sessionToken,\n } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/submit`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n transactions: transactions.map((tx) => ({\n ...tx,\n // Only include value if it exists and is > 0\n ...(tx.value !== undefined && tx.value > BigInt(0)\n ? { value: tx.value.toString() }\n : {}),\n })),\n sessionToken,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Relay submit endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as SubmitResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Relay submit failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n return {\n transactionHashes: result.transactionHashes.map((h: string) => h as Hash),\n successfulIndexes: result.successfulIndexes || [],\n failedIndexes: result.failedIndexes || [],\n errors: result.errors || [],\n backendWalletAddress: result.backendWalletAddress as Address,\n appFeeTransactionHash: result.appFeeTransactionHash as Hash,\n };\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport type { Address } from \"viem\";\nimport type {\n RetryFailedTransactionsParams,\n RetryConfig,\n RelaySubmitResult,\n} from \"./types\";\nimport { DEFAULT_RETRY_CONFIG } from \"./constants\";\nimport { submitTransactionsViaRelay } from \"./submit\";\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for exponential backoff\n */\nfunction calculateDelay(\n attempt: number,\n config: Required<RetryConfig>\n): number {\n const delay =\n config.initialDelay * Math.pow(config.backoffMultiplier, attempt);\n return Math.min(delay, config.maxDelay);\n}\n\n/**\n * Retry failed transactions with exponential backoff\n *\n * This function:\n * 1. Extracts failed transactions by index from RelaySubmitResult\n * 2. Optionally re-checks on-chain before retry (via recheckFunction)\n * 3. Retries with exponential backoff\n * 4. Handles nested retries\n *\n * @param params - Retry parameters\n * @returns Final success/failure status after retries\n */\nexport async function retryFailedTransactions(\n params: RetryFailedTransactionsParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n failedIndexes: initialFailedIndexes,\n originalTransactions,\n backendWalletAddress,\n config = {},\n sessionToken,\n recheckFunction,\n } = params;\n\n const retryConfig: Required<RetryConfig> = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let failedIndexes = initialFailedIndexes;\n let attempt = 0;\n let lastResult: RelaySubmitResult | null = null;\n\n while (failedIndexes.length > 0 && attempt < retryConfig.maxRetries) {\n attempt++;\n\n // Re-check on-chain before retry (if recheckFunction provided)\n if (recheckFunction) {\n failedIndexes = await recheckFunction(\n failedIndexes,\n originalTransactions,\n backendWalletAddress\n );\n }\n\n if (failedIndexes.length === 0) {\n // All transactions have succeeded\n break;\n }\n\n // Calculate delay for exponential backoff\n const delay = calculateDelay(attempt - 1, retryConfig);\n if (attempt > 1) {\n // Don't delay on first attempt\n await sleep(delay);\n }\n\n // Extract failed transactions\n const failedTransactions = failedIndexes.map(\n (idx) => originalTransactions[idx]\n );\n\n // Retry failed transactions\n try {\n const retryResult = await submitTransactionsViaRelay({\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions: failedTransactions,\n sessionToken,\n });\n\n // Merge results\n if (lastResult) {\n // Combine transaction hashes\n lastResult.transactionHashes.push(...retryResult.transactionHashes);\n // Combine successful indexes (adjust for original index)\n lastResult.successfulIndexes.push(\n ...retryResult.successfulIndexes.map((idx) => failedIndexes[idx])\n );\n // Update failed indexes\n lastResult.failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n // Combine errors\n lastResult.errors.push(\n ...retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n }))\n );\n } else {\n lastResult = {\n ...retryResult,\n successfulIndexes: retryResult.successfulIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n failedIndexes: retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n errors: retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n })),\n };\n }\n\n // Update failed indexes for next iteration\n failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n } catch (error) {\n // Retry failed, keep current failed indexes\n console.error(`Retry attempt ${attempt} failed:`, error);\n }\n }\n\n if (!lastResult) {\n throw new Error(\"Retry failed: No result after retries\");\n }\n\n return lastResult;\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport {\n MAX_TRANSACTIONS_PER_BATCH,\n MAX_BATCH_SIZE_BYTES,\n MAX_TRANSACTION_SIZE_BYTES,\n} from \"./constants\";\n\n/**\n * Estimate the size of a serialized transaction config in bytes\n *\n * Storage transactions can be large due to:\n * - Large args arrays (chunk data)\n * - Hex-encoded data in args\n * - ABI structure overhead\n *\n * We use a conservative estimate of 100KB per transaction to ensure we stay under the 1MB limit.\n * With 100KB per transaction, we can fit ~9 transactions per batch (900KB / 100KB).\n */\nexport function estimateTransactionSize(tx: WriteTransactionConfig): number {\n // Estimate based on args size\n // Args can contain large hex-encoded data (chunks), so we assume up to 100KB\n // Add overhead for JSON structure, ABI, function name, etc. (~1KB)\n const argsSize = tx.args ? JSON.stringify(tx.args).length : 0;\n\n // Use the larger of: actual args size or conservative estimate\n // Cap at MAX_TRANSACTION_SIZE_BYTES to prevent single transaction from exceeding batch limit\n return Math.min(\n argsSize + 1024, // args + overhead\n MAX_TRANSACTION_SIZE_BYTES\n );\n}\n\n/**\n * Estimate the total request size for a batch of transactions\n */\nexport function estimateRequestSize(\n transactions: WriteTransactionConfig[]\n): number {\n // Base overhead: operatorAddress (~42 bytes),\n // secretKey (~50-200 bytes), JSON structure (~100 bytes)\n const baseOverhead = 300;\n const transactionsSize = transactions.reduce(\n (sum, tx) => sum + estimateTransactionSize(tx),\n 0\n );\n return baseOverhead + transactionsSize;\n}\n\n/**\n * Batch transactions into groups that respect count and size limits\n *\n * With 100KB per transaction estimate:\n * - Size limit: ~9 transactions per batch (900KB / 100KB)\n * - Count limit: 100 transactions per batch\n * - Size limit is the constraining factor for large transactions\n */\nexport function batchTransactions(\n transactions: WriteTransactionConfig[]\n): WriteTransactionConfig[][] {\n const batches: WriteTransactionConfig[][] = [];\n let currentBatch: WriteTransactionConfig[] = [];\n\n for (const tx of transactions) {\n // Calculate what the batch size would be with this transaction added\n const batchWithTx = [...currentBatch, tx];\n const estimatedSize = estimateRequestSize(batchWithTx);\n\n // Check if adding this transaction would exceed limits\n // Size limit is typically the constraining factor (9 transactions @ 100KB each)\n if (\n currentBatch.length >= MAX_TRANSACTIONS_PER_BATCH ||\n estimatedSize > MAX_BATCH_SIZE_BYTES\n ) {\n // Start a new batch\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n }\n }\n\n // If a single transaction exceeds the batch size limit, we still add it\n // (it will be its own batch, and the server will reject it with a clear error)\n currentBatch.push(tx);\n }\n\n // Add the last batch if it has transactions\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n","import { waitForTransactionReceipt } from \"viem/actions\";\nimport type { Hash } from \"viem\";\nimport type {\n WaitForConfirmationsParams,\n ConfirmationResult,\n} from \"./types\";\nimport { DEFAULT_CONFIRMATIONS, DEFAULT_TIMEOUT } from \"./constants\";\n\n/**\n * Wait for transaction confirmations\n *\n * Uses waitForTransactionReceipt() from viem/actions to wait for\n * multiple transactions in parallel. Handles timeouts and tracks progress.\n *\n * @param params - Confirmation parameters\n * @returns Array of transaction receipts\n * @throws Error if timeout occurs or transaction fails\n */\nexport async function waitForConfirmations(\n params: WaitForConfirmationsParams\n): Promise<ConfirmationResult[]> {\n const {\n publicClient,\n transactionHashes,\n confirmations = DEFAULT_CONFIRMATIONS,\n timeout = DEFAULT_TIMEOUT,\n onProgress,\n } = params;\n\n if (transactionHashes.length === 0) {\n return [];\n }\n\n const results: ConfirmationResult[] = [];\n let confirmed = 0;\n\n // Wait for all transactions in parallel\n const promises = transactionHashes.map(async (hash) => {\n try {\n const receipt = await waitForTransactionReceipt(publicClient, {\n hash,\n confirmations,\n timeout,\n });\n\n confirmed++;\n if (onProgress) {\n onProgress(confirmed, transactionHashes.length);\n }\n\n return { hash, receipt };\n } catch (error) {\n // Transaction failed or timed out\n throw new Error(\n `Transaction ${hash} failed or timed out: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n });\n\n // Wait for all promises\n const receipts = await Promise.all(promises);\n\n return receipts;\n}\n\n","import { x402Client, wrapFetchWithPayment, x402HTTPClient } from \"@x402/fetch\";\nimport { registerExactEvmScheme } from \"@x402/evm/exact/client\";\nimport type { LocalAccount } from \"viem/accounts\";\nimport type { X402ClientResult } from \"../types\";\n\n/**\n * Create x402 client for relay payments\n *\n * Sets up x402Client with user's account, registers EVM scheme,\n * and returns wrapped fetch function and HTTP client for header extraction.\n *\n * @param account - User's local account (from privateKeyToAccount)\n * @param chainId - Chain ID (optional, for logging purposes)\n * @returns Object with fetchWithPayment and httpClient\n */\nexport function createRelayX402Client(\n account: LocalAccount,\n chainId?: number\n): X402ClientResult {\n const client = new x402Client();\n registerExactEvmScheme(client, { signer: account });\n const fetchWithPayment = wrapFetchWithPayment(fetch, client);\n const httpClient = new x402HTTPClient(client);\n\n return { fetchWithPayment, httpClient };\n}\n\n","import type { LocalAccount, Address } from \"viem/accounts\";\nimport type { PublicClient, Hash } from \"viem\";\nimport type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport { createRelaySession } from \"../session\";\nimport { checkBackendWalletBalance } from \"../balance\";\nimport { fundBackendWallet } from \"../fund\";\nimport { submitTransactionsViaRelay } from \"../submit\";\nimport { retryFailedTransactions } from \"../retry\";\nimport { createRelayX402Client } from \"./x402Client\";\nimport type {\n CheckBalanceResult,\n RelayFundResult,\n RelaySubmitResult,\n RetryFailedTransactionsParams,\n RetryConfig,\n FundBackendWalletParams,\n SubmitTransactionsViaRelayParams,\n} from \"../types\";\n\n/**\n * High-level client for Net Relay Service\n *\n * Provides a convenient class-based API that stores apiUrl and chainId,\n * reducing boilerplate when making multiple relay calls.\n */\nexport class RelayClient {\n private apiUrl: string;\n private chainId: number;\n\n constructor(options: { apiUrl: string; chainId: number }) {\n this.apiUrl = options.apiUrl;\n this.chainId = options.chainId;\n }\n\n /**\n * Create a relay session token\n *\n * @param params - Session creation parameters (apiUrl and chainId are already set)\n * @returns Session token and expiration timestamp\n */\n async createSession(params: {\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number;\n }): Promise<{ sessionToken: string; expiresAt: number }> {\n return createRelaySession({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Check backend wallet balance\n *\n * @param params - Balance check parameters (apiUrl and chainId are already set)\n * @returns Result with balance information\n */\n async checkBalance(params: {\n operatorAddress: Address;\n secretKey: string;\n }): Promise<CheckBalanceResult> {\n return checkBackendWalletBalance({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Fund backend wallet via x402 payment\n *\n * @param params - Funding parameters (apiUrl and chainId are already set)\n * @returns Result with paymentTxHash and backendWalletAddress\n */\n async fundBackendWallet(params: {\n operatorAddress: Address;\n secretKey: string;\n fetchWithPayment: typeof fetch;\n httpClient: FundBackendWalletParams[\"httpClient\"];\n }): Promise<RelayFundResult> {\n return fundBackendWallet({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Submit transactions via relay\n *\n * @param params - Submission parameters (apiUrl and chainId are already set)\n * @returns Result with transaction hashes and success/failure tracking\n */\n async submitTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n transactions: WriteTransactionConfig[];\n sessionToken: string;\n }): Promise<RelaySubmitResult> {\n return submitTransactionsViaRelay({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Retry failed transactions with exponential backoff\n *\n * @param params - Retry parameters (apiUrl and chainId are already set)\n * @returns Final success/failure status after retries\n */\n async retryFailedTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n failedIndexes: number[];\n originalTransactions: WriteTransactionConfig[];\n backendWalletAddress: Address;\n config?: RetryConfig;\n sessionToken: string;\n recheckFunction?: RetryFailedTransactionsParams[\"recheckFunction\"];\n }): Promise<RelaySubmitResult> {\n return retryFailedTransactions({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Create x402 client for relay payments\n *\n * @param account - User's local account\n * @returns Object with fetchWithPayment and httpClient\n */\n createX402Client(account: LocalAccount) {\n return createRelayX402Client(account, this.chainId);\n }\n}\n\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/session.ts","../src/balance.ts","../src/fund.ts","../src/submit.ts","../src/retry.ts","../src/batch.ts","../src/confirmations.ts","../src/client/x402Client.ts","../src/client/RelayClient.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { RetryConfig } from \"./types\";\n\n/**\n * EIP-712 domain name for relay session signing\n */\nexport const RELAY_DOMAIN_NAME = \"Net Relay Service\";\n\n/**\n * EIP-712 domain version for relay session signing\n */\nexport const RELAY_DOMAIN_VERSION = \"1\";\n\n/**\n * EIP-712 types for relay session signing\n */\nexport const RELAY_SESSION_TYPES = {\n RelaySession: [\n { name: \"operatorAddress\", type: \"address\" },\n { name: \"secretKeyHash\", type: \"bytes32\" },\n { name: \"expiresAt\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * Default retry configuration\n */\nexport const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n};\n\n/**\n * Default number of confirmations to wait for\n */\nexport const DEFAULT_CONFIRMATIONS = 1;\n\n/**\n * Default timeout for waiting for transaction confirmations (milliseconds)\n */\nexport const DEFAULT_TIMEOUT = 60000; // 60 seconds\n\n/**\n * Maximum transactions per batch (matches server limit)\n */\nexport const MAX_TRANSACTIONS_PER_BATCH = 100;\n\n/**\n * Maximum request size in bytes (slightly under 1MB for safety margin)\n */\nexport const MAX_BATCH_SIZE_BYTES = 900 * 1024; // 900KB\n\n/**\n * Maximum size per transaction in bytes\n * Storage transactions can include large data chunks (up to ~200KB per transaction)\n * This cap prevents a single malformed transaction from blocking the entire batch\n */\nexport const MAX_TRANSACTION_SIZE_BYTES = 250 * 1024; // 250KB\n\n","import { keccak256, toBytes } from \"viem\";\nimport type { LocalAccount, Address } from \"viem/accounts\";\nimport {\n RELAY_DOMAIN_NAME,\n RELAY_DOMAIN_VERSION,\n RELAY_SESSION_TYPES,\n} from \"./constants\";\nimport type { CreateSessionResponse, ErrorResponse } from \"./types\";\n\n/**\n * Create a relay session token\n *\n * Signs an EIP-712 message proving ownership of operatorAddress\n * and receives a sessionToken that can be reused for multiple batch requests.\n *\n * @param params - Session creation parameters\n * @returns Session token and expiration timestamp\n * @throws Error if session creation fails\n */\nexport async function createRelaySession(params: {\n apiUrl: string;\n chainId: number;\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number; // seconds, default 3600\n}): Promise<{ sessionToken: string; expiresAt: number }> {\n const { apiUrl, chainId, operatorAddress, secretKey, account, expiresIn } =\n params;\n\n const expiresInSeconds = expiresIn || 3600; // Default 1 hour\n const expiresAt = Math.floor(Date.now() / 1000) + expiresInSeconds;\n const secretKeyHash = keccak256(toBytes(secretKey));\n\n const domain = {\n name: RELAY_DOMAIN_NAME,\n version: RELAY_DOMAIN_VERSION,\n chainId,\n };\n\n const message = {\n operatorAddress,\n secretKeyHash,\n expiresAt: BigInt(expiresAt),\n };\n\n // Sign the typed data using account's signTypedData method\n const signature = await account.signTypedData({\n domain,\n types: RELAY_SESSION_TYPES,\n primaryType: \"RelaySession\",\n message,\n });\n\n // Call session endpoint (send expiresAt - the exact value that was signed)\n const response = await fetch(`${apiUrl}/api/relay/session`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n signature,\n expiresAt, // Send the exact expiresAt that was signed\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Session creation failed: ${response.status} ${\n errorData.error || response.statusText\n }`\n );\n }\n\n const result = (await response.json()) as\n | CreateSessionResponse\n | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Session creation failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n if (!result.sessionToken || !result.expiresAt) {\n throw new Error(\n \"Session creation failed: Missing sessionToken or expiresAt in response\"\n );\n }\n\n return {\n sessionToken: result.sessionToken,\n expiresAt: result.expiresAt,\n };\n}\n\n","import type {\n CheckBackendWalletBalanceParams,\n CheckBalanceResult,\n BalanceResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Check backend wallet balance via relay service\n *\n * This function:\n * 1. Calls /api/relay/balance with operatorAddress and secretKey\n * 2. Returns balance information including sufficientBalance flag\n *\n * @param params - Balance check parameters\n * @returns Result with balance information\n * @throws Error if balance check fails\n */\nexport async function checkBackendWalletBalance(\n params: CheckBackendWalletBalanceParams\n): Promise<CheckBalanceResult> {\n const { apiUrl, chainId, operatorAddress, secretKey } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/balance`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Balance check endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as BalanceResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Balance check failed: ${(\"error\" in result ? result.error : null) || \"Unknown error\"}`\n );\n }\n\n return {\n backendWalletAddress: result.backendWalletAddress,\n balanceWei: result.balanceWei,\n balanceEth: result.balanceEth,\n sufficientBalance: result.sufficientBalance,\n minRequiredWei: result.minRequiredWei,\n minRequiredEth: result.minRequiredEth,\n };\n}\n\n","import type { Hash } from \"viem\";\nimport type {\n FundBackendWalletParams,\n RelayFundResult,\n FundResponse,\n VerifyFundResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Extract payment transaction hash from response headers\n */\nfunction extractPaymentTxHash(\n response: Response,\n httpClient: FundBackendWalletParams[\"httpClient\"]\n): string | null {\n try {\n const paymentResponse = httpClient.getPaymentSettleResponse(\n (name: string) => response.headers.get(name)\n );\n return paymentResponse?.transaction || paymentResponse?.txHash || null;\n } catch (error) {\n console.error(\"Failed to extract payment transaction hash:\", error);\n return null;\n }\n}\n\n/**\n * Determine if a verify error is retryable based on HTTP status and error message\n */\nfunction isRetryableVerifyError(\n statusCode: number,\n errorMessage: string\n): boolean {\n // 5xx = always retryable\n if (statusCode >= 500) return true;\n\n // 4xx = check for retryable patterns\n if (statusCode >= 400 && statusCode < 500) {\n const msg = errorMessage.toLowerCase();\n return (\n msg.includes(\"failed to fetch payment transaction\") ||\n msg.includes(\"treasury wallet has insufficient balance\") ||\n msg.includes(\"transferfailed\")\n );\n }\n\n return false;\n}\n\n/**\n * Retry /fund/verify with exponential backoff\n */\nasync function verifyFundWithRetry(\n apiUrl: string,\n paymentTxHash: Hash,\n operatorAddress: string,\n secretKey: string,\n chainId: number\n): Promise<VerifyFundResponse> {\n const maxRetries = 3;\n const initialDelayMs = 2000;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(`${apiUrl}/api/relay/fund/verify`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n chainId,\n paymentTxHash,\n operatorAddress,\n secretKey,\n }),\n });\n\n const data = (await response.json()) as VerifyFundResponse | ErrorResponse;\n\n if (response.ok && data.success) {\n return data as VerifyFundResponse;\n }\n\n const errorMessage = (data as ErrorResponse).error || \"Unknown error\";\n\n // Don't retry non-retryable errors\n if (!isRetryableVerifyError(response.status, errorMessage)) {\n throw new Error(`Fund verify failed: ${response.status} ${errorMessage}`);\n }\n\n // Last attempt failed\n if (attempt === maxRetries) {\n throw new Error(\n `Fund verify failed after ${maxRetries + 1} attempts: ${errorMessage}`\n );\n }\n\n // Wait before retry (exponential backoff)\n const delayMs = initialDelayMs * Math.pow(2, attempt);\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n\n throw new Error(\"Verify failed after all retries\");\n}\n\n/**\n * Fund backend wallet via x402 relay service\n *\n * This function:\n * 1. Calls /api/relay/[chainId]/fund with x402 payment (using fetchWithPayment)\n * 2. Extracts paymentTxHash from X-PAYMENT-RESPONSE header\n * 3. Waits for payment confirmation (2 seconds)\n * 4. Calls /api/relay/fund/verify to get backendWalletAddress\n * 5. Returns { paymentTxHash, backendWalletAddress }\n *\n * @param params - Funding parameters\n * @returns Result with paymentTxHash and backendWalletAddress\n * @throws Error if funding fails\n */\nexport async function fundBackendWallet(\n params: FundBackendWalletParams\n): Promise<RelayFundResult> {\n const {\n apiUrl,\n operatorAddress,\n secretKey,\n fetchWithPayment,\n httpClient,\n chainId,\n } = params;\n\n const fundUrl = `${apiUrl}/api/relay/${chainId}/fund`;\n\n console.log(\"💰 Funding backend wallet\", {\n url: fundUrl,\n chainId,\n operatorAddress,\n facilitator:\n chainId === 8453\n ? \"Coinbase CDP (Base Mainnet)\"\n : chainId === 84532\n ? \"x402.org (Base Sepolia)\"\n : \"unknown\",\n });\n\n // Step 1: Call /api/relay/[chainId]/fund (Payment)\n let fundResponse: Response;\n try {\n fundResponse = await fetchWithPayment(fundUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n }),\n });\n } catch (error) {\n console.error(\"❌ Fund request failed\", {\n error: error instanceof Error ? error.message : String(error),\n chainId,\n url: fundUrl,\n });\n throw error;\n }\n\n const fundData = (await fundResponse.json()) as FundResponse | ErrorResponse;\n\n // Handle 402 Payment Required\n if (fundResponse.status === 402) {\n // Check if payment was actually processed despite 402\n if (\"payer\" in fundData && fundData.payer) {\n // Payment appears to have been processed\n } else if (\"success\" in fundData && fundData.success) {\n // Payment appears to have been processed\n } else {\n throw new Error(\n `Fund endpoint returned 402 Payment Required: ${JSON.stringify(\n fundData\n )}`\n );\n }\n } else if (!fundResponse.ok) {\n throw new Error(\n `Fund endpoint failed: ${fundResponse.status} ${JSON.stringify(fundData)}`\n );\n }\n\n // Extract payment transaction hash from response headers\n const paymentTxHash = extractPaymentTxHash(fundResponse, httpClient);\n\n if (!paymentTxHash) {\n throw new Error(\n \"Failed to extract payment transaction hash from payment response headers\"\n );\n }\n\n // Step 2: Wait for payment confirmation\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Step 3: Call /api/relay/fund/verify with retry logic\n const verifyData = await verifyFundWithRetry(\n apiUrl,\n paymentTxHash as Hash,\n operatorAddress,\n secretKey,\n chainId\n );\n\n console.log(\"✓ Payment verified and backend wallet funded\", {\n backendWalletAddress: verifyData.backendWalletAddress,\n });\n\n if (!verifyData.backendWalletAddress) {\n throw new Error(\"Backend wallet address not found in verify response\");\n }\n\n return {\n paymentTxHash: paymentTxHash as Hash,\n backendWalletAddress: verifyData.backendWalletAddress,\n };\n}\n","import type { Hash, Address } from \"viem\";\nimport type {\n SubmitTransactionsViaRelayParams,\n RelaySubmitResult,\n SubmitResponse,\n ErrorResponse,\n} from \"./types\";\n\n/**\n * Submit transactions via relay service\n *\n * Calls /api/relay/submit with transactions and returns result\n * with success/failure tracking by index.\n *\n * @param params - Submission parameters\n * @returns Result with transaction hashes and success/failure tracking\n * @throws Error if submission fails\n */\nexport async function submitTransactionsViaRelay(\n params: SubmitTransactionsViaRelayParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions,\n sessionToken,\n } = params;\n\n const response = await fetch(`${apiUrl}/api/relay/submit`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n chainId,\n operatorAddress,\n secretKey,\n transactions: transactions.map((tx) => ({\n ...tx,\n // Only include value if it exists and is > 0\n ...(tx.value !== undefined && tx.value > BigInt(0)\n ? { value: tx.value.toString() }\n : {}),\n })),\n sessionToken,\n }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n throw new Error(\n `Relay submit endpoint failed: ${response.status} ${JSON.stringify(\n errorData\n )}`\n );\n }\n\n const result = (await response.json()) as SubmitResponse | ErrorResponse;\n if (!result.success || \"error\" in result) {\n throw new Error(\n `Relay submit failed: ${\n (\"error\" in result ? result.error : null) || \"Unknown error\"\n }`\n );\n }\n\n return {\n transactionHashes: result.transactionHashes.map((h: string) => h as Hash),\n successfulIndexes: result.successfulIndexes || [],\n failedIndexes: result.failedIndexes || [],\n errors: result.errors || [],\n backendWalletAddress: result.backendWalletAddress as Address,\n appFeeTransactionHash: result.appFeeTransactionHash as Hash,\n };\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport type { Address } from \"viem\";\nimport type {\n RetryFailedTransactionsParams,\n RetryConfig,\n RelaySubmitResult,\n} from \"./types\";\nimport { DEFAULT_RETRY_CONFIG } from \"./constants\";\nimport { submitTransactionsViaRelay } from \"./submit\";\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay for exponential backoff\n */\nfunction calculateDelay(\n attempt: number,\n config: Required<RetryConfig>\n): number {\n const delay =\n config.initialDelay * Math.pow(config.backoffMultiplier, attempt);\n return Math.min(delay, config.maxDelay);\n}\n\n/**\n * Retry failed transactions with exponential backoff\n *\n * This function:\n * 1. Extracts failed transactions by index from RelaySubmitResult\n * 2. Optionally re-checks on-chain before retry (via recheckFunction)\n * 3. Retries with exponential backoff\n * 4. Handles nested retries\n *\n * @param params - Retry parameters\n * @returns Final success/failure status after retries\n */\nexport async function retryFailedTransactions(\n params: RetryFailedTransactionsParams\n): Promise<RelaySubmitResult> {\n const {\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n failedIndexes: initialFailedIndexes,\n originalTransactions,\n backendWalletAddress,\n config = {},\n sessionToken,\n recheckFunction,\n } = params;\n\n const retryConfig: Required<RetryConfig> = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n let failedIndexes = initialFailedIndexes;\n let attempt = 0;\n let lastResult: RelaySubmitResult | null = null;\n\n while (failedIndexes.length > 0 && attempt < retryConfig.maxRetries) {\n attempt++;\n\n // Re-check on-chain before retry (if recheckFunction provided)\n if (recheckFunction) {\n failedIndexes = await recheckFunction(\n failedIndexes,\n originalTransactions,\n backendWalletAddress\n );\n }\n\n if (failedIndexes.length === 0) {\n // All transactions have succeeded\n break;\n }\n\n // Calculate delay for exponential backoff\n const delay = calculateDelay(attempt - 1, retryConfig);\n if (attempt > 1) {\n // Don't delay on first attempt\n await sleep(delay);\n }\n\n // Extract failed transactions\n const failedTransactions = failedIndexes.map(\n (idx) => originalTransactions[idx]\n );\n\n // Retry failed transactions\n try {\n const retryResult = await submitTransactionsViaRelay({\n apiUrl,\n chainId,\n operatorAddress,\n secretKey,\n transactions: failedTransactions,\n sessionToken,\n });\n\n // Merge results\n if (lastResult) {\n // Combine transaction hashes\n lastResult.transactionHashes.push(...retryResult.transactionHashes);\n // Combine successful indexes (adjust for original index)\n lastResult.successfulIndexes.push(\n ...retryResult.successfulIndexes.map((idx) => failedIndexes[idx])\n );\n // Update failed indexes\n lastResult.failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n // Combine errors\n lastResult.errors.push(\n ...retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n }))\n );\n } else {\n lastResult = {\n ...retryResult,\n successfulIndexes: retryResult.successfulIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n failedIndexes: retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n ),\n errors: retryResult.errors.map((err) => ({\n index: failedIndexes[err.index],\n error: err.error,\n })),\n };\n }\n\n // Update failed indexes for next iteration\n failedIndexes = retryResult.failedIndexes.map(\n (idx) => failedIndexes[idx]\n );\n } catch (error) {\n // Retry failed, keep current failed indexes\n console.error(`Retry attempt ${attempt} failed:`, error);\n }\n }\n\n if (!lastResult) {\n throw new Error(\"Retry failed: No result after retries\");\n }\n\n return lastResult;\n}\n\n","import type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport {\n MAX_TRANSACTIONS_PER_BATCH,\n MAX_BATCH_SIZE_BYTES,\n MAX_TRANSACTION_SIZE_BYTES,\n} from \"./constants\";\n\n/**\n * Estimate the size of a serialized transaction config in bytes\n *\n * Storage transactions can be large due to:\n * - Large args arrays (chunk data)\n * - Hex-encoded data in args\n * - Full ABI included in each transaction (can be 2-3KB)\n *\n * The entire transaction object is serialized to JSON, including the ABI,\n * so we must account for all fields.\n */\nexport function estimateTransactionSize(tx: WriteTransactionConfig): number {\n // Measure actual sizes of serialized fields\n const argsSize = tx.args ? JSON.stringify(tx.args).length : 0;\n const abiSize = tx.abi ? JSON.stringify(tx.abi).length : 0;\n \n // Add overhead for: to (~44 bytes), functionName (~20 bytes), \n // JSON structure/keys (~100 bytes)\n const overhead = 200;\n\n // Cap at MAX_TRANSACTION_SIZE_BYTES to prevent single transaction from exceeding batch limit\n return Math.min(\n argsSize + abiSize + overhead,\n MAX_TRANSACTION_SIZE_BYTES\n );\n}\n\n/**\n * Estimate the total request size for a batch of transactions\n */\nexport function estimateRequestSize(\n transactions: WriteTransactionConfig[]\n): number {\n // Base overhead: operatorAddress (~42 bytes),\n // secretKey (~50-200 bytes), JSON structure (~100 bytes)\n const baseOverhead = 300;\n const transactionsSize = transactions.reduce(\n (sum, tx) => sum + estimateTransactionSize(tx),\n 0\n );\n return baseOverhead + transactionsSize;\n}\n\n/**\n * Batch transactions into groups that respect count and size limits\n *\n * With 100KB per transaction estimate:\n * - Size limit: ~9 transactions per batch (900KB / 100KB)\n * - Count limit: 100 transactions per batch\n * - Size limit is the constraining factor for large transactions\n */\nexport function batchTransactions(\n transactions: WriteTransactionConfig[]\n): WriteTransactionConfig[][] {\n const batches: WriteTransactionConfig[][] = [];\n let currentBatch: WriteTransactionConfig[] = [];\n\n for (const tx of transactions) {\n // Calculate what the batch size would be with this transaction added\n const batchWithTx = [...currentBatch, tx];\n const estimatedSize = estimateRequestSize(batchWithTx);\n\n // Check if adding this transaction would exceed limits\n // Size limit is typically the constraining factor (9 transactions @ 100KB each)\n if (\n currentBatch.length >= MAX_TRANSACTIONS_PER_BATCH ||\n estimatedSize > MAX_BATCH_SIZE_BYTES\n ) {\n // Start a new batch\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n }\n }\n\n // If a single transaction exceeds the batch size limit, we still add it\n // (it will be its own batch, and the server will reject it with a clear error)\n currentBatch.push(tx);\n }\n\n // Add the last batch if it has transactions\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n","import { waitForTransactionReceipt } from \"viem/actions\";\nimport type { Hash } from \"viem\";\nimport type {\n WaitForConfirmationsParams,\n ConfirmationResult,\n} from \"./types\";\nimport { DEFAULT_CONFIRMATIONS, DEFAULT_TIMEOUT } from \"./constants\";\n\n/**\n * Wait for transaction confirmations\n *\n * Uses waitForTransactionReceipt() from viem/actions to wait for\n * multiple transactions in parallel. Handles timeouts and tracks progress.\n *\n * @param params - Confirmation parameters\n * @returns Array of transaction receipts\n * @throws Error if timeout occurs or transaction fails\n */\nexport async function waitForConfirmations(\n params: WaitForConfirmationsParams\n): Promise<ConfirmationResult[]> {\n const {\n publicClient,\n transactionHashes,\n confirmations = DEFAULT_CONFIRMATIONS,\n timeout = DEFAULT_TIMEOUT,\n onProgress,\n } = params;\n\n if (transactionHashes.length === 0) {\n return [];\n }\n\n const results: ConfirmationResult[] = [];\n let confirmed = 0;\n\n // Wait for all transactions in parallel\n const promises = transactionHashes.map(async (hash) => {\n try {\n const receipt = await waitForTransactionReceipt(publicClient, {\n hash,\n confirmations,\n timeout,\n });\n\n confirmed++;\n if (onProgress) {\n onProgress(confirmed, transactionHashes.length);\n }\n\n return { hash, receipt };\n } catch (error) {\n // Transaction failed or timed out\n throw new Error(\n `Transaction ${hash} failed or timed out: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n });\n\n // Wait for all promises\n const receipts = await Promise.all(promises);\n\n return receipts;\n}\n\n","import { x402Client, wrapFetchWithPayment, x402HTTPClient } from \"@x402/fetch\";\nimport { registerExactEvmScheme } from \"@x402/evm/exact/client\";\nimport type { LocalAccount } from \"viem/accounts\";\nimport type { X402ClientResult } from \"../types\";\n\n/**\n * Create x402 client for relay payments\n *\n * Sets up x402Client with user's account, registers EVM scheme,\n * and returns wrapped fetch function and HTTP client for header extraction.\n *\n * @param account - User's local account (from privateKeyToAccount)\n * @param chainId - Chain ID (optional, for logging purposes)\n * @returns Object with fetchWithPayment and httpClient\n */\nexport function createRelayX402Client(\n account: LocalAccount,\n chainId?: number\n): X402ClientResult {\n const client = new x402Client();\n registerExactEvmScheme(client, { signer: account });\n const fetchWithPayment = wrapFetchWithPayment(fetch, client);\n const httpClient = new x402HTTPClient(client);\n\n return { fetchWithPayment, httpClient };\n}\n\n","import type { LocalAccount, Address } from \"viem/accounts\";\nimport type { PublicClient, Hash } from \"viem\";\nimport type { WriteTransactionConfig } from \"@net-protocol/core\";\nimport { createRelaySession } from \"../session\";\nimport { checkBackendWalletBalance } from \"../balance\";\nimport { fundBackendWallet } from \"../fund\";\nimport { submitTransactionsViaRelay } from \"../submit\";\nimport { retryFailedTransactions } from \"../retry\";\nimport { createRelayX402Client } from \"./x402Client\";\nimport type {\n CheckBalanceResult,\n RelayFundResult,\n RelaySubmitResult,\n RetryFailedTransactionsParams,\n RetryConfig,\n FundBackendWalletParams,\n SubmitTransactionsViaRelayParams,\n} from \"../types\";\n\n/**\n * High-level client for Net Relay Service\n *\n * Provides a convenient class-based API that stores apiUrl and chainId,\n * reducing boilerplate when making multiple relay calls.\n */\nexport class RelayClient {\n private apiUrl: string;\n private chainId: number;\n\n constructor(options: { apiUrl: string; chainId: number }) {\n this.apiUrl = options.apiUrl;\n this.chainId = options.chainId;\n }\n\n /**\n * Create a relay session token\n *\n * @param params - Session creation parameters (apiUrl and chainId are already set)\n * @returns Session token and expiration timestamp\n */\n async createSession(params: {\n operatorAddress: Address;\n secretKey: string;\n account: LocalAccount;\n expiresIn?: number;\n }): Promise<{ sessionToken: string; expiresAt: number }> {\n return createRelaySession({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Check backend wallet balance\n *\n * @param params - Balance check parameters (apiUrl and chainId are already set)\n * @returns Result with balance information\n */\n async checkBalance(params: {\n operatorAddress: Address;\n secretKey: string;\n }): Promise<CheckBalanceResult> {\n return checkBackendWalletBalance({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Fund backend wallet via x402 payment\n *\n * @param params - Funding parameters (apiUrl and chainId are already set)\n * @returns Result with paymentTxHash and backendWalletAddress\n */\n async fundBackendWallet(params: {\n operatorAddress: Address;\n secretKey: string;\n fetchWithPayment: typeof fetch;\n httpClient: FundBackendWalletParams[\"httpClient\"];\n }): Promise<RelayFundResult> {\n return fundBackendWallet({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Submit transactions via relay\n *\n * @param params - Submission parameters (apiUrl and chainId are already set)\n * @returns Result with transaction hashes and success/failure tracking\n */\n async submitTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n transactions: WriteTransactionConfig[];\n sessionToken: string;\n }): Promise<RelaySubmitResult> {\n return submitTransactionsViaRelay({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Retry failed transactions with exponential backoff\n *\n * @param params - Retry parameters (apiUrl and chainId are already set)\n * @returns Final success/failure status after retries\n */\n async retryFailedTransactions(params: {\n operatorAddress: Address;\n secretKey: string;\n failedIndexes: number[];\n originalTransactions: WriteTransactionConfig[];\n backendWalletAddress: Address;\n config?: RetryConfig;\n sessionToken: string;\n recheckFunction?: RetryFailedTransactionsParams[\"recheckFunction\"];\n }): Promise<RelaySubmitResult> {\n return retryFailedTransactions({\n apiUrl: this.apiUrl,\n chainId: this.chainId,\n ...params,\n });\n }\n\n /**\n * Create x402 client for relay payments\n *\n * @param account - User's local account\n * @returns Object with fetchWithPayment and httpClient\n */\n createX402Client(account: LocalAccount) {\n return createRelayX402Client(account, this.chainId);\n }\n}\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@net-protocol/relay",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Net Relay SDK for submitting transactions via x402 payment relay service",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",