@circle-fin/provider-cctp-v2 0.0.2-alpha.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +28 -124
  2. package/index.cjs.js +120 -91
  3. package/index.d.ts +47 -65
  4. package/index.mjs +120 -91
  5. package/package.json +20 -6
package/README.md CHANGED
@@ -5,8 +5,9 @@
5
5
  [![npm version](https://badge.fury.io/js/@circle-fin%2Fprovider-cctp-v2.svg)](https://badge.fury.io/js/@circle-fin%2Fprovider-cctp-v2)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)
7
7
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
+ [![Discord](https://img.shields.io/discord/473781666251538452?label=Discord&logo=discord)](https://discord.com/invite/buildoncircle)
8
9
 
9
- **Circle's Cross-Chain Transfer Protocol v2 provider for Stablecoin Kits**
10
+ **Circle's Cross-Chain Transfer Protocol v2 provider for Bridge Kit**
10
11
 
11
12
  _Native USDC bridging across 34 chains using Circle's battle-tested protocols._
12
13
 
@@ -20,19 +21,19 @@ _Native USDC bridging across 34 chains using Circle's battle-tested protocols._
20
21
  - [Why CCTPv2 Provider?](#why-cctpv2-provider)
21
22
  - [Installation](#installation)
22
23
  - [Quick Start](#quick-start)
23
- - [Option 1: With Bridging Kit (Recommended)](#option-1-with-bridging-kit-recommended)
24
+ - [Option 1: With Bridge Kit (Recommended)](#option-1-with-bridge-kit-recommended)
24
25
  - [Option 2: Direct Provider Usage](#option-2-direct-provider-usage)
25
26
  - [Features](#features)
26
27
  - [Supported Chains \& Routes](#supported-chains--routes)
27
- - [Mainnet Chains (12 chains)](#mainnet-chains-12-chains)
28
- - [Testnet Chains (12 chains)](#testnet-chains-12-chains)
28
+ - [Mainnet Chains](#mainnet-chains)
29
+ - [Testnet Chains](#testnet-chains)
29
30
  - [Usage Examples](#usage-examples)
30
31
  - [Basic Bridge Operation](#basic-bridge-operation)
31
32
  - [Route Validation](#route-validation)
32
33
  - [Bridge Configurations](#bridge-configurations)
33
34
  - [Error Handling](#error-handling)
34
35
  - [Bridge Process](#bridge-process)
35
- - [Integration with Bridging Kit](#integration-with-bridging-kit)
36
+ - [Integration with Bridge Kit](#integration-with-bridge-kit)
36
37
  - [API Reference](#api-reference)
37
38
  - [Core Methods](#core-methods)
38
39
  - [Transfer Parameters](#transfer-parameters)
@@ -42,9 +43,9 @@ _Native USDC bridging across 34 chains using Circle's battle-tested protocols._
42
43
 
43
44
  ## Overview
44
45
 
45
- The CCTPv2 Bridging Provider is a strongly-typed implementation of Circle's Cross-Chain Transfer Protocol (CCTP) version 2 that enables **native USDC bridging** between 24+ supported blockchain networks.
46
+ The CCTPv2 Bridging Provider is a strongly-typed implementation of Circle's Cross-Chain Transfer Protocol (CCTP) version 2 that enables **native USDC bridging** between 34+ supported blockchain networks.
46
47
 
47
- While primarily designed to power the [Bridging Kit](https://www.npmjs.com/package/@circle-fin/bridging-kit), this provider can also be used **directly in applications** that need fine-grained control over the CCTP transfer process or want to integrate CCTP without the full Stablecoin Kits framework.
48
+ While primarily designed to power the [Bridge Kit](https://www.npmjs.com/package/@circle-fin/bridge-kit), this provider can also be used **directly in applications** that need fine-grained control over the CCTP transfer process or want to integrate CCTP without the full Stablecoin Kits framework.
48
49
 
49
50
  ### Why CCTPv2 Provider?
50
51
 
@@ -62,21 +63,21 @@ npm install @circle-fin/provider-cctp-v2
62
63
  yarn add @circle-fin/provider-cctp-v2
63
64
  ```
64
65
 
65
- > **Note**: This provider is included by default with the [Bridging Kit](https://www.npmjs.com/package/@circle-fin/bridging-kit). You can import this provider if you need to do a custom CCTP integration.
66
+ > **Note**: This provider is included by default with the [Bridge Kit](https://www.npmjs.com/package/@circle-fin/bridge-kit). You can import this provider if you need to do a custom CCTP integration.
66
67
 
67
68
  ## Quick Start
68
69
 
69
- ### Option 1: With Bridging Kit (Recommended)
70
+ ### Option 1: With Bridge Kit (Recommended)
70
71
 
71
72
  ```typescript
72
- import { BridgingKit } from '@circle-fin/bridging-kit'
73
+ import { BridgeKit } from '@circle-fin/bridge-kit'
73
74
 
74
75
  // Provider included by default
75
- const kit = new BridgingKit()
76
+ const kit = new BridgeKit()
76
77
 
77
78
  const result = await kit.bridge({
78
- source: { adapter: sourceAdapter },
79
- destination: { adapter: destAdapter },
79
+ from: { adapter: sourceAdapter, chain: 'Ethereum' },
80
+ to: { adapter: destAdapter, chain: 'Base' },
80
81
  amount: '100.50',
81
82
  })
82
83
  ```
@@ -113,16 +114,16 @@ const isSupported = provider.supportsRoute('Ethereum', 'Base', 'USDC')
113
114
 
114
115
  // Get bridge estimate
115
116
  const estimate = await provider.estimate({
116
- source: { adapter: sourceAdapter },
117
- destination: { adapter: destAdapter },
117
+ from: { adapter: sourceAdapter, chain: 'Ethereum' },
118
+ to: { adapter: destAdapter, chain: 'Base' },
118
119
  amount: '100.50',
119
120
  config: { transferSpeed: 'FAST' },
120
121
  })
121
122
 
122
123
  // Execute bridge operation with custom logic
123
124
  const result = await provider.bridge({
124
- source: { adapter: sourceAdapter },
125
- destination: { adapter: destAdapter },
125
+ from: { adapter: sourceAdapter, chain: 'Ethereum' },
126
+ to: { adapter: destAdapter, chain: 'Base' },
126
127
  amount: '100.50',
127
128
  config: { transferSpeed: 'FAST' },
128
129
  })
@@ -141,92 +142,14 @@ const result = await provider.bridge({
141
142
 
142
143
  The provider supports **544 total bridge routes** across these chains:
143
144
 
144
- ### Mainnet Chains (17 chains)
145
+ ### Mainnet Chains
145
146
 
146
147
  **Arbitrum**, **Avalanche**, **Base**, **Codex**, **Ethereum**, **HyperEVM**, **Ink**, **Linea**, **OP Mainnet**, **Plume**, **Polygon PoS**, **Sei**, **Solana**, **Sonic**, **Unichain**, **World Chain**, **XDC**
147
148
 
148
- ### Testnet Chains (17 chains)
149
+ ### Testnet Chains
149
150
 
150
151
  **Arbitrum Sepolia**, **Avalanche Fuji**, **Base Sepolia**, **Codex Testnet**, **Ethereum Sepolia**, **HyperEVM Testnet**, **Ink Testnet**, **Linea Sepolia**, **OP Sepolia**, **Plume Testnet**, **Polygon PoS Amoy**, **Sei Testnet**, **Solana Devnet**, **Sonic Testnet**, **Unichain Sepolia**, **World Chain Sepolia**, **XDC Apothem**
151
152
 
152
- ## Usage Examples
153
-
154
- ### Basic Bridge Operation
155
-
156
- ```typescript
157
- import { BridgingKit } from '@circle-fin/bridging-kit'
158
- import { ViemAdapter } from '@circle-fin/adapter-viem-v2'
159
- import { createPublicClient, createWalletClient, http } from 'viem'
160
- import { mainnet, base } from 'viem/chains'
161
- import { privateKeyToAccount } from 'viem/accounts'
162
-
163
- const account = privateKeyToAccount(process.env.PRIVATE_KEY)
164
- const kit = new BridgingKit() // CCTPv2 provider included by default
165
-
166
- const ethereumAdapter = new ViemAdapter({
167
- publicClient: createPublicClient({ chain: mainnet, transport: http() }),
168
- walletClient: createWalletClient({
169
- account,
170
- chain: mainnet,
171
- transport: http(),
172
- }),
173
- })
174
-
175
- const baseAdapter = new ViemAdapter({
176
- publicClient: createPublicClient({ chain: base, transport: http() }),
177
- walletClient: createWalletClient({ account, chain: base, transport: http() }),
178
- })
179
-
180
- const result = await kit.bridge({
181
- source: { adapter: ethereumAdapter },
182
- destination: { adapter: baseAdapter },
183
- amount: '100.50',
184
- config: { transferSpeed: 'FAST' },
185
- })
186
- ```
187
-
188
- ### Route Validation
189
-
190
- ```typescript
191
- import { CCTPV2BridgingProvider } from '@circle-fin/provider-cctp-v2'
192
- import { BridgingKit } from '@circle-fin/bridging-kit'
193
-
194
- const provider = new CCTPV2BridgingProvider()
195
- const kit = new BridgingKit()
196
-
197
- // Check if a route is supported
198
- const isSupported = provider.supportsRoute('Ethereum', 'Base', 'USDC')
199
- console.log('Ethereum → Base:', isSupported ? '✅' : '❌')
200
-
201
- // Validate before bridging
202
- const sourceChain = 'Ethereum'
203
- const destChain = 'Base'
204
- if (!kit.supportsRoute(sourceChain, destChain, 'USDC')) {
205
- throw new Error('Route not supported')
206
- }
207
- ```
208
-
209
- ### Bridge Configurations
210
-
211
- ```typescript
212
- // Using the same kit and adapters from the examples above
213
- // Fast bridge (higher fees, faster processing)
214
- const fastResult = await kit.bridge({
215
- source: { adapter: ethereumAdapter },
216
- destination: { adapter: baseAdapter },
217
- amount: '50.0',
218
- config: { transferSpeed: 'FAST' },
219
- })
220
-
221
- // Slow bridge (lower fees, longer processing)
222
- const slowResult = await kit.bridge({
223
- source: { adapter: ethereumAdapter },
224
- destination: { adapter: baseAdapter },
225
- amount: '50.0',
226
- config: { transferSpeed: 'SLOW' },
227
- })
228
- ```
229
-
230
153
  ## Error Handling
231
154
 
232
155
  The provider implements thoughtful error handling for different scenarios:
@@ -234,8 +157,8 @@ The provider implements thoughtful error handling for different scenarios:
234
157
  ```typescript
235
158
  // Using the same kit and adapters from the examples above
236
159
  const params = {
237
- source: { adapter: ethereumAdapter },
238
- destination: { adapter: baseAdapter },
160
+ from: { adapter: sourceAdapter, chain: 'Ethereum' },
161
+ to: { adapter: destAdapter, chain: 'Base' },
239
162
  amount: '100.50',
240
163
  }
241
164
 
@@ -276,12 +199,12 @@ The CCTPv2 provider handles the complete cross-chain bridging flow:
276
199
 
277
200
  Each step is tracked and can be monitored through the Provider's event system. Transaction details for each step include explorer URLs for easy verification on block explorers.
278
201
 
279
- ## Integration with Bridging Kit
202
+ ## Integration with Bridge Kit
280
203
 
281
- This provider is designed specifically for the [Bridging Kit](https://www.npmjs.com/package/@circle-fin/bridging-kit):
204
+ This provider is designed specifically for the [Bridge Kit](https://www.npmjs.com/package/@circle-fin/bridge-kit):
282
205
 
283
206
  ```typescript
284
- import { BridgingKit } from '@circle-fin/bridging-kit'
207
+ import { BridgeKit } from '@circle-fin/bridge-kit'
285
208
  import { ViemAdapter } from '@circle-fin/adapter-viem-v2'
286
209
  import { createPublicClient, createWalletClient, http } from 'viem'
287
210
  import { mainnet, base } from 'viem/chains'
@@ -290,7 +213,7 @@ import { privateKeyToAccount } from 'viem/accounts'
290
213
  const account = privateKeyToAccount(process.env.PRIVATE_KEY)
291
214
 
292
215
  // Provider is included by default
293
- const kit = new BridgingKit()
216
+ const kit = new BridgeKit()
294
217
 
295
218
  const sourceAdapter = new ViemAdapter({
296
219
  publicClient: createPublicClient({ chain: mainnet, transport: http() }),
@@ -315,31 +238,12 @@ kit.on('mint', (event) => console.log('Mint:', event.values.txHash))
315
238
 
316
239
  // Execute transfer
317
240
  const result = await kit.bridge({
318
- source: { adapter: sourceAdapter },
319
- destination: { adapter: destAdapter },
241
+ from: { adapter: sourceAdapter, chain: 'Ethereum' },
242
+ to: { adapter: destAdapter, chain: 'Base' },
320
243
  amount: '25.0',
321
244
  })
322
245
  ```
323
246
 
324
- ## API Reference
325
-
326
- ### Core Methods
327
-
328
- - `supportsRoute(source, destination, token)` - Check if transfer route is supported
329
- - `bridge(params)` - Execute cross-chain bridge operation
330
- - `estimate(params)` - Get cost estimates for transfer
331
-
332
- ### Transfer Parameters
333
-
334
- ```typescript
335
- interface BridgeParams {
336
- source: WalletContextWithFlexibleChain
337
- destination: WalletContextWithFlexibleChain
338
- amount: string
339
- config?: BridgeConfig
340
- }
341
- ```
342
-
343
247
  ## Development
344
248
 
345
249
  This package is part of the Stablecoin Kits monorepo.
package/index.cjs.js CHANGED
@@ -18,6 +18,17 @@
18
18
 
19
19
  'use strict';
20
20
 
21
+ // Buffer polyfill setup - executes before any other code
22
+ // Ensures globalThis.Buffer is available for @solana/spl-token and other Solana libraries
23
+ import { Buffer } from 'buffer';
24
+ if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
25
+ globalThis.Buffer = Buffer;
26
+ }
27
+ if (typeof window !== 'undefined' && typeof window.Buffer === 'undefined') {
28
+ window.Buffer = Buffer;
29
+ }
30
+
31
+
21
32
  var zod = require('zod');
22
33
  var bytes = require('@ethersproject/bytes');
23
34
  var address = require('@ethersproject/address');
@@ -2152,7 +2163,7 @@ var Chains = {
2152
2163
  *
2153
2164
  * @example
2154
2165
  * ```typescript
2155
- * import { isCCTPV2Supported } from '@circle-fin/bridging-kit'
2166
+ * import { isCCTPV2Supported } from '@circle-fin/bridge-kit'
2156
2167
  *
2157
2168
  * const isSupported = isCCTPV2Supported(ethChainDefinition)
2158
2169
  * console.log(isSupported) // true
@@ -2244,6 +2255,11 @@ const baseChainDefinitionSchema = zod.z.object({
2244
2255
  eurcAddress: zod.z.string().nullable(),
2245
2256
  usdcAddress: zod.z.string().nullable(),
2246
2257
  cctp: zod.z.any().nullable(), // We'll accept any CCTP config structure
2258
+ kitContracts: zod.z
2259
+ .object({
2260
+ bridge: zod.z.string().optional(),
2261
+ })
2262
+ .optional(),
2247
2263
  });
2248
2264
  /**
2249
2265
  * Zod schema for validating EVM chain definitions specifically.
@@ -2275,13 +2291,15 @@ const baseChainDefinitionSchema = zod.z.object({
2275
2291
  * }
2276
2292
  * ```
2277
2293
  */
2278
- const evmChainDefinitionSchema = baseChainDefinitionSchema.extend({
2294
+ const evmChainDefinitionSchema = baseChainDefinitionSchema
2295
+ .extend({
2279
2296
  type: zod.z.literal('evm'),
2280
2297
  chainId: zod.z.number({
2281
2298
  required_error: 'EVM chains must have a chainId. Please provide a valid EVM chain ID.',
2282
2299
  invalid_type_error: 'EVM chain ID must be a number.',
2283
2300
  }),
2284
- });
2301
+ })
2302
+ .strict(); //// Reject any additional properties not defined in the schema
2285
2303
  /**
2286
2304
  * Zod schema for validating non-EVM chain definitions.
2287
2305
  * This schema extends the base schema with non-EVM specific properties.
@@ -2301,7 +2319,7 @@ const nonEvmChainDefinitionSchema = baseChainDefinitionSchema
2301
2319
  'polkadot',
2302
2320
  ]),
2303
2321
  })
2304
- .strict(); // Reject additional properties like chainId
2322
+ .strict(); // Reject any additional properties not defined in the schema
2305
2323
  /**
2306
2324
  * Discriminated union schema for all chain definitions.
2307
2325
  * This schema validates different chain types based on their 'type' field.
@@ -2574,8 +2592,8 @@ class BridgingProvider {
2574
2592
  *
2575
2593
  * @example
2576
2594
  * ```typescript
2577
- * setKitIdentifier('bridging-kit', '1.2.3')
2578
- * getUserAgent() // "bridging-kit/1.2.3 (node/18.16.0)"
2595
+ * setKitIdentifier('bridge-kit', '1.2.3')
2596
+ * getUserAgent() // "bridge-kit/1.2.3 (node/18.16.0)"
2579
2597
  * ```
2580
2598
  *
2581
2599
  * @returns The Stablecoin Kits SDK user agent string.
@@ -2610,7 +2628,7 @@ function getRuntime() {
2610
2628
  /**
2611
2629
  * Get the user agent string for Stablecoin Kits SDK (universal, sync).
2612
2630
  *
2613
- * @returns The user agent string, e.g., "bridging-kit/1.2.3 (node/18.16.0)"
2631
+ * @returns The user agent string, e.g., "bridge-kit/1.2.3 (node/18.16.0)"
2614
2632
  */
2615
2633
  function getUserAgent() {
2616
2634
  if (cachedUserAgent !== undefined)
@@ -4188,67 +4206,48 @@ class KitError extends Error {
4188
4206
  }
4189
4207
 
4190
4208
  /**
4191
- * Standardized error codes for INPUT type errors.
4209
+ * Standardized error definitions for INPUT type errors.
4210
+ *
4211
+ * Each entry combines the numeric error code with its corresponding
4212
+ * string name to ensure consistency when creating error instances.
4192
4213
  *
4193
4214
  * Error codes follow a hierarchical numbering scheme where the first digit
4194
4215
  * indicates the error category (1 = INPUT) and subsequent digits provide
4195
4216
  * specific error identification within that category.
4196
4217
  *
4218
+ *
4197
4219
  * @example
4198
4220
  * ```typescript
4199
- * import { InputErrorCode, InputErrorName } from '@core/errors'
4221
+ * import { InputError } from '@core/errors'
4200
4222
  *
4201
4223
  * const error = new KitError({
4202
- * code: InputErrorCode.NETWORK_MISMATCH,
4203
- * name: InputErrorName.NETWORK_MISMATCH,
4224
+ * ...InputError.NETWORK_MISMATCH,
4204
4225
  * recoverability: 'FATAL',
4205
4226
  * message: 'Source and destination networks must be different'
4206
4227
  * })
4228
+ *
4229
+ * // Access code and name individually if needed
4230
+ * console.log(InputError.NETWORK_MISMATCH.code) // 1001
4231
+ * console.log(InputError.NETWORK_MISMATCH.name) // 'INPUT_NETWORK_MISMATCH'
4207
4232
  * ```
4208
4233
  */
4209
- var InputErrorCode;
4210
- (function (InputErrorCode) {
4234
+ const InputError = {
4211
4235
  /** Network type mismatch between chains (mainnet vs testnet) */
4212
- InputErrorCode[InputErrorCode["NETWORK_MISMATCH"] = 1001] = "NETWORK_MISMATCH";
4213
- /** Invalid amount format or value (negative, zero, or malformed) */
4214
- InputErrorCode[InputErrorCode["INVALID_AMOUNT"] = 1002] = "INVALID_AMOUNT";
4236
+ NETWORK_MISMATCH: {
4237
+ code: 1001,
4238
+ name: 'INPUT_NETWORK_MISMATCH',
4239
+ },
4215
4240
  /** Unsupported or invalid bridge route configuration */
4216
- InputErrorCode[InputErrorCode["UNSUPPORTED_ROUTE"] = 1003] = "UNSUPPORTED_ROUTE";
4217
- /** Invalid wallet or contract address format */
4218
- InputErrorCode[InputErrorCode["INVALID_ADDRESS"] = 1004] = "INVALID_ADDRESS";
4219
- /** Invalid or unsupported chain identifier */
4220
- InputErrorCode[InputErrorCode["INVALID_CHAIN"] = 1005] = "INVALID_CHAIN";
4241
+ UNSUPPORTED_ROUTE: {
4242
+ code: 1003,
4243
+ name: 'INPUT_UNSUPPORTED_ROUTE',
4244
+ },
4221
4245
  /** General validation failure for complex validation rules */
4222
- InputErrorCode[InputErrorCode["VALIDATION_FAILED"] = 1098] = "VALIDATION_FAILED";
4223
- })(InputErrorCode || (InputErrorCode = {}));
4224
- /**
4225
- * Standardized error names for INPUT type errors.
4226
- *
4227
- * These names correspond 1:1 with InputErrorCode and should always
4228
- * be used together to ensure consistency across error instances.
4229
- *
4230
- * @example
4231
- * ```typescript
4232
- * import { InputErrorCode, InputErrorName } from '@core/errors'
4233
- *
4234
- * // Use matching code and name enums
4235
- * const error = new KitError({
4236
- * code: InputErrorCode.NETWORK_MISMATCH,
4237
- * name: InputErrorName.NETWORK_MISMATCH,
4238
- * recoverability: 'FATAL',
4239
- * message: 'Network mismatch detected'
4240
- * })
4241
- * ```
4242
- */
4243
- var InputErrorName;
4244
- (function (InputErrorName) {
4245
- InputErrorName["NETWORK_MISMATCH"] = "INPUT_NETWORK_MISMATCH";
4246
- InputErrorName["INVALID_AMOUNT"] = "INPUT_INVALID_AMOUNT";
4247
- InputErrorName["UNSUPPORTED_ROUTE"] = "INPUT_UNSUPPORTED_ROUTE";
4248
- InputErrorName["INVALID_ADDRESS"] = "INPUT_INVALID_ADDRESS";
4249
- InputErrorName["INVALID_CHAIN"] = "INPUT_INVALID_CHAIN";
4250
- InputErrorName["VALIDATION_FAILED"] = "INPUT_VALIDATION_FAILED";
4251
- })(InputErrorName || (InputErrorName = {}));
4246
+ VALIDATION_FAILED: {
4247
+ code: 1098,
4248
+ name: 'INPUT_VALIDATION_FAILED',
4249
+ },
4250
+ };
4252
4251
 
4253
4252
  /**
4254
4253
  * Creates error for network type mismatch between source and destination.
@@ -4275,8 +4274,7 @@ function createNetworkMismatchError(sourceChain, destChain) {
4275
4274
  const sourceNetworkType = sourceChain.isTestnet ? 'testnet' : 'mainnet';
4276
4275
  const destNetworkType = destChain.isTestnet ? 'testnet' : 'mainnet';
4277
4276
  const errorDetails = {
4278
- code: InputErrorCode.NETWORK_MISMATCH,
4279
- name: InputErrorName.NETWORK_MISMATCH,
4277
+ ...InputError.NETWORK_MISMATCH,
4280
4278
  recoverability: 'FATAL',
4281
4279
  message: `Cannot bridge between ${sourceChain.name} (${sourceNetworkType}) and ${destChain.name} (${destNetworkType}). Source and destination networks must both be testnet or both be mainnet.`,
4282
4280
  cause: {
@@ -4305,8 +4303,7 @@ function createNetworkMismatchError(sourceChain, destChain) {
4305
4303
  */
4306
4304
  function createUnsupportedRouteError(source, destination) {
4307
4305
  const errorDetails = {
4308
- code: InputErrorCode.UNSUPPORTED_ROUTE,
4309
- name: InputErrorName.UNSUPPORTED_ROUTE,
4306
+ ...InputError.UNSUPPORTED_ROUTE,
4310
4307
  recoverability: 'FATAL',
4311
4308
  message: `Route from ${source} to ${destination} is not supported.`,
4312
4309
  cause: {
@@ -4353,8 +4350,7 @@ function createValidationFailedError(field, value, reason) {
4353
4350
  valueString = String(value);
4354
4351
  }
4355
4352
  const errorDetails = {
4356
- code: InputErrorCode.VALIDATION_FAILED,
4357
- name: InputErrorName.VALIDATION_FAILED,
4353
+ ...InputError.VALIDATION_FAILED,
4358
4354
  recoverability: 'FATAL',
4359
4355
  message: `Validation failed for '${field}': ${valueString} - ${reason}.`,
4360
4356
  cause: {
@@ -4518,15 +4514,21 @@ mintAddress) => {
4518
4514
  return rawAddress;
4519
4515
  }
4520
4516
  else {
4521
- const [{ getAssociatedTokenAddress }, { PublicKey }] = await Promise.all([
4522
- import('@solana/spl-token'),
4523
- import('@solana/web3.js'),
4524
- ]);
4525
4517
  // Solana: derive the associated token account
4526
- const owner = new PublicKey(rawAddress);
4527
- const mintPub = new PublicKey(mintAddress);
4528
- const ata = await getAssociatedTokenAddress(mintPub, owner);
4529
- return ata.toBase58();
4518
+ // Use dynamic import to avoid loading Solana dependencies for EVM-only users
4519
+ try {
4520
+ const [{ PublicKey }, { getAssociatedTokenAddressSync }] = await Promise.all([
4521
+ import('@solana/web3.js'),
4522
+ import('@solana/spl-token'),
4523
+ ]);
4524
+ const owner = new PublicKey(rawAddress);
4525
+ const mintPub = new PublicKey(mintAddress);
4526
+ const ata = getAssociatedTokenAddressSync(mintPub, owner);
4527
+ return ata.toBase58();
4528
+ }
4529
+ catch {
4530
+ throw new Error('Failed to derive Solana token account. Please ensure @solana/web3.js and @solana/spl-token are installed: npm install @solana/web3.js @solana/spl-token');
4531
+ }
4530
4532
  }
4531
4533
  };
4532
4534
 
@@ -4764,6 +4766,7 @@ async function bridgeFetchAttestation({ params, provider, }, txHash) {
4764
4766
  ...step,
4765
4767
  state: 'error',
4766
4768
  error: err,
4769
+ data: undefined,
4767
4770
  };
4768
4771
  }
4769
4772
  return step;
@@ -4946,12 +4949,29 @@ async function bridge(params, provider) {
4946
4949
  throw new Error(`${name} step failed: ${errorDetails}`);
4947
4950
  }
4948
4951
  context = updateContext?.(step);
4949
- provider.actionDispatcher?.dispatch(name, {
4952
+ const actionValues = {
4950
4953
  protocol: 'cctp',
4951
4954
  version: 'v2',
4952
- method: name,
4953
- values: step.data,
4954
- });
4955
+ values: step,
4956
+ };
4957
+ // use a switch statement for type safety to separate the different step types
4958
+ switch (name) {
4959
+ case 'approve':
4960
+ case 'burn':
4961
+ case 'mint':
4962
+ provider.actionDispatcher?.dispatch(name, {
4963
+ ...actionValues,
4964
+ method: name,
4965
+ });
4966
+ break;
4967
+ case 'fetchAttestation':
4968
+ provider.actionDispatcher?.dispatch(name, {
4969
+ ...actionValues,
4970
+ method: name,
4971
+ values: step,
4972
+ });
4973
+ break;
4974
+ }
4955
4975
  result.steps.push(step);
4956
4976
  }
4957
4977
  catch (error) {
@@ -5207,7 +5227,6 @@ base58StringSchema.refine((value) => value.length >= 86 && value.length <= 88, '
5207
5227
  zod.z.object({
5208
5228
  prepare: zod.z.function(),
5209
5229
  waitForTransaction: zod.z.function(),
5210
- getChain: zod.z.function(),
5211
5230
  getAddress: zod.z.function(),
5212
5231
  });
5213
5232
 
@@ -5730,9 +5749,9 @@ class CCTPV2BridgingProvider extends BridgingProvider {
5730
5749
  *
5731
5750
  * @param params - The bridge parameters containing source, destination, amount, and optional config.
5732
5751
  * @returns A promise resolving to the bridge result, including transaction details, step states, and explorer URLs.
5733
- * @throws {ValidationError} If the parameters are invalid
5734
- * @throws {BridgeError} If the bridge operation fails
5735
- * @throws {UnsupportedRouteError} If the route is not supported
5752
+ * @throws {ValidationError} When the parameters are invalid.
5753
+ * @throws {BridgeError} When the bridge operation fails.
5754
+ * @throws {UnsupportedRouteError} When the route is not supported.
5736
5755
  *
5737
5756
  * @example
5738
5757
  * ```typescript
@@ -5794,9 +5813,14 @@ class CCTPV2BridgingProvider extends BridgingProvider {
5794
5813
  * chains, as well as any applicable protocol fees.
5795
5814
  *
5796
5815
  * @param params - The bridge parameters containing source, destination, amount, and optional config.
5797
- * @returns Promise resolving to detailed cost breakdown including gas estimates and protocol fees
5798
- * @throws {ValidationError} If the parameters are invalid
5799
- * @throws {UnsupportedRouteError} If the route is not supported
5816
+ * @returns Promise resolving to detailed cost breakdown including:
5817
+ * - `gasFees`: Array of gas estimates for each step (Approve, Burn, Mint)
5818
+ * - Gas amounts in native token smallest units (wei for ETH, lamports for SOL, etc.)
5819
+ * - `fees`: Array of protocol and kit fees
5820
+ * - Provider fees in USDC decimal units (e.g., "0.1" USDC)
5821
+ * - Kit fees in USDC decimal units if configured
5822
+ * @throws {ValidationError} When the parameters are invalid.
5823
+ * @throws {UnsupportedRouteError} When the route is not supported.
5800
5824
  *
5801
5825
  * @example
5802
5826
  * ```typescript
@@ -6063,6 +6087,7 @@ class CCTPV2BridgingProvider extends BridgingProvider {
6063
6087
  message: attestation.message,
6064
6088
  attestation: attestation.attestation,
6065
6089
  eventNonce: attestation.eventNonce,
6090
+ destinationAddress: destination.address,
6066
6091
  };
6067
6092
  // Single call with or without context
6068
6093
  if (resolvedContext) {
@@ -6176,28 +6201,29 @@ class CCTPV2BridgingProvider extends BridgingProvider {
6176
6201
  return false;
6177
6202
  }
6178
6203
  /**
6179
- * This method determines the appropriate maximum fee for a cross-chain bridge operation
6180
- * based on the configured bridge speed and chain requirements.
6204
+ * Determines the appropriate maximum fee for a cross-chain bridge operation.
6181
6205
  *
6182
6206
  * For FAST bridge operations, it calculates a dynamic fee based on the bridge amount
6183
6207
  * and fast bridge burn fee, or uses a provided maxFee if specified.
6184
6208
  *
6185
6209
  * For SLOW bridge operations, it returns 0 as there are no additional fees.
6186
6210
  *
6187
- * @param sourceChain - The source chain definition where the bridge originates
6188
- * @param destinationChain - The destination chain definition where tokens will be minted
6189
- * @param amount - The bridge amount in minor units (e.g., "1000000" for 1 USDC)
6190
- * @param config - Optional bridge configuration including speed and fee settings
6191
- * @returns The maximum fee to be used for the bridge operation
6211
+ * @param params - The bridge parameters object containing:
6212
+ * - `source`: The source wallet context with chain definition and adapter
6213
+ * - `destination`: The destination wallet context with chain definition and adapter
6214
+ * - `amount`: The bridge amount in minor units (e.g., "1000000" for 1 USDC)
6215
+ * - `config`: Optional bridge configuration including transferSpeed and maxFee settings
6216
+ * @returns The maximum fee to be used for the bridge operation in minor units
6192
6217
  *
6193
6218
  * @example
6194
6219
  * ```typescript
6195
- * const maxFee = await provider.getMaxFee(
6196
- * sourceChain,
6197
- * destinationChain,
6198
- * '1000000', // 1 USDC
6199
- * { transferSpeed: 'FAST' }
6200
- * )
6220
+ * const maxFee = await provider.getMaxFee({
6221
+ * source: { adapter: sourceAdapter, chain: Chains.Ethereum, address: '0x...' },
6222
+ * destination: { adapter: destAdapter, chain: Chains.Base, address: '0x...' },
6223
+ * amount: '1000000', // 1 USDC
6224
+ * token: 'USDC',
6225
+ * config: { transferSpeed: TransferSpeed.FAST }
6226
+ * })
6201
6227
  * console.log('Max fee:', maxFee)
6202
6228
  * ```
6203
6229
  */
@@ -6264,8 +6290,11 @@ class CCTPV2BridgingProvider extends BridgingProvider {
6264
6290
  // Get the min finality threshold based on the transfer speed
6265
6291
  const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
6266
6292
  // Calculate the max fee
6267
- const maxFee = await this.getMaxFee(params);
6268
- const mintRecipient = await getMintRecipientAccount(destination.chain.type, destination.address ?? (await destination.adapter.getAddress()), destination.chain.usdcAddress);
6293
+ const [maxFee, mintRecipient] = await Promise.all([
6294
+ this.getMaxFee(params),
6295
+ getMintRecipientAccount(destination.chain.type, destination.address ??
6296
+ (await destination.adapter.getAddress(destination.chain)), destination.chain.usdcAddress),
6297
+ ]);
6269
6298
  const actionParams = {
6270
6299
  fromChain: source.chain,
6271
6300
  toChain: destination.chain,
package/index.d.ts CHANGED
@@ -1167,6 +1167,14 @@ interface CCTPv2ActionMap {
1167
1167
  * Destination chain definition where tokens will be minted.
1168
1168
  */
1169
1169
  readonly toChain: ChainDefinitionWithCCTPv2;
1170
+ /**
1171
+ * Optional destination wallet address on the destination chain to receive minted USDC.
1172
+ *
1173
+ * When provided (e.g., for Solana), the mint instruction will derive the
1174
+ * recipient's Associated Token Account (ATA) from this address instead of
1175
+ * the adapter's default address.
1176
+ */
1177
+ readonly destinationAddress?: string;
1170
1178
  };
1171
1179
  /**
1172
1180
  * Initiate a cross-chain USDC transfer using a custom bridge contract with preapproval funnel.
@@ -1524,7 +1532,7 @@ interface USDCActionMap {
1524
1532
  /**
1525
1533
  * Central registry of all available action namespaces and their operations.
1526
1534
  *
1527
- * Define the complete action map structure used throughout the bridging kit.
1535
+ * Define the complete action map structure used throughout the bridge kit.
1528
1536
  * Each top-level key represents a namespace (e.g., 'token', 'usdc') containing
1529
1537
  * related operations. The structure supports arbitrary nesting depth through
1530
1538
  * the recursive utility types provided in this module.
@@ -1617,7 +1625,7 @@ type NestedValue<T, K extends string> = K extends `${infer First}.${infer Rest}`
1617
1625
  *
1618
1626
  * @remarks
1619
1627
  * This type serves as the canonical source for all valid action identifiers
1620
- * in the bridging kit. It ensures compile-time validation of action keys
1628
+ * in the bridge kit. It ensures compile-time validation of action keys
1621
1629
  * and enables type-safe action dispatching throughout the application.
1622
1630
  *
1623
1631
  * @see {@link ActionPayload} for extracting parameter types
@@ -1986,26 +1994,6 @@ declare abstract class Adapter<TAdapterCapabilities extends AdapterCapabilities
1986
1994
  * ```
1987
1995
  */
1988
1996
  capabilities?: TAdapterCapabilities;
1989
- /**
1990
- * Default chain for operations when none is explicitly provided.
1991
- *
1992
- * This allows adapters to have sensible defaults for chain operations,
1993
- * reducing the need for explicit chain specification in every call.
1994
- *
1995
- * @remarks
1996
- * This is optional for backward compatibility and because some adapter types
1997
- * (like developer-controlled adapters) may not have meaningful defaults.
1998
- *
1999
- * @example
2000
- * ```typescript
2001
- * // User-controlled adapter with default chain
2002
- * defaultChain = Ethereum
2003
- *
2004
- * // Developer-controlled adapter (no default)
2005
- * defaultChain = undefined
2006
- * ```
2007
- */
2008
- defaultChain?: ChainDefinition;
2009
1997
  /**
2010
1998
  * Registry of available actions for this adapter.
2011
1999
  *
@@ -2119,16 +2107,6 @@ declare abstract class Adapter<TAdapterCapabilities extends AdapterCapabilities
2119
2107
  * @returns A promise that resolves to the blockchain address as a string.
2120
2108
  */
2121
2109
  abstract getAddress(chain?: ChainDefinition): Promise<string>;
2122
- /**
2123
- * Retrieves the {@link ChainDefinition} object that describes the blockchain
2124
- * this adapter is configured to interact with.
2125
- *
2126
- * This includes information such as the chain ID, name, native currency, etc.,
2127
- * as defined by the `ChainDefinition` type.
2128
- *
2129
- * @returns A promise that resolves to the {@link ChainDefinition} for the current chain.
2130
- */
2131
- abstract getChain(): Promise<ChainDefinition>;
2132
2110
  /**
2133
2111
  * Switches the adapter to operate on the specified chain.
2134
2112
  *
@@ -2173,17 +2151,14 @@ declare abstract class Adapter<TAdapterCapabilities extends AdapterCapabilities
2173
2151
  * - **Browser wallet adapters**: Request chain switch via EIP-1193 or equivalent
2174
2152
  * - **Multi-entity adapters**: Validate chain support (operations are contextual)
2175
2153
  *
2176
- * @param chain - The target chain for operations. If not provided, uses the adapter's defaultChain.
2154
+ * @param chain - The target chain for operations.
2177
2155
  * @returns A promise that resolves when the adapter is operating on the specified chain.
2178
2156
  * @throws When the target chain is not supported or chain switching fails.
2179
2157
  *
2180
2158
  * @remarks
2181
- * This method replaces the pattern of calling `getChain()` to check current chain and then
2182
- * manually switching. It provides a declarative "ensure this chain" interface for operations.
2183
- *
2184
- * **Backward Compatibility**: The default implementation provides basic validation but
2185
- * doesn't perform actual chain switching. Concrete adapter implementations should override
2186
- * this method to provide proper chain switching logic.
2159
+ * This method always calls `switchToChain()` to ensure consistency across all adapter types.
2160
+ * The underlying implementations handle idempotent switching efficiently (e.g., browser wallets
2161
+ * gracefully handle switching to the current chain, private key adapters recreate lightweight clients).
2187
2162
  *
2188
2163
  * @example
2189
2164
  * ```typescript
@@ -2197,7 +2172,7 @@ declare abstract class Adapter<TAdapterCapabilities extends AdapterCapabilities
2197
2172
  * await circleWalletsAdapter.ensureChain(Ethereum)
2198
2173
  * ```
2199
2174
  */
2200
- ensureChain(chain?: ChainDefinition): Promise<void>;
2175
+ ensureChain(targetChain: ChainDefinition): Promise<void>;
2201
2176
  /**
2202
2177
  * Validate that the target chain is supported by this adapter.
2203
2178
  *
@@ -2264,7 +2239,7 @@ interface ApiPollingConfig {
2264
2239
  *
2265
2240
  * @example
2266
2241
  * ```typescript
2267
- * import { Actionable } from '@circle/bridging-kit/utils';
2242
+ * import { Actionable } from '@circle-fin/bridge-kit/utils';
2268
2243
  *
2269
2244
  * // Define your action types
2270
2245
  * type TransferActions = {
@@ -2584,7 +2559,7 @@ interface EstimateResult {
2584
2559
  }[];
2585
2560
  /** Array of protocol and service fees for the transfer */
2586
2561
  fees: {
2587
- /** The type of fee - either from the bridging kit or the underlying provider */
2562
+ /** The type of fee - either from the bridge kit or the underlying provider */
2588
2563
  type: 'kit' | 'provider';
2589
2564
  /** The token in which the fee is charged (currently only USDC) */
2590
2565
  token: 'USDC';
@@ -2647,10 +2622,9 @@ interface BridgeConfig {
2647
2622
  interface CustomFee {
2648
2623
  /**
2649
2624
  * The absolute fee to charge for the transfer.
2650
- * Provide the amount in the token's smallest unit (e.g., USDC uses 6 decimals)
2651
- * as a base-10 numeric string. This is not a percentage.
2652
- *
2653
- * For example: to charge 1 USDC, pass `'1000000'`.
2625
+ * Provide the amount as a base-10 numeric string representing the integer amount of the token (not in smallest units).
2626
+ * For example: to charge 1 USDC or 1 USDC, pass `'1'`.
2627
+ * This is not a percentage.
2654
2628
  *
2655
2629
  * Note: passing `'0'` results in no fee being charged.
2656
2630
  */
@@ -3125,6 +3099,7 @@ type BridgeFetchAttestationStep = BridgeStep &
3125
3099
  | {
3126
3100
  state: 'pending';
3127
3101
  txHash?: string;
3102
+ data?: undefined;
3128
3103
  }
3129
3104
  /**
3130
3105
  * The error state of the fetch attestation step.
@@ -3132,6 +3107,7 @@ type BridgeFetchAttestationStep = BridgeStep &
3132
3107
  | {
3133
3108
  state: 'error';
3134
3109
  error: unknown;
3110
+ data?: undefined;
3135
3111
  });
3136
3112
 
3137
3113
  /**
@@ -3349,9 +3325,9 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3349
3325
  *
3350
3326
  * @param params - The bridge parameters containing source, destination, amount, and optional config.
3351
3327
  * @returns A promise resolving to the bridge result, including transaction details, step states, and explorer URLs.
3352
- * @throws {ValidationError} If the parameters are invalid
3353
- * @throws {BridgeError} If the bridge operation fails
3354
- * @throws {UnsupportedRouteError} If the route is not supported
3328
+ * @throws {ValidationError} When the parameters are invalid.
3329
+ * @throws {BridgeError} When the bridge operation fails.
3330
+ * @throws {UnsupportedRouteError} When the route is not supported.
3355
3331
  *
3356
3332
  * @example
3357
3333
  * ```typescript
@@ -3396,9 +3372,14 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3396
3372
  * chains, as well as any applicable protocol fees.
3397
3373
  *
3398
3374
  * @param params - The bridge parameters containing source, destination, amount, and optional config.
3399
- * @returns Promise resolving to detailed cost breakdown including gas estimates and protocol fees
3400
- * @throws {ValidationError} If the parameters are invalid
3401
- * @throws {UnsupportedRouteError} If the route is not supported
3375
+ * @returns Promise resolving to detailed cost breakdown including:
3376
+ * - `gasFees`: Array of gas estimates for each step (Approve, Burn, Mint)
3377
+ * - Gas amounts in native token smallest units (wei for ETH, lamports for SOL, etc.)
3378
+ * - `fees`: Array of protocol and kit fees
3379
+ * - Provider fees in USDC decimal units (e.g., "0.1" USDC)
3380
+ * - Kit fees in USDC decimal units if configured
3381
+ * @throws {ValidationError} When the parameters are invalid.
3382
+ * @throws {UnsupportedRouteError} When the route is not supported.
3402
3383
  *
3403
3384
  * @example
3404
3385
  * ```typescript
@@ -3576,28 +3557,29 @@ declare class CCTPV2BridgingProvider extends BridgingProvider<CCTPV2Actions> imp
3576
3557
  */
3577
3558
  supportsRoute(source: ChainDefinition, destination: ChainDefinition, token: 'USDC'): boolean;
3578
3559
  /**
3579
- * This method determines the appropriate maximum fee for a cross-chain bridge operation
3580
- * based on the configured bridge speed and chain requirements.
3560
+ * Determines the appropriate maximum fee for a cross-chain bridge operation.
3581
3561
  *
3582
3562
  * For FAST bridge operations, it calculates a dynamic fee based on the bridge amount
3583
3563
  * and fast bridge burn fee, or uses a provided maxFee if specified.
3584
3564
  *
3585
3565
  * For SLOW bridge operations, it returns 0 as there are no additional fees.
3586
3566
  *
3587
- * @param sourceChain - The source chain definition where the bridge originates
3588
- * @param destinationChain - The destination chain definition where tokens will be minted
3589
- * @param amount - The bridge amount in minor units (e.g., "1000000" for 1 USDC)
3590
- * @param config - Optional bridge configuration including speed and fee settings
3591
- * @returns The maximum fee to be used for the bridge operation
3567
+ * @param params - The bridge parameters object containing:
3568
+ * - `source`: The source wallet context with chain definition and adapter
3569
+ * - `destination`: The destination wallet context with chain definition and adapter
3570
+ * - `amount`: The bridge amount in minor units (e.g., "1000000" for 1 USDC)
3571
+ * - `config`: Optional bridge configuration including transferSpeed and maxFee settings
3572
+ * @returns The maximum fee to be used for the bridge operation in minor units
3592
3573
  *
3593
3574
  * @example
3594
3575
  * ```typescript
3595
- * const maxFee = await provider.getMaxFee(
3596
- * sourceChain,
3597
- * destinationChain,
3598
- * '1000000', // 1 USDC
3599
- * { transferSpeed: 'FAST' }
3600
- * )
3576
+ * const maxFee = await provider.getMaxFee({
3577
+ * source: { adapter: sourceAdapter, chain: Chains.Ethereum, address: '0x...' },
3578
+ * destination: { adapter: destAdapter, chain: Chains.Base, address: '0x...' },
3579
+ * amount: '1000000', // 1 USDC
3580
+ * token: 'USDC',
3581
+ * config: { transferSpeed: TransferSpeed.FAST }
3582
+ * })
3601
3583
  * console.log('Max fee:', maxFee)
3602
3584
  * ```
3603
3585
  */
package/index.mjs CHANGED
@@ -16,6 +16,17 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
+ // Buffer polyfill setup - executes before any other code
20
+ // Ensures globalThis.Buffer is available for @solana/spl-token and other Solana libraries
21
+ import { Buffer } from 'buffer';
22
+ if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
23
+ globalThis.Buffer = Buffer;
24
+ }
25
+ if (typeof window !== 'undefined' && typeof window.Buffer === 'undefined') {
26
+ window.Buffer = Buffer;
27
+ }
28
+
29
+
19
30
  import { z } from 'zod';
20
31
  import { hexlify, hexZeroPad } from '@ethersproject/bytes';
21
32
  import { getAddress } from '@ethersproject/address';
@@ -2146,7 +2157,7 @@ var Chains = /*#__PURE__*/Object.freeze({
2146
2157
  *
2147
2158
  * @example
2148
2159
  * ```typescript
2149
- * import { isCCTPV2Supported } from '@circle-fin/bridging-kit'
2160
+ * import { isCCTPV2Supported } from '@circle-fin/bridge-kit'
2150
2161
  *
2151
2162
  * const isSupported = isCCTPV2Supported(ethChainDefinition)
2152
2163
  * console.log(isSupported) // true
@@ -2238,6 +2249,11 @@ const baseChainDefinitionSchema = z.object({
2238
2249
  eurcAddress: z.string().nullable(),
2239
2250
  usdcAddress: z.string().nullable(),
2240
2251
  cctp: z.any().nullable(), // We'll accept any CCTP config structure
2252
+ kitContracts: z
2253
+ .object({
2254
+ bridge: z.string().optional(),
2255
+ })
2256
+ .optional(),
2241
2257
  });
2242
2258
  /**
2243
2259
  * Zod schema for validating EVM chain definitions specifically.
@@ -2269,13 +2285,15 @@ const baseChainDefinitionSchema = z.object({
2269
2285
  * }
2270
2286
  * ```
2271
2287
  */
2272
- const evmChainDefinitionSchema = baseChainDefinitionSchema.extend({
2288
+ const evmChainDefinitionSchema = baseChainDefinitionSchema
2289
+ .extend({
2273
2290
  type: z.literal('evm'),
2274
2291
  chainId: z.number({
2275
2292
  required_error: 'EVM chains must have a chainId. Please provide a valid EVM chain ID.',
2276
2293
  invalid_type_error: 'EVM chain ID must be a number.',
2277
2294
  }),
2278
- });
2295
+ })
2296
+ .strict(); //// Reject any additional properties not defined in the schema
2279
2297
  /**
2280
2298
  * Zod schema for validating non-EVM chain definitions.
2281
2299
  * This schema extends the base schema with non-EVM specific properties.
@@ -2295,7 +2313,7 @@ const nonEvmChainDefinitionSchema = baseChainDefinitionSchema
2295
2313
  'polkadot',
2296
2314
  ]),
2297
2315
  })
2298
- .strict(); // Reject additional properties like chainId
2316
+ .strict(); // Reject any additional properties not defined in the schema
2299
2317
  /**
2300
2318
  * Discriminated union schema for all chain definitions.
2301
2319
  * This schema validates different chain types based on their 'type' field.
@@ -2568,8 +2586,8 @@ class BridgingProvider {
2568
2586
  *
2569
2587
  * @example
2570
2588
  * ```typescript
2571
- * setKitIdentifier('bridging-kit', '1.2.3')
2572
- * getUserAgent() // "bridging-kit/1.2.3 (node/18.16.0)"
2589
+ * setKitIdentifier('bridge-kit', '1.2.3')
2590
+ * getUserAgent() // "bridge-kit/1.2.3 (node/18.16.0)"
2573
2591
  * ```
2574
2592
  *
2575
2593
  * @returns The Stablecoin Kits SDK user agent string.
@@ -2604,7 +2622,7 @@ function getRuntime() {
2604
2622
  /**
2605
2623
  * Get the user agent string for Stablecoin Kits SDK (universal, sync).
2606
2624
  *
2607
- * @returns The user agent string, e.g., "bridging-kit/1.2.3 (node/18.16.0)"
2625
+ * @returns The user agent string, e.g., "bridge-kit/1.2.3 (node/18.16.0)"
2608
2626
  */
2609
2627
  function getUserAgent() {
2610
2628
  if (cachedUserAgent !== undefined)
@@ -4182,67 +4200,48 @@ class KitError extends Error {
4182
4200
  }
4183
4201
 
4184
4202
  /**
4185
- * Standardized error codes for INPUT type errors.
4203
+ * Standardized error definitions for INPUT type errors.
4204
+ *
4205
+ * Each entry combines the numeric error code with its corresponding
4206
+ * string name to ensure consistency when creating error instances.
4186
4207
  *
4187
4208
  * Error codes follow a hierarchical numbering scheme where the first digit
4188
4209
  * indicates the error category (1 = INPUT) and subsequent digits provide
4189
4210
  * specific error identification within that category.
4190
4211
  *
4212
+ *
4191
4213
  * @example
4192
4214
  * ```typescript
4193
- * import { InputErrorCode, InputErrorName } from '@core/errors'
4215
+ * import { InputError } from '@core/errors'
4194
4216
  *
4195
4217
  * const error = new KitError({
4196
- * code: InputErrorCode.NETWORK_MISMATCH,
4197
- * name: InputErrorName.NETWORK_MISMATCH,
4218
+ * ...InputError.NETWORK_MISMATCH,
4198
4219
  * recoverability: 'FATAL',
4199
4220
  * message: 'Source and destination networks must be different'
4200
4221
  * })
4222
+ *
4223
+ * // Access code and name individually if needed
4224
+ * console.log(InputError.NETWORK_MISMATCH.code) // 1001
4225
+ * console.log(InputError.NETWORK_MISMATCH.name) // 'INPUT_NETWORK_MISMATCH'
4201
4226
  * ```
4202
4227
  */
4203
- var InputErrorCode;
4204
- (function (InputErrorCode) {
4228
+ const InputError = {
4205
4229
  /** Network type mismatch between chains (mainnet vs testnet) */
4206
- InputErrorCode[InputErrorCode["NETWORK_MISMATCH"] = 1001] = "NETWORK_MISMATCH";
4207
- /** Invalid amount format or value (negative, zero, or malformed) */
4208
- InputErrorCode[InputErrorCode["INVALID_AMOUNT"] = 1002] = "INVALID_AMOUNT";
4230
+ NETWORK_MISMATCH: {
4231
+ code: 1001,
4232
+ name: 'INPUT_NETWORK_MISMATCH',
4233
+ },
4209
4234
  /** Unsupported or invalid bridge route configuration */
4210
- InputErrorCode[InputErrorCode["UNSUPPORTED_ROUTE"] = 1003] = "UNSUPPORTED_ROUTE";
4211
- /** Invalid wallet or contract address format */
4212
- InputErrorCode[InputErrorCode["INVALID_ADDRESS"] = 1004] = "INVALID_ADDRESS";
4213
- /** Invalid or unsupported chain identifier */
4214
- InputErrorCode[InputErrorCode["INVALID_CHAIN"] = 1005] = "INVALID_CHAIN";
4235
+ UNSUPPORTED_ROUTE: {
4236
+ code: 1003,
4237
+ name: 'INPUT_UNSUPPORTED_ROUTE',
4238
+ },
4215
4239
  /** General validation failure for complex validation rules */
4216
- InputErrorCode[InputErrorCode["VALIDATION_FAILED"] = 1098] = "VALIDATION_FAILED";
4217
- })(InputErrorCode || (InputErrorCode = {}));
4218
- /**
4219
- * Standardized error names for INPUT type errors.
4220
- *
4221
- * These names correspond 1:1 with InputErrorCode and should always
4222
- * be used together to ensure consistency across error instances.
4223
- *
4224
- * @example
4225
- * ```typescript
4226
- * import { InputErrorCode, InputErrorName } from '@core/errors'
4227
- *
4228
- * // Use matching code and name enums
4229
- * const error = new KitError({
4230
- * code: InputErrorCode.NETWORK_MISMATCH,
4231
- * name: InputErrorName.NETWORK_MISMATCH,
4232
- * recoverability: 'FATAL',
4233
- * message: 'Network mismatch detected'
4234
- * })
4235
- * ```
4236
- */
4237
- var InputErrorName;
4238
- (function (InputErrorName) {
4239
- InputErrorName["NETWORK_MISMATCH"] = "INPUT_NETWORK_MISMATCH";
4240
- InputErrorName["INVALID_AMOUNT"] = "INPUT_INVALID_AMOUNT";
4241
- InputErrorName["UNSUPPORTED_ROUTE"] = "INPUT_UNSUPPORTED_ROUTE";
4242
- InputErrorName["INVALID_ADDRESS"] = "INPUT_INVALID_ADDRESS";
4243
- InputErrorName["INVALID_CHAIN"] = "INPUT_INVALID_CHAIN";
4244
- InputErrorName["VALIDATION_FAILED"] = "INPUT_VALIDATION_FAILED";
4245
- })(InputErrorName || (InputErrorName = {}));
4240
+ VALIDATION_FAILED: {
4241
+ code: 1098,
4242
+ name: 'INPUT_VALIDATION_FAILED',
4243
+ },
4244
+ };
4246
4245
 
4247
4246
  /**
4248
4247
  * Creates error for network type mismatch between source and destination.
@@ -4269,8 +4268,7 @@ function createNetworkMismatchError(sourceChain, destChain) {
4269
4268
  const sourceNetworkType = sourceChain.isTestnet ? 'testnet' : 'mainnet';
4270
4269
  const destNetworkType = destChain.isTestnet ? 'testnet' : 'mainnet';
4271
4270
  const errorDetails = {
4272
- code: InputErrorCode.NETWORK_MISMATCH,
4273
- name: InputErrorName.NETWORK_MISMATCH,
4271
+ ...InputError.NETWORK_MISMATCH,
4274
4272
  recoverability: 'FATAL',
4275
4273
  message: `Cannot bridge between ${sourceChain.name} (${sourceNetworkType}) and ${destChain.name} (${destNetworkType}). Source and destination networks must both be testnet or both be mainnet.`,
4276
4274
  cause: {
@@ -4299,8 +4297,7 @@ function createNetworkMismatchError(sourceChain, destChain) {
4299
4297
  */
4300
4298
  function createUnsupportedRouteError(source, destination) {
4301
4299
  const errorDetails = {
4302
- code: InputErrorCode.UNSUPPORTED_ROUTE,
4303
- name: InputErrorName.UNSUPPORTED_ROUTE,
4300
+ ...InputError.UNSUPPORTED_ROUTE,
4304
4301
  recoverability: 'FATAL',
4305
4302
  message: `Route from ${source} to ${destination} is not supported.`,
4306
4303
  cause: {
@@ -4347,8 +4344,7 @@ function createValidationFailedError(field, value, reason) {
4347
4344
  valueString = String(value);
4348
4345
  }
4349
4346
  const errorDetails = {
4350
- code: InputErrorCode.VALIDATION_FAILED,
4351
- name: InputErrorName.VALIDATION_FAILED,
4347
+ ...InputError.VALIDATION_FAILED,
4352
4348
  recoverability: 'FATAL',
4353
4349
  message: `Validation failed for '${field}': ${valueString} - ${reason}.`,
4354
4350
  cause: {
@@ -4512,15 +4508,21 @@ mintAddress) => {
4512
4508
  return rawAddress;
4513
4509
  }
4514
4510
  else {
4515
- const [{ getAssociatedTokenAddress }, { PublicKey }] = await Promise.all([
4516
- import('@solana/spl-token'),
4517
- import('@solana/web3.js'),
4518
- ]);
4519
4511
  // Solana: derive the associated token account
4520
- const owner = new PublicKey(rawAddress);
4521
- const mintPub = new PublicKey(mintAddress);
4522
- const ata = await getAssociatedTokenAddress(mintPub, owner);
4523
- return ata.toBase58();
4512
+ // Use dynamic import to avoid loading Solana dependencies for EVM-only users
4513
+ try {
4514
+ const [{ PublicKey }, { getAssociatedTokenAddressSync }] = await Promise.all([
4515
+ import('@solana/web3.js'),
4516
+ import('@solana/spl-token'),
4517
+ ]);
4518
+ const owner = new PublicKey(rawAddress);
4519
+ const mintPub = new PublicKey(mintAddress);
4520
+ const ata = getAssociatedTokenAddressSync(mintPub, owner);
4521
+ return ata.toBase58();
4522
+ }
4523
+ catch {
4524
+ throw new Error('Failed to derive Solana token account. Please ensure @solana/web3.js and @solana/spl-token are installed: npm install @solana/web3.js @solana/spl-token');
4525
+ }
4524
4526
  }
4525
4527
  };
4526
4528
 
@@ -4758,6 +4760,7 @@ async function bridgeFetchAttestation({ params, provider, }, txHash) {
4758
4760
  ...step,
4759
4761
  state: 'error',
4760
4762
  error: err,
4763
+ data: undefined,
4761
4764
  };
4762
4765
  }
4763
4766
  return step;
@@ -4940,12 +4943,29 @@ async function bridge(params, provider) {
4940
4943
  throw new Error(`${name} step failed: ${errorDetails}`);
4941
4944
  }
4942
4945
  context = updateContext?.(step);
4943
- provider.actionDispatcher?.dispatch(name, {
4946
+ const actionValues = {
4944
4947
  protocol: 'cctp',
4945
4948
  version: 'v2',
4946
- method: name,
4947
- values: step.data,
4948
- });
4949
+ values: step,
4950
+ };
4951
+ // use a switch statement for type safety to separate the different step types
4952
+ switch (name) {
4953
+ case 'approve':
4954
+ case 'burn':
4955
+ case 'mint':
4956
+ provider.actionDispatcher?.dispatch(name, {
4957
+ ...actionValues,
4958
+ method: name,
4959
+ });
4960
+ break;
4961
+ case 'fetchAttestation':
4962
+ provider.actionDispatcher?.dispatch(name, {
4963
+ ...actionValues,
4964
+ method: name,
4965
+ values: step,
4966
+ });
4967
+ break;
4968
+ }
4949
4969
  result.steps.push(step);
4950
4970
  }
4951
4971
  catch (error) {
@@ -5201,7 +5221,6 @@ base58StringSchema.refine((value) => value.length >= 86 && value.length <= 88, '
5201
5221
  z.object({
5202
5222
  prepare: z.function(),
5203
5223
  waitForTransaction: z.function(),
5204
- getChain: z.function(),
5205
5224
  getAddress: z.function(),
5206
5225
  });
5207
5226
 
@@ -5724,9 +5743,9 @@ class CCTPV2BridgingProvider extends BridgingProvider {
5724
5743
  *
5725
5744
  * @param params - The bridge parameters containing source, destination, amount, and optional config.
5726
5745
  * @returns A promise resolving to the bridge result, including transaction details, step states, and explorer URLs.
5727
- * @throws {ValidationError} If the parameters are invalid
5728
- * @throws {BridgeError} If the bridge operation fails
5729
- * @throws {UnsupportedRouteError} If the route is not supported
5746
+ * @throws {ValidationError} When the parameters are invalid.
5747
+ * @throws {BridgeError} When the bridge operation fails.
5748
+ * @throws {UnsupportedRouteError} When the route is not supported.
5730
5749
  *
5731
5750
  * @example
5732
5751
  * ```typescript
@@ -5788,9 +5807,14 @@ class CCTPV2BridgingProvider extends BridgingProvider {
5788
5807
  * chains, as well as any applicable protocol fees.
5789
5808
  *
5790
5809
  * @param params - The bridge parameters containing source, destination, amount, and optional config.
5791
- * @returns Promise resolving to detailed cost breakdown including gas estimates and protocol fees
5792
- * @throws {ValidationError} If the parameters are invalid
5793
- * @throws {UnsupportedRouteError} If the route is not supported
5810
+ * @returns Promise resolving to detailed cost breakdown including:
5811
+ * - `gasFees`: Array of gas estimates for each step (Approve, Burn, Mint)
5812
+ * - Gas amounts in native token smallest units (wei for ETH, lamports for SOL, etc.)
5813
+ * - `fees`: Array of protocol and kit fees
5814
+ * - Provider fees in USDC decimal units (e.g., "0.1" USDC)
5815
+ * - Kit fees in USDC decimal units if configured
5816
+ * @throws {ValidationError} When the parameters are invalid.
5817
+ * @throws {UnsupportedRouteError} When the route is not supported.
5794
5818
  *
5795
5819
  * @example
5796
5820
  * ```typescript
@@ -6057,6 +6081,7 @@ class CCTPV2BridgingProvider extends BridgingProvider {
6057
6081
  message: attestation.message,
6058
6082
  attestation: attestation.attestation,
6059
6083
  eventNonce: attestation.eventNonce,
6084
+ destinationAddress: destination.address,
6060
6085
  };
6061
6086
  // Single call with or without context
6062
6087
  if (resolvedContext) {
@@ -6170,28 +6195,29 @@ class CCTPV2BridgingProvider extends BridgingProvider {
6170
6195
  return false;
6171
6196
  }
6172
6197
  /**
6173
- * This method determines the appropriate maximum fee for a cross-chain bridge operation
6174
- * based on the configured bridge speed and chain requirements.
6198
+ * Determines the appropriate maximum fee for a cross-chain bridge operation.
6175
6199
  *
6176
6200
  * For FAST bridge operations, it calculates a dynamic fee based on the bridge amount
6177
6201
  * and fast bridge burn fee, or uses a provided maxFee if specified.
6178
6202
  *
6179
6203
  * For SLOW bridge operations, it returns 0 as there are no additional fees.
6180
6204
  *
6181
- * @param sourceChain - The source chain definition where the bridge originates
6182
- * @param destinationChain - The destination chain definition where tokens will be minted
6183
- * @param amount - The bridge amount in minor units (e.g., "1000000" for 1 USDC)
6184
- * @param config - Optional bridge configuration including speed and fee settings
6185
- * @returns The maximum fee to be used for the bridge operation
6205
+ * @param params - The bridge parameters object containing:
6206
+ * - `source`: The source wallet context with chain definition and adapter
6207
+ * - `destination`: The destination wallet context with chain definition and adapter
6208
+ * - `amount`: The bridge amount in minor units (e.g., "1000000" for 1 USDC)
6209
+ * - `config`: Optional bridge configuration including transferSpeed and maxFee settings
6210
+ * @returns The maximum fee to be used for the bridge operation in minor units
6186
6211
  *
6187
6212
  * @example
6188
6213
  * ```typescript
6189
- * const maxFee = await provider.getMaxFee(
6190
- * sourceChain,
6191
- * destinationChain,
6192
- * '1000000', // 1 USDC
6193
- * { transferSpeed: 'FAST' }
6194
- * )
6214
+ * const maxFee = await provider.getMaxFee({
6215
+ * source: { adapter: sourceAdapter, chain: Chains.Ethereum, address: '0x...' },
6216
+ * destination: { adapter: destAdapter, chain: Chains.Base, address: '0x...' },
6217
+ * amount: '1000000', // 1 USDC
6218
+ * token: 'USDC',
6219
+ * config: { transferSpeed: TransferSpeed.FAST }
6220
+ * })
6195
6221
  * console.log('Max fee:', maxFee)
6196
6222
  * ```
6197
6223
  */
@@ -6258,8 +6284,11 @@ class CCTPV2BridgingProvider extends BridgingProvider {
6258
6284
  // Get the min finality threshold based on the transfer speed
6259
6285
  const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
6260
6286
  // Calculate the max fee
6261
- const maxFee = await this.getMaxFee(params);
6262
- const mintRecipient = await getMintRecipientAccount(destination.chain.type, destination.address ?? (await destination.adapter.getAddress()), destination.chain.usdcAddress);
6287
+ const [maxFee, mintRecipient] = await Promise.all([
6288
+ this.getMaxFee(params),
6289
+ getMintRecipientAccount(destination.chain.type, destination.address ??
6290
+ (await destination.adapter.getAddress(destination.chain)), destination.chain.usdcAddress),
6291
+ ]);
6263
6292
  const actionParams = {
6264
6293
  fromChain: source.chain,
6265
6294
  toChain: destination.chain,
package/package.json CHANGED
@@ -1,18 +1,32 @@
1
1
  {
2
2
  "name": "@circle-fin/provider-cctp-v2",
3
- "version": "0.0.2-alpha.7",
3
+ "version": "1.0.0",
4
4
  "main": "./index.cjs.js",
5
5
  "module": "./index.mjs",
6
6
  "types": "./index.d.ts",
7
7
  "dependencies": {
8
- "@solana/web3.js": "^1.90.0",
9
- "@solana/spl-token": "0.4.13",
10
- "abitype": "1.0.8",
8
+ "@coral-xyz/anchor": "^0.31.1",
9
+ "bs58": "6.0.0",
10
+ "buffer": "^6.0.3",
11
+ "abitype": "^1.1.0",
12
+ "@solana/web3.js": "^1.98.4",
13
+ "@solana/spl-token": "0.4.14",
11
14
  "zod": "3.25.67",
12
15
  "@ethersproject/address": "^5.8.0",
13
16
  "@ethersproject/bytes": "^5.8.0",
14
- "@ethersproject/units": "^5.8.0",
15
- "bs58": "6.0.0"
17
+ "@ethersproject/units": "^5.8.0"
18
+ },
19
+ "peerDependencies": {
20
+ "@solana/spl-token": "^0.4.13",
21
+ "@solana/web3.js": "^1.98.2"
22
+ },
23
+ "peerDependenciesMeta": {
24
+ "@solana/spl-token": {
25
+ "optional": true
26
+ },
27
+ "@solana/web3.js": {
28
+ "optional": true
29
+ }
16
30
  },
17
31
  "exports": {
18
32
  "./package.json": "./package.json",