@circle-fin/provider-cctp-v2 1.8.1 → 1.8.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @circle-fin/provider-cctp-v2
2
2
 
3
+ ## 1.8.3
4
+
5
+ ### Patch Changes
6
+
7
+ - `bridge` no longer rejects Gas Station-enabled smart-contract accounts (SCAs) with zero native balance on the source or destination chain. EOA wallets without native funds will still fail at simulation with the underlying RPC error.
8
+
9
+ ## 1.8.2
10
+
11
+ ### Patch Changes
12
+
13
+ - Internal dependency updates. No user-facing changes.
14
+
3
15
  ## 1.8.1
4
16
 
5
17
  ### Patch Changes
package/index.cjs CHANGED
@@ -400,23 +400,21 @@ var UnifiedBalanceChain;
400
400
  * Enumeration of blockchains that support earn (vault deposit/withdraw)
401
401
  * operations through the Earn Kit.
402
402
  *
403
- * Currently only Ethereum mainnet is supported. Additional chains
404
- * will be added as vault protocol support expands.
405
- *
406
403
  * @example
407
404
  * ```typescript
408
405
  * import { EarnChain } from '@core/chains'
409
406
  *
410
407
  * const result = await earnKit.deposit({
411
- * from: { adapter, chain: EarnChain.Ethereum },
408
+ * from: { adapter, chain: EarnChain.Arc_Testnet },
412
409
  * vaultAddress: '0x...',
413
410
  * amount: '100',
414
411
  * })
415
412
  * ```
416
413
  */
414
+ // Values must match Blockchain enum members exactly.
417
415
  var EarnChain;
418
416
  (function (EarnChain) {
419
- EarnChain["Ethereum"] = "Ethereum";
417
+ EarnChain["Arc_Testnet"] = "Arc_Testnet";
420
418
  })(EarnChain || (EarnChain = {}));
421
419
 
422
420
  /**
@@ -4094,7 +4092,7 @@ zod.z.union([
4094
4092
  * Zod schema for validating earn-specific chain identifiers.
4095
4093
  *
4096
4094
  * Validate that the provided chain is supported for earn (vault
4097
- * deposit/withdraw) operations. Currently only Ethereum is
4095
+ * deposit/withdraw) operations. Currently only Arc Testnet is
4098
4096
  * supported.
4099
4097
  *
4100
4098
  * Accept an EarnChain enum value, a matching string literal, or
@@ -4103,12 +4101,12 @@ zod.z.union([
4103
4101
  * @example
4104
4102
  * ```typescript
4105
4103
  * import { earnChainIdentifierSchema } from '@core/chains'
4106
- * import { EarnChain, Ethereum } from '@core/chains'
4104
+ * import { ArcTestnet, EarnChain } from '@core/chains'
4107
4105
  *
4108
4106
  * // Valid
4109
- * earnChainIdentifierSchema.parse(EarnChain.Ethereum)
4110
- * earnChainIdentifierSchema.parse('Ethereum')
4111
- * earnChainIdentifierSchema.parse(Ethereum)
4107
+ * earnChainIdentifierSchema.parse(EarnChain.Arc_Testnet)
4108
+ * earnChainIdentifierSchema.parse('Arc_Testnet')
4109
+ * earnChainIdentifierSchema.parse(ArcTestnet)
4112
4110
  *
4113
4111
  * // Invalid (throws ZodError)
4114
4112
  * earnChainIdentifierSchema.parse('Solana')
@@ -6393,7 +6391,8 @@ const DEFAULT_RETRYABLE_ERROR_CODES = [
6393
6391
  *
6394
6392
  * @remarks
6395
6393
  * Check order for KitError instances:
6396
- * 1. If `recoverability === 'RETRYABLE'`, return `true` immediately (priority check).
6394
+ * 1. If `recoverability === 'RETRYABLE'` or `recoverability === 'RESUMABLE'`,
6395
+ * return `true` immediately (priority check).
6397
6396
  * 2. Otherwise, check if `error.code` is in `DEFAULT_RETRYABLE_ERROR_CODES` (fallback check).
6398
6397
  * 3. Non-KitError instances always return `false`.
6399
6398
  *
@@ -6404,6 +6403,12 @@ const DEFAULT_RETRYABLE_ERROR_CODES = [
6404
6403
  * subsequent attempts, such as network timeouts or temporary service
6405
6404
  * unavailability. These errors are safe to retry after a delay.
6406
6405
  *
6406
+ * RESUMABLE errors indicate a multi-phase operation that completed some phases
6407
+ * before failing (for example, a token approval landed but the execution
6408
+ * transaction failed). They are also retryable — re-running the operation is
6409
+ * safe — but callers that have a kit-level `retry()` should prefer it so that
6410
+ * already-completed phases are skipped.
6411
+ *
6407
6412
  * @param error - Unknown error to check
6408
6413
  * @returns True if error is retryable
6409
6414
  *
@@ -6449,16 +6454,29 @@ const DEFAULT_RETRYABLE_ERROR_CODES = [
6449
6454
  * })
6450
6455
  * isRetryableError(error3) // false
6451
6456
  *
6457
+ * // KitError with RESUMABLE recoverability (partially-completed operation)
6458
+ * const error4 = new KitError({
6459
+ * code: 8101,
6460
+ * name: 'EARN_EXECUTION_FAILED',
6461
+ * type: 'SERVICE',
6462
+ * recoverability: 'RESUMABLE',
6463
+ * message: 'Execution failed after approval',
6464
+ * })
6465
+ * isRetryableError(error4) // true
6466
+ *
6452
6467
  * // Non-KitError
6453
- * const error4 = new Error('Standard error')
6454
- * isRetryableError(error4) // false
6468
+ * const error5 = new Error('Standard error')
6469
+ * isRetryableError(error5) // false
6455
6470
  * ```
6456
6471
  */
6457
6472
  function isRetryableError$1(error) {
6458
6473
  // Use proper type guard to check if it's a KitError
6459
6474
  if (isKitError(error)) {
6460
- // Priority check: explicit recoverability
6461
- if (error.recoverability === 'RETRYABLE') {
6475
+ // Priority check: explicit recoverability. RESUMABLE errors are a subset of
6476
+ // retryable errors re-running the operation is safe, but a kit-level
6477
+ // retry() can resume from the failed phase instead.
6478
+ if (error.recoverability === 'RETRYABLE' ||
6479
+ error.recoverability === 'RESUMABLE') {
6462
6480
  return true;
6463
6481
  }
6464
6482
  // Fallback check: error code against default retryable codes
@@ -12248,7 +12266,7 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain, statusCo
12248
12266
  return step;
12249
12267
  }
12250
12268
 
12251
- var version = "1.8.1";
12269
+ var version = "1.8.3";
12252
12270
  var pkg = {
12253
12271
  version: version};
12254
12272
 
@@ -12662,7 +12680,9 @@ const hexStringSchema = zod.z
12662
12680
  * console.log(result.success) // true
12663
12681
  * ```
12664
12682
  */
12665
- hexStringSchema.refine((value) => value.length === 42, 'EVM address must be exactly 42 characters long (0x + 40 hex characters)');
12683
+ hexStringSchema
12684
+ .refine((value) => value.length === 42, 'EVM address must be exactly 42 characters long (0x + 40 hex characters)')
12685
+ .transform((value) => value);
12666
12686
  /**
12667
12687
  * Schema for validating transaction hashes.
12668
12688
  *
@@ -12683,6 +12703,29 @@ hexStringSchema.refine((value) => value.length === 42, 'EVM address must be exac
12683
12703
  * ```
12684
12704
  */
12685
12705
  hexStringSchema.refine((value) => value.length === 66, 'Transaction hash must be exactly 66 characters long (0x + 64 hex characters)');
12706
+ /**
12707
+ * Schema for validating EVM signatures.
12708
+ *
12709
+ * This schema validates that a string is a properly formatted 65-byte EVM
12710
+ * signature:
12711
+ * - Must be a valid hex string with '0x' prefix
12712
+ * - Must be exactly 132 characters long (0x + 130 hex characters)
12713
+ *
12714
+ * @throws {KitError} If validation fails with INPUT_VALIDATION_FAILED code (1098), with details about which properties failed
12715
+ *
12716
+ * @example
12717
+ * ```typescript
12718
+ * import { evmSignatureSchema } from '@core/adapter'
12719
+ *
12720
+ * const validSignature = `0x${'ab'.repeat(65)}`
12721
+ *
12722
+ * const result = evmSignatureSchema.safeParse(validSignature)
12723
+ * console.log(result.success) // true
12724
+ * ```
12725
+ */
12726
+ hexStringSchema
12727
+ .refine((value) => value.length === 132, 'EVM signature must be exactly 132 characters long (0x + 130 hex characters)')
12728
+ .transform((value) => value);
12686
12729
  /**
12687
12730
  * Schema for validating base58-encoded strings.
12688
12731
  *
@@ -12829,60 +12872,6 @@ const validateBalanceForTransaction = async (params) => {
12829
12872
  }
12830
12873
  };
12831
12874
 
12832
- /**
12833
- * Validate that the adapter has sufficient native token balance for transaction fees.
12834
- *
12835
- * This function checks if the adapter's current native token balance (ETH, SOL, etc.)
12836
- * is greater than zero. It throws a KitError with code 9002 (BALANCE_INSUFFICIENT_GAS)
12837
- * if the balance is zero, indicating the wallet cannot pay for transaction fees.
12838
- *
12839
- * @param params - The validation parameters containing adapter and operation context.
12840
- * @returns A promise that resolves to void if validation passes.
12841
- * @throws {KitError} When the adapter's native balance is zero (code: 9002).
12842
- *
12843
- * @example
12844
- * ```typescript
12845
- * import { validateNativeBalanceForTransaction } from '@core/adapter'
12846
- * import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
12847
- * import { isKitError, ERROR_TYPES } from '@core/errors'
12848
- *
12849
- * const adapter = createViemAdapterFromPrivateKey({
12850
- * privateKey: '0x...',
12851
- * chain: 'Ethereum',
12852
- * })
12853
- *
12854
- * try {
12855
- * await validateNativeBalanceForTransaction({
12856
- * adapter,
12857
- * operationContext: { chain: 'Ethereum' },
12858
- * })
12859
- * console.log('Native balance validation passed')
12860
- * } catch (error) {
12861
- * if (isKitError(error) && error.type === ERROR_TYPES.BALANCE) {
12862
- * console.error('Insufficient gas funds:', error.message)
12863
- * }
12864
- * }
12865
- * ```
12866
- */
12867
- const validateNativeBalanceForTransaction = async (params) => {
12868
- const { adapter, operationContext } = params;
12869
- const balancePrepared = await adapter.prepareAction('native.balanceOf', {
12870
- walletAddress: operationContext.address,
12871
- }, operationContext);
12872
- const balance = await balancePrepared.execute();
12873
- if (BigInt(balance) === 0n) {
12874
- const { chain } = operationContext;
12875
- const chainName = extractChainInfo(chain).name;
12876
- const nativeSymbol = typeof chain === 'object' && chain !== null && 'nativeCurrency' in chain
12877
- ? chain.nativeCurrency.symbol
12878
- : undefined;
12879
- throw createInsufficientGasError(chainName, nativeSymbol, {
12880
- balance: '0',
12881
- walletAddress: operationContext.address,
12882
- });
12883
- }
12884
- };
12885
-
12886
12875
  /**
12887
12876
  * Permit signature standards for gasless token approvals.
12888
12877
  *
@@ -13443,7 +13432,7 @@ class CCTPV2BridgingProvider extends BridgingProvider {
13443
13432
  async bridge(params) {
13444
13433
  // CCTP-specific bridge params validation (includes base validation)
13445
13434
  assertCCTPv2BridgeParams(params);
13446
- const { source, destination, amount, token } = params;
13435
+ const { source, amount, token } = params;
13447
13436
  // Extract operation context from source wallet context for balance validation
13448
13437
  const sourceOperationContext = this.extractOperationContext(source);
13449
13438
  // Validate USDC balance for transaction on source chain
@@ -13454,24 +13443,6 @@ class CCTPV2BridgingProvider extends BridgingProvider {
13454
13443
  tokenAddress: source.chain.usdcAddress,
13455
13444
  operationContext: sourceOperationContext,
13456
13445
  });
13457
- // Validate native balance > 0 for gas fees on source chain
13458
- await validateNativeBalanceForTransaction({
13459
- adapter: source.adapter,
13460
- operationContext: sourceOperationContext,
13461
- });
13462
- // Only validate destination native balance if there's an adapter
13463
- // and forwarder is not being used (forwarder handles mint, no gas needed)
13464
- if ('adapter' in destination &&
13465
- destination.adapter &&
13466
- !destination.useForwarder) {
13467
- // Extract operation context from destination wallet context
13468
- const destinationOperationContext = this.extractOperationContext(destination);
13469
- // Validate native balance > 0 for gas fees on destination chain
13470
- await validateNativeBalanceForTransaction({
13471
- adapter: destination.adapter,
13472
- operationContext: destinationOperationContext,
13473
- });
13474
- }
13475
13446
  return bridge(params, this);
13476
13447
  }
13477
13448
  /**
package/index.d.ts CHANGED
@@ -1810,12 +1810,14 @@ declare enum PermitType {
1810
1810
  * The Adapter Contract uses this to pull tokens from the user's wallet
1811
1811
  * using permit signatures instead of requiring separate approval transactions.
1812
1812
  *
1813
+ * Shared by the `swap.*` and `earn.*` action namespaces because both forward
1814
+ * `tokenInputs` unchanged to the adapter contract's `execute` call.
1815
+ *
1813
1816
  * @example
1814
1817
  * ```typescript
1815
1818
  * const tokenInput: TokenInput = {
1816
1819
  * permitType: PermitType.EIP2612,
1817
1820
  * token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
1818
- * from: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
1819
1821
  * amount: 1000000n, // 1 USDC
1820
1822
  * permitCalldata: '0x...' // Encoded permit(value, deadline, v, r, s)
1821
1823
  * }
@@ -1838,12 +1840,91 @@ interface TokenInput {
1838
1840
  * ABI-encoded permit calldata.
1839
1841
  *
1840
1842
  * For EIP-2612: encode(value, deadline, v, r, s)
1841
- * For Permit2: encode(permit, signature)
1842
1843
  *
1843
1844
  * @example '0x0000000000000000000000000000000000000000000000000000000000989680...'
1844
1845
  */
1845
1846
  permitCalldata: `0x${string}`;
1846
1847
  }
1848
+
1849
+ /**
1850
+ * Parameters for executing a service-signed earn operation via the Adapter
1851
+ * smart contract on EVM chains.
1852
+ *
1853
+ * Shared across earn action keys: `earn.deposit`, `earn.withdraw`, and
1854
+ * `earn.claimRewards`. Each operation forwards the same `executeParams`,
1855
+ * `tokenInputs`, and `signature` triple to the adapter contract's `execute`
1856
+ * function. The service signs `executeParams` off-chain; the contract verifies
1857
+ * the signature on-chain.
1858
+ *
1859
+ * @example
1860
+ * ```typescript
1861
+ * import type { ActionPayload } from '@core/adapter'
1862
+ *
1863
+ * const params: ActionPayload<'earn.deposit'> = {
1864
+ * executeParams: { instructions: [], tokens: [], execId: 1n, deadline: 0n, metadata: '0x' },
1865
+ * tokenInputs: [],
1866
+ * signature: '0x...',
1867
+ * }
1868
+ *
1869
+ * const prepared = await adapter.prepareAction('earn.deposit', params, { chain, address })
1870
+ * const txHash = await prepared.execute()
1871
+ * ```
1872
+ */
1873
+ interface ExecuteEarnEVMParams extends ActionParameters {
1874
+ /**
1875
+ * Execution parameters returned by the earn service.
1876
+ *
1877
+ * Kept as an opaque record so the adapter forwards the service-signed struct
1878
+ * unchanged. The adapter contract ABI decodes it on-chain.
1879
+ */
1880
+ executeParams: Record<string, unknown>;
1881
+ /**
1882
+ * Token inputs with permit signatures for gasless approvals.
1883
+ *
1884
+ * Populated by the earn provider after it decides how token spending is
1885
+ * authorised. Today deposit uses a separate `token.approve` transaction and
1886
+ * passes `PermitType.NONE`; a future permit-enabled path can populate this
1887
+ * field without a breaking change.
1888
+ */
1889
+ tokenInputs: TokenInput[];
1890
+ /**
1891
+ * EIP-712 signature from the earn service proxy.
1892
+ *
1893
+ * The adapter contract verifies this signature on-chain. Passed through
1894
+ * unchanged.
1895
+ */
1896
+ signature: `0x${string}`;
1897
+ }
1898
+ /**
1899
+ * Parameters for earn execute actions across supported ecosystems.
1900
+ *
1901
+ * EVM-only today; becomes a union when a non-EVM adapter implementation
1902
+ * lands. Action handlers narrow via a property-based type guard, same
1903
+ * pattern as {@link ExecuteSwapParams}.
1904
+ */
1905
+ type ExecuteEarnParams = ExecuteEarnEVMParams;
1906
+ /**
1907
+ * Action map for earn operations.
1908
+ *
1909
+ * Each action key forwards the same `(executeParams, tokenInputs, signature)`
1910
+ * triple to the adapter contract. Provider-side orchestration performs any
1911
+ * required token approval; this action only prepares the adapter execute call.
1912
+ */
1913
+ interface EarnActionMap {
1914
+ /**
1915
+ * Execute a service-signed deposit against the adapter contract.
1916
+ */
1917
+ readonly deposit: ExecuteEarnParams;
1918
+ /**
1919
+ * Execute a service-signed withdraw against the adapter contract.
1920
+ */
1921
+ readonly withdraw: ExecuteEarnParams;
1922
+ /**
1923
+ * Execute a service-signed claim rewards against the adapter contract.
1924
+ */
1925
+ readonly claimRewards: ExecuteEarnParams;
1926
+ }
1927
+
1847
1928
  /**
1848
1929
  * Single instruction to execute within the Adapter Contract.
1849
1930
  *
@@ -2025,7 +2106,6 @@ interface ExecuteParams {
2025
2106
  * const tokenInputs: TokenInput[] = [{
2026
2107
  * permitType: PermitType.EIP2612,
2027
2108
  * token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
2028
- * from: userAddress,
2029
2109
  * amount: 1000000n,
2030
2110
  * permitCalldata: '0x...' // Encoded permit signature
2031
2111
  * }]
@@ -2068,7 +2148,6 @@ interface ExecuteSwapEVMParams extends ActionParameters {
2068
2148
  * [{
2069
2149
  * permitType: PermitType.EIP2612,
2070
2150
  * token: '0xUSDC',
2071
- * from: userAddress,
2072
2151
  * amount: 1000000n,
2073
2152
  * permitCalldata: '0x...'
2074
2153
  * }]
@@ -2804,6 +2883,8 @@ interface ActionMap {
2804
2883
  readonly usdt: USDTActionMap;
2805
2884
  /** Swap operations for DEX aggregator integrations. */
2806
2885
  readonly swap: SwapActionMap;
2886
+ /** Earn operations that execute service-signed payloads via the adapter contract. */
2887
+ readonly earn: EarnActionMap;
2807
2888
  }
2808
2889
  /**
2809
2890
  * Determine if a type represents an action parameter object (leaf node).
package/index.mjs CHANGED
@@ -393,23 +393,21 @@ var UnifiedBalanceChain;
393
393
  * Enumeration of blockchains that support earn (vault deposit/withdraw)
394
394
  * operations through the Earn Kit.
395
395
  *
396
- * Currently only Ethereum mainnet is supported. Additional chains
397
- * will be added as vault protocol support expands.
398
- *
399
396
  * @example
400
397
  * ```typescript
401
398
  * import { EarnChain } from '@core/chains'
402
399
  *
403
400
  * const result = await earnKit.deposit({
404
- * from: { adapter, chain: EarnChain.Ethereum },
401
+ * from: { adapter, chain: EarnChain.Arc_Testnet },
405
402
  * vaultAddress: '0x...',
406
403
  * amount: '100',
407
404
  * })
408
405
  * ```
409
406
  */
407
+ // Values must match Blockchain enum members exactly.
410
408
  var EarnChain;
411
409
  (function (EarnChain) {
412
- EarnChain["Ethereum"] = "Ethereum";
410
+ EarnChain["Arc_Testnet"] = "Arc_Testnet";
413
411
  })(EarnChain || (EarnChain = {}));
414
412
 
415
413
  /**
@@ -4087,7 +4085,7 @@ z.union([
4087
4085
  * Zod schema for validating earn-specific chain identifiers.
4088
4086
  *
4089
4087
  * Validate that the provided chain is supported for earn (vault
4090
- * deposit/withdraw) operations. Currently only Ethereum is
4088
+ * deposit/withdraw) operations. Currently only Arc Testnet is
4091
4089
  * supported.
4092
4090
  *
4093
4091
  * Accept an EarnChain enum value, a matching string literal, or
@@ -4096,12 +4094,12 @@ z.union([
4096
4094
  * @example
4097
4095
  * ```typescript
4098
4096
  * import { earnChainIdentifierSchema } from '@core/chains'
4099
- * import { EarnChain, Ethereum } from '@core/chains'
4097
+ * import { ArcTestnet, EarnChain } from '@core/chains'
4100
4098
  *
4101
4099
  * // Valid
4102
- * earnChainIdentifierSchema.parse(EarnChain.Ethereum)
4103
- * earnChainIdentifierSchema.parse('Ethereum')
4104
- * earnChainIdentifierSchema.parse(Ethereum)
4100
+ * earnChainIdentifierSchema.parse(EarnChain.Arc_Testnet)
4101
+ * earnChainIdentifierSchema.parse('Arc_Testnet')
4102
+ * earnChainIdentifierSchema.parse(ArcTestnet)
4105
4103
  *
4106
4104
  * // Invalid (throws ZodError)
4107
4105
  * earnChainIdentifierSchema.parse('Solana')
@@ -6386,7 +6384,8 @@ const DEFAULT_RETRYABLE_ERROR_CODES = [
6386
6384
  *
6387
6385
  * @remarks
6388
6386
  * Check order for KitError instances:
6389
- * 1. If `recoverability === 'RETRYABLE'`, return `true` immediately (priority check).
6387
+ * 1. If `recoverability === 'RETRYABLE'` or `recoverability === 'RESUMABLE'`,
6388
+ * return `true` immediately (priority check).
6390
6389
  * 2. Otherwise, check if `error.code` is in `DEFAULT_RETRYABLE_ERROR_CODES` (fallback check).
6391
6390
  * 3. Non-KitError instances always return `false`.
6392
6391
  *
@@ -6397,6 +6396,12 @@ const DEFAULT_RETRYABLE_ERROR_CODES = [
6397
6396
  * subsequent attempts, such as network timeouts or temporary service
6398
6397
  * unavailability. These errors are safe to retry after a delay.
6399
6398
  *
6399
+ * RESUMABLE errors indicate a multi-phase operation that completed some phases
6400
+ * before failing (for example, a token approval landed but the execution
6401
+ * transaction failed). They are also retryable — re-running the operation is
6402
+ * safe — but callers that have a kit-level `retry()` should prefer it so that
6403
+ * already-completed phases are skipped.
6404
+ *
6400
6405
  * @param error - Unknown error to check
6401
6406
  * @returns True if error is retryable
6402
6407
  *
@@ -6442,16 +6447,29 @@ const DEFAULT_RETRYABLE_ERROR_CODES = [
6442
6447
  * })
6443
6448
  * isRetryableError(error3) // false
6444
6449
  *
6450
+ * // KitError with RESUMABLE recoverability (partially-completed operation)
6451
+ * const error4 = new KitError({
6452
+ * code: 8101,
6453
+ * name: 'EARN_EXECUTION_FAILED',
6454
+ * type: 'SERVICE',
6455
+ * recoverability: 'RESUMABLE',
6456
+ * message: 'Execution failed after approval',
6457
+ * })
6458
+ * isRetryableError(error4) // true
6459
+ *
6445
6460
  * // Non-KitError
6446
- * const error4 = new Error('Standard error')
6447
- * isRetryableError(error4) // false
6461
+ * const error5 = new Error('Standard error')
6462
+ * isRetryableError(error5) // false
6448
6463
  * ```
6449
6464
  */
6450
6465
  function isRetryableError$1(error) {
6451
6466
  // Use proper type guard to check if it's a KitError
6452
6467
  if (isKitError(error)) {
6453
- // Priority check: explicit recoverability
6454
- if (error.recoverability === 'RETRYABLE') {
6468
+ // Priority check: explicit recoverability. RESUMABLE errors are a subset of
6469
+ // retryable errors re-running the operation is safe, but a kit-level
6470
+ // retry() can resume from the failed phase instead.
6471
+ if (error.recoverability === 'RETRYABLE' ||
6472
+ error.recoverability === 'RESUMABLE') {
6455
6473
  return true;
6456
6474
  }
6457
6475
  // Fallback check: error code against default retryable codes
@@ -12241,7 +12259,7 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain, statusCo
12241
12259
  return step;
12242
12260
  }
12243
12261
 
12244
- var version = "1.8.1";
12262
+ var version = "1.8.3";
12245
12263
  var pkg = {
12246
12264
  version: version};
12247
12265
 
@@ -12655,7 +12673,9 @@ const hexStringSchema = z
12655
12673
  * console.log(result.success) // true
12656
12674
  * ```
12657
12675
  */
12658
- hexStringSchema.refine((value) => value.length === 42, 'EVM address must be exactly 42 characters long (0x + 40 hex characters)');
12676
+ hexStringSchema
12677
+ .refine((value) => value.length === 42, 'EVM address must be exactly 42 characters long (0x + 40 hex characters)')
12678
+ .transform((value) => value);
12659
12679
  /**
12660
12680
  * Schema for validating transaction hashes.
12661
12681
  *
@@ -12676,6 +12696,29 @@ hexStringSchema.refine((value) => value.length === 42, 'EVM address must be exac
12676
12696
  * ```
12677
12697
  */
12678
12698
  hexStringSchema.refine((value) => value.length === 66, 'Transaction hash must be exactly 66 characters long (0x + 64 hex characters)');
12699
+ /**
12700
+ * Schema for validating EVM signatures.
12701
+ *
12702
+ * This schema validates that a string is a properly formatted 65-byte EVM
12703
+ * signature:
12704
+ * - Must be a valid hex string with '0x' prefix
12705
+ * - Must be exactly 132 characters long (0x + 130 hex characters)
12706
+ *
12707
+ * @throws {KitError} If validation fails with INPUT_VALIDATION_FAILED code (1098), with details about which properties failed
12708
+ *
12709
+ * @example
12710
+ * ```typescript
12711
+ * import { evmSignatureSchema } from '@core/adapter'
12712
+ *
12713
+ * const validSignature = `0x${'ab'.repeat(65)}`
12714
+ *
12715
+ * const result = evmSignatureSchema.safeParse(validSignature)
12716
+ * console.log(result.success) // true
12717
+ * ```
12718
+ */
12719
+ hexStringSchema
12720
+ .refine((value) => value.length === 132, 'EVM signature must be exactly 132 characters long (0x + 130 hex characters)')
12721
+ .transform((value) => value);
12679
12722
  /**
12680
12723
  * Schema for validating base58-encoded strings.
12681
12724
  *
@@ -12822,60 +12865,6 @@ const validateBalanceForTransaction = async (params) => {
12822
12865
  }
12823
12866
  };
12824
12867
 
12825
- /**
12826
- * Validate that the adapter has sufficient native token balance for transaction fees.
12827
- *
12828
- * This function checks if the adapter's current native token balance (ETH, SOL, etc.)
12829
- * is greater than zero. It throws a KitError with code 9002 (BALANCE_INSUFFICIENT_GAS)
12830
- * if the balance is zero, indicating the wallet cannot pay for transaction fees.
12831
- *
12832
- * @param params - The validation parameters containing adapter and operation context.
12833
- * @returns A promise that resolves to void if validation passes.
12834
- * @throws {KitError} When the adapter's native balance is zero (code: 9002).
12835
- *
12836
- * @example
12837
- * ```typescript
12838
- * import { validateNativeBalanceForTransaction } from '@core/adapter'
12839
- * import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
12840
- * import { isKitError, ERROR_TYPES } from '@core/errors'
12841
- *
12842
- * const adapter = createViemAdapterFromPrivateKey({
12843
- * privateKey: '0x...',
12844
- * chain: 'Ethereum',
12845
- * })
12846
- *
12847
- * try {
12848
- * await validateNativeBalanceForTransaction({
12849
- * adapter,
12850
- * operationContext: { chain: 'Ethereum' },
12851
- * })
12852
- * console.log('Native balance validation passed')
12853
- * } catch (error) {
12854
- * if (isKitError(error) && error.type === ERROR_TYPES.BALANCE) {
12855
- * console.error('Insufficient gas funds:', error.message)
12856
- * }
12857
- * }
12858
- * ```
12859
- */
12860
- const validateNativeBalanceForTransaction = async (params) => {
12861
- const { adapter, operationContext } = params;
12862
- const balancePrepared = await adapter.prepareAction('native.balanceOf', {
12863
- walletAddress: operationContext.address,
12864
- }, operationContext);
12865
- const balance = await balancePrepared.execute();
12866
- if (BigInt(balance) === 0n) {
12867
- const { chain } = operationContext;
12868
- const chainName = extractChainInfo(chain).name;
12869
- const nativeSymbol = typeof chain === 'object' && chain !== null && 'nativeCurrency' in chain
12870
- ? chain.nativeCurrency.symbol
12871
- : undefined;
12872
- throw createInsufficientGasError(chainName, nativeSymbol, {
12873
- balance: '0',
12874
- walletAddress: operationContext.address,
12875
- });
12876
- }
12877
- };
12878
-
12879
12868
  /**
12880
12869
  * Permit signature standards for gasless token approvals.
12881
12870
  *
@@ -13436,7 +13425,7 @@ class CCTPV2BridgingProvider extends BridgingProvider {
13436
13425
  async bridge(params) {
13437
13426
  // CCTP-specific bridge params validation (includes base validation)
13438
13427
  assertCCTPv2BridgeParams(params);
13439
- const { source, destination, amount, token } = params;
13428
+ const { source, amount, token } = params;
13440
13429
  // Extract operation context from source wallet context for balance validation
13441
13430
  const sourceOperationContext = this.extractOperationContext(source);
13442
13431
  // Validate USDC balance for transaction on source chain
@@ -13447,24 +13436,6 @@ class CCTPV2BridgingProvider extends BridgingProvider {
13447
13436
  tokenAddress: source.chain.usdcAddress,
13448
13437
  operationContext: sourceOperationContext,
13449
13438
  });
13450
- // Validate native balance > 0 for gas fees on source chain
13451
- await validateNativeBalanceForTransaction({
13452
- adapter: source.adapter,
13453
- operationContext: sourceOperationContext,
13454
- });
13455
- // Only validate destination native balance if there's an adapter
13456
- // and forwarder is not being used (forwarder handles mint, no gas needed)
13457
- if ('adapter' in destination &&
13458
- destination.adapter &&
13459
- !destination.useForwarder) {
13460
- // Extract operation context from destination wallet context
13461
- const destinationOperationContext = this.extractOperationContext(destination);
13462
- // Validate native balance > 0 for gas fees on destination chain
13463
- await validateNativeBalanceForTransaction({
13464
- adapter: destination.adapter,
13465
- operationContext: destinationOperationContext,
13466
- });
13467
- }
13468
13439
  return bridge(params, this);
13469
13440
  }
13470
13441
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@circle-fin/provider-cctp-v2",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "Circle's official Cross-Chain Transfer Protocol v2 provider for native USDC bridging",
5
5
  "keywords": [
6
6
  "circle",