@circle-fin/app-kit 1.10.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/bridge.cjs +74 -22
- package/bridge.d.cts +12 -1
- package/bridge.d.mts +12 -1
- package/bridge.d.ts +12 -1
- package/bridge.mjs +74 -22
- package/chains.cjs +11 -0
- package/chains.mjs +11 -0
- package/context.cjs +11 -0
- package/context.d.cts +12 -1
- package/context.d.mts +12 -1
- package/context.d.ts +12 -1
- package/context.mjs +11 -0
- package/earn.cjs +701 -49
- package/earn.d.cts +12 -1
- package/earn.d.mts +12 -1
- package/earn.d.ts +12 -1
- package/earn.mjs +701 -49
- package/estimateBridge.cjs +74 -22
- package/estimateBridge.d.cts +12 -1
- package/estimateBridge.d.mts +12 -1
- package/estimateBridge.d.ts +12 -1
- package/estimateBridge.mjs +74 -22
- package/estimateSwap.cjs +259 -30
- package/estimateSwap.d.cts +12 -1
- package/estimateSwap.d.mts +12 -1
- package/estimateSwap.d.ts +12 -1
- package/estimateSwap.mjs +259 -30
- package/index.cjs +539 -81
- package/index.d.cts +101 -7
- package/index.d.mts +101 -7
- package/index.d.ts +101 -7
- package/index.mjs +539 -81
- package/package.json +7 -6
- package/swap.cjs +259 -30
- package/swap.d.cts +12 -1
- package/swap.d.mts +12 -1
- package/swap.d.ts +12 -1
- package/swap.mjs +259 -30
- package/unifiedBalance.cjs +96 -26
- package/unifiedBalance.d.cts +28 -5
- package/unifiedBalance.d.mts +28 -5
- package/unifiedBalance.d.ts +28 -5
- package/unifiedBalance.mjs +96 -26
package/estimateSwap.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 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 'pino';
|
|
21
32
|
import { hexlify, hexZeroPad } from '@ethersproject/bytes';
|
|
@@ -44,6 +55,51 @@ import { keccak256 } from '@ethersproject/keccak256';
|
|
|
44
55
|
* }
|
|
45
56
|
* ```
|
|
46
57
|
*/ const isNodeEnvironment = ()=>typeof process !== 'undefined' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
|
|
58
|
+
/**
|
|
59
|
+
* Check whether the current runtime exposes a browser DOM.
|
|
60
|
+
*
|
|
61
|
+
* @remarks
|
|
62
|
+
* This intentionally does not treat every non-Node runtime as a browser.
|
|
63
|
+
* Server-side edge runtimes such as Cloudflare Workers, Deno, and Supabase
|
|
64
|
+
* Edge Functions do not expose Node globals but can safely use server
|
|
65
|
+
* credentials. A Node.js runtime remains server-side even when a test or SSR
|
|
66
|
+
* environment provides a DOM shim.
|
|
67
|
+
*
|
|
68
|
+
* @returns `true` when running in a browser window, `false` otherwise.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { isBrowserEnvironment } from '@core/utils'
|
|
73
|
+
*
|
|
74
|
+
* if (isBrowserEnvironment()) {
|
|
75
|
+
* throw new Error('Server-only secrets must not be used in the browser')
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*/ const isBrowserEnvironment = ()=>{
|
|
79
|
+
const browserWindow = globalThis.window;
|
|
80
|
+
return !isNodeEnvironment() && browserWindow?.document !== undefined;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Return the SDK User-Agent request header only when running in Node.js.
|
|
84
|
+
*
|
|
85
|
+
* Browsers forbid manually setting `User-Agent`, and a custom fallback header
|
|
86
|
+
* can trigger CORS preflight. Non-Node server runtimes also omit this optional
|
|
87
|
+
* attribution header because they cannot set it reliably.
|
|
88
|
+
*
|
|
89
|
+
* @returns A User-Agent header in Node.js, or an empty object otherwise.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* import { getNodeUserAgentHeader } from '@core/utils'
|
|
94
|
+
*
|
|
95
|
+
* const headers = {
|
|
96
|
+
* 'Content-Type': 'application/json',
|
|
97
|
+
* ...getNodeUserAgentHeader(),
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/ const getNodeUserAgentHeader = ()=>isNodeEnvironment() ? {
|
|
101
|
+
'User-Agent': getUserAgent()
|
|
102
|
+
} : {};
|
|
47
103
|
/**
|
|
48
104
|
* Detect the runtime environment and return a shortened identifier.
|
|
49
105
|
*
|
|
@@ -8021,13 +8077,12 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8021
8077
|
headers: {
|
|
8022
8078
|
...DEFAULT_CONFIG$1.headers,
|
|
8023
8079
|
...config.headers ?? {},
|
|
8024
|
-
//
|
|
8025
|
-
//
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
}
|
|
8080
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
8081
|
+
// fallback header the SDK used instead trips CORS preflight against the
|
|
8082
|
+
// Circle APIs (it isn't in their `Access-Control-Allow-Headers`),
|
|
8083
|
+
// blocking the request. So send the SDK user agent only in Node;
|
|
8084
|
+
// browsers omit it entirely.
|
|
8085
|
+
...getNodeUserAgentHeader()
|
|
8031
8086
|
}
|
|
8032
8087
|
};
|
|
8033
8088
|
let lastError;
|
|
@@ -9528,6 +9583,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9528
9583
|
if (payload.tokenIn !== undefined) safe['tokenIn'] = payload.tokenIn;
|
|
9529
9584
|
if (payload.tokenOut !== undefined) safe['tokenOut'] = payload.tokenOut;
|
|
9530
9585
|
if (payload.txHash !== undefined) safe['txHash'] = payload.txHash;
|
|
9586
|
+
if (payload.correlationId !== undefined) safe['correlationId'] = payload.correlationId;
|
|
9531
9587
|
if (payload.errorDetails !== undefined) {
|
|
9532
9588
|
const errorDetails = {
|
|
9533
9589
|
...payload.errorDetails.errorCode !== undefined && {
|
|
@@ -9598,18 +9654,15 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9598
9654
|
timeoutHandle.unref();
|
|
9599
9655
|
}
|
|
9600
9656
|
try {
|
|
9601
|
-
const isNode = isNodeEnvironment();
|
|
9602
|
-
const userAgent = getUserAgent();
|
|
9603
9657
|
await fetch(getLogsUrl(), {
|
|
9604
9658
|
method: 'POST',
|
|
9605
9659
|
headers: {
|
|
9606
9660
|
'Content-Type': 'application/json',
|
|
9607
|
-
//
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
9612
|
-
}
|
|
9661
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
9662
|
+
// fallback header the SDK used instead trips CORS preflight (it isn't
|
|
9663
|
+
// in the telemetry endpoint's `Access-Control-Allow-Headers`), so send
|
|
9664
|
+
// it only in Node; browsers omit it entirely.
|
|
9665
|
+
...getNodeUserAgentHeader()
|
|
9613
9666
|
},
|
|
9614
9667
|
body: JSON.stringify(toSafePayload(payload)),
|
|
9615
9668
|
signal: controller.signal
|
|
@@ -9777,7 +9830,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9777
9830
|
// discards the stack trace, nested `cause`, and any custom Error
|
|
9778
9831
|
// properties — exactly the context an on-call needs when a
|
|
9779
9832
|
// resolver-closure regression triggers this path.
|
|
9780
|
-
console.warn(`[stablecoin-kits telemetry] dropped
|
|
9833
|
+
console.warn(`[stablecoin-kits telemetry] dropped event '${eventType}':`, cause);
|
|
9781
9834
|
} catch {
|
|
9782
9835
|
// console.warn itself throwing is the user's environment; nothing more we
|
|
9783
9836
|
// can do without risking the original operation error.
|
|
@@ -9793,7 +9846,9 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9793
9846
|
sdkVersion: config.sdkVersion,
|
|
9794
9847
|
eventType,
|
|
9795
9848
|
timestamp: new Date().toISOString(),
|
|
9796
|
-
errorDetails
|
|
9849
|
+
...errorDetails !== undefined && {
|
|
9850
|
+
errorDetails
|
|
9851
|
+
},
|
|
9797
9852
|
clientContext: buildClientContext(),
|
|
9798
9853
|
...context?.sourceChain != null && {
|
|
9799
9854
|
sourceChain: context.sourceChain
|
|
@@ -9809,9 +9864,45 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9809
9864
|
},
|
|
9810
9865
|
...context?.txHash != null && {
|
|
9811
9866
|
txHash: context.txHash
|
|
9867
|
+
},
|
|
9868
|
+
...context?.correlationId != null && {
|
|
9869
|
+
correlationId: context.correlationId
|
|
9812
9870
|
}
|
|
9813
9871
|
};
|
|
9814
9872
|
}
|
|
9873
|
+
/**
|
|
9874
|
+
* Emit telemetry for a completed operation without affecting its caller.
|
|
9875
|
+
*
|
|
9876
|
+
* No-ops when `config.disabled` is `true`. Like {@link withErrorTelemetry},
|
|
9877
|
+
* failures while constructing or submitting the telemetry payload are reported
|
|
9878
|
+
* as a soft warning and never change a completed operation's result.
|
|
9879
|
+
*
|
|
9880
|
+
* @param eventType - The telemetry event type for the completed operation.
|
|
9881
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
9882
|
+
* @param context - Optional chain, token, and transaction context.
|
|
9883
|
+
* @returns Nothing.
|
|
9884
|
+
* @throws Never — telemetry failures are reported as warnings.
|
|
9885
|
+
*
|
|
9886
|
+
* @example
|
|
9887
|
+
* ```typescript
|
|
9888
|
+
* import { emitSuccessTelemetry } from '@core/utils'
|
|
9889
|
+
*
|
|
9890
|
+
* emitSuccessTelemetry(
|
|
9891
|
+
* 'bridge_bridge',
|
|
9892
|
+
* { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
|
|
9893
|
+
* { sourceChain: 'Ethereum', destinationChain: 'Base', tokenIn: 'USDC' },
|
|
9894
|
+
* )
|
|
9895
|
+
* ```
|
|
9896
|
+
*/ function emitSuccessTelemetry(eventType, config, context) {
|
|
9897
|
+
if (config.disabled) {
|
|
9898
|
+
return;
|
|
9899
|
+
}
|
|
9900
|
+
try {
|
|
9901
|
+
void emitAnalyticsLog(buildPayload(config, eventType, undefined, context));
|
|
9902
|
+
} catch (telemetryError) {
|
|
9903
|
+
warnTelemetryDrop(eventType, telemetryError);
|
|
9904
|
+
}
|
|
9905
|
+
}
|
|
9815
9906
|
/**
|
|
9816
9907
|
* Wrap an async operation with error telemetry.
|
|
9817
9908
|
*
|
|
@@ -9870,7 +9961,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9870
9961
|
}
|
|
9871
9962
|
|
|
9872
9963
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9873
|
-
var version$2 = "1.12.
|
|
9964
|
+
var version$2 = "1.12.2";
|
|
9874
9965
|
var pkg$2 = {
|
|
9875
9966
|
name: name$2,
|
|
9876
9967
|
version: version$2};
|
|
@@ -10731,7 +10822,13 @@ var TransferSpeed;
|
|
|
10731
10822
|
/**
|
|
10732
10823
|
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
10733
10824
|
* hookData must start with.
|
|
10734
|
-
|
|
10825
|
+
*
|
|
10826
|
+
* Encoded with `TextEncoder` (a browser-safe Web API) rather than `Buffer.from`
|
|
10827
|
+
* so this module-level constant does not reference the Node `Buffer` global at
|
|
10828
|
+
* import time. App Kit inlines this provider into its bundle without a Buffer polyfill, and a
|
|
10829
|
+
* bare `Buffer` here crashes browser bundles (e.g. Vite) on load — even for apps
|
|
10830
|
+
* that never touch the prepaid FORWARD path. Mirrors `buildForwardingHookData`.
|
|
10831
|
+
*/ Array.from(new TextEncoder().encode(CCTP_FORWARD_MAGIC_PREFIX)).map((byte)=>byte.toString(16).padStart(2, '0')).join('');
|
|
10735
10832
|
|
|
10736
10833
|
/**
|
|
10737
10834
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
@@ -10765,7 +10862,7 @@ var TransferSpeed;
|
|
|
10765
10862
|
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
10766
10863
|
|
|
10767
10864
|
var name$1 = "@circle-fin/swap-kit";
|
|
10768
|
-
var version$1 = "1.
|
|
10865
|
+
var version$1 = "1.5.0";
|
|
10769
10866
|
var pkg$1 = {
|
|
10770
10867
|
name: name$1,
|
|
10771
10868
|
version: version$1};
|
|
@@ -11598,6 +11695,16 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11598
11695
|
required_error: 'estimatedAmount is required',
|
|
11599
11696
|
invalid_type_error: 'estimatedAmount must be a string'
|
|
11600
11697
|
}).min(1, 'estimatedAmount must be a non-empty string'),
|
|
11698
|
+
// Per-swap join key echoed back verbatim on success telemetry. Optional so a
|
|
11699
|
+
// not-yet-upgraded service (no field) still validates during rollout. A
|
|
11700
|
+
// malformed/non-UUID value is coerced to `undefined` (no telemetry id) rather
|
|
11701
|
+
// than throwing: this is a telemetry-only field (stripped from the developer
|
|
11702
|
+
// result, never used for control flow), so it must not be able to abort the
|
|
11703
|
+
// swap via `parseCreateSwapResponse().parse()`. Mirrors the best-effort,
|
|
11704
|
+
// never-throw contract of the rest of the telemetry stack. Implemented with
|
|
11705
|
+
// `preprocess` rather than Zod's `.catch()` because static analysis misreads
|
|
11706
|
+
// `.catch` on the schema chain as an unhandled Promise (S7785).
|
|
11707
|
+
correlationId: z.preprocess((value)=>z.string().uuid().safeParse(value).success ? value : undefined, z.string().optional()),
|
|
11601
11708
|
config: createSwapRequestBaseSchema.shape.config.optional(),
|
|
11602
11709
|
fees: createSwapFeesSchema.optional(),
|
|
11603
11710
|
transaction: createSwapTransactionSchema
|
|
@@ -11684,6 +11791,45 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11684
11791
|
* }
|
|
11685
11792
|
* ```
|
|
11686
11793
|
*/ const isGetTokenRatesResponse = (obj)=>getTokenRatesResponseSchema.safeParse(obj).success;
|
|
11794
|
+
/**
|
|
11795
|
+
* Assert that a Stablecoin Service kit key is not being supplied from a browser.
|
|
11796
|
+
*
|
|
11797
|
+
* The kit key (`KIT_KEY:<id>:<secret>`) is a server-only secret. Every
|
|
11798
|
+
* Stablecoin Service request that attaches an `Authorization: Bearer` header
|
|
11799
|
+
* funnels through this package, so calling this guard before that header is
|
|
11800
|
+
* built prevents the secret from being sent from — and thus bundled into — a
|
|
11801
|
+
* client application. In Node.js the check is a no-op, preserving the
|
|
11802
|
+
* legitimate "hold the kit key on the server, forward the prepared transaction
|
|
11803
|
+
* to the client" flow. When no kit key is supplied the permissionless (keyless)
|
|
11804
|
+
* client path remains fully allowed.
|
|
11805
|
+
*
|
|
11806
|
+
* @param apiKey - The inline kit key for the request, or `undefined` when none
|
|
11807
|
+
* was supplied (permissionless mode).
|
|
11808
|
+
* @returns Nothing.
|
|
11809
|
+
* @throws KitError with VALIDATION_FAILED when a kit key is supplied while
|
|
11810
|
+
* running in a browser environment. The secret value is never echoed.
|
|
11811
|
+
*
|
|
11812
|
+
* @example
|
|
11813
|
+
* ```typescript
|
|
11814
|
+
* import { assertBrowserSafeApiKey } from '@core/service-client'
|
|
11815
|
+
*
|
|
11816
|
+
* // Server (Node.js): no-op, request proceeds with the Authorization header.
|
|
11817
|
+
* assertBrowserSafeApiKey('KIT_KEY:my-id:my-secret')
|
|
11818
|
+
*
|
|
11819
|
+
* // Browser: throws to stop the secret from leaking into the client bundle.
|
|
11820
|
+
* assertBrowserSafeApiKey('KIT_KEY:my-id:my-secret')
|
|
11821
|
+
*
|
|
11822
|
+
* // Browser, permissionless: allowed.
|
|
11823
|
+
* assertBrowserSafeApiKey(undefined)
|
|
11824
|
+
* ```
|
|
11825
|
+
*/ const assertBrowserSafeApiKey = (apiKey)=>{
|
|
11826
|
+
if (apiKey === undefined) {
|
|
11827
|
+
return;
|
|
11828
|
+
}
|
|
11829
|
+
if (isBrowserEnvironment()) {
|
|
11830
|
+
throw createValidationFailedError$1('kitKey', '[redacted]', 'kitKey must not be provided in a browser environment — it is a server-only secret. Run kit operations that use a kit key on your server, or omit kitKey to use the permissionless (keyless) client path');
|
|
11831
|
+
}
|
|
11832
|
+
};
|
|
11687
11833
|
|
|
11688
11834
|
/**
|
|
11689
11835
|
* Create a cross-chain bridge and swap transaction through the Stablecoin Service.
|
|
@@ -11741,6 +11887,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11741
11887
|
const url = new URL('/v1/stablecoinKits/swap', STABLECOIN_SERVICE_BASE_URL).toString();
|
|
11742
11888
|
// Remove the API key from the request body
|
|
11743
11889
|
const { apiKey, ...requestBody } = validatedParams;
|
|
11890
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
11891
|
+
assertBrowserSafeApiKey(apiKey);
|
|
11744
11892
|
const effectiveConfig = {
|
|
11745
11893
|
...DEFAULT_CONFIG,
|
|
11746
11894
|
headers: {
|
|
@@ -11895,6 +12043,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11895
12043
|
}
|
|
11896
12044
|
// Use validated data
|
|
11897
12045
|
const validatedParams = result.data;
|
|
12046
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
12047
|
+
assertBrowserSafeApiKey(validatedParams.apiKey);
|
|
11898
12048
|
// Build the API URL
|
|
11899
12049
|
const url = buildQuoteUrl(validatedParams);
|
|
11900
12050
|
// Merge default config with Authorization header
|
|
@@ -11967,6 +12117,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11967
12117
|
toChain: result.data.toChain
|
|
11968
12118
|
}
|
|
11969
12119
|
};
|
|
12120
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
12121
|
+
assertBrowserSafeApiKey(validatedParams.apiKey);
|
|
11970
12122
|
const url = buildSwapStatusUrl(validatedParams);
|
|
11971
12123
|
const effectiveConfig = {
|
|
11972
12124
|
...DEFAULT_CONFIG,
|
|
@@ -12071,6 +12223,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
12071
12223
|
addresses: result.data.addresses
|
|
12072
12224
|
}
|
|
12073
12225
|
};
|
|
12226
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
12227
|
+
assertBrowserSafeApiKey(validatedParams.apiKey);
|
|
12074
12228
|
const url = buildTokenRatesUrl(validatedParams);
|
|
12075
12229
|
const effectiveConfig = {
|
|
12076
12230
|
...DEFAULT_CONFIG,
|
|
@@ -16497,6 +16651,11 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16497
16651
|
apiKey: serviceParams.apiKey
|
|
16498
16652
|
}
|
|
16499
16653
|
});
|
|
16654
|
+
// Per-swap correlation id returned by the service as a top-level response
|
|
16655
|
+
// field for every chain (EVM + Solana). Attached to success telemetry so a
|
|
16656
|
+
// swap can be correlated across records; never used for control flow.
|
|
16657
|
+
// Undefined only against a not-yet-upgraded service that omits it.
|
|
16658
|
+
const correlationId = serviceResponse.correlationId;
|
|
16500
16659
|
// Build and return SwapResult
|
|
16501
16660
|
return {
|
|
16502
16661
|
tokenIn,
|
|
@@ -16506,6 +16665,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16506
16665
|
fromAddress: serviceParams.fromAddress,
|
|
16507
16666
|
toAddress: serviceParams.toAddress,
|
|
16508
16667
|
txHash,
|
|
16668
|
+
...correlationId !== undefined && {
|
|
16669
|
+
correlationId
|
|
16670
|
+
},
|
|
16509
16671
|
executedTransactions,
|
|
16510
16672
|
...config !== undefined && {
|
|
16511
16673
|
config
|
|
@@ -19405,7 +19567,13 @@ async function resolveTokenDecimals(context, resolvedParams) {
|
|
|
19405
19567
|
* amountIn: '50.00'
|
|
19406
19568
|
* })
|
|
19407
19569
|
* ```
|
|
19408
|
-
*/ async function swap(context, params, /**
|
|
19570
|
+
*/ async function swap(context, params, /**
|
|
19571
|
+
* @internal
|
|
19572
|
+
* Invoked after a successful broadcast with the on-chain `txHash` and the
|
|
19573
|
+
* service-issued `correlationId` (join key for success telemetry). The
|
|
19574
|
+
* service returns `correlationId` for every chain (EVM + Solana); it is
|
|
19575
|
+
* undefined only against a not-yet-upgraded service that omits the field.
|
|
19576
|
+
*/ onBroadcast) {
|
|
19409
19577
|
// Step 1: Validate parameters using schema
|
|
19410
19578
|
assertSwapParams(params, swapParamsSchema);
|
|
19411
19579
|
// Step 2: Resolve parameters (chain definitions, wallet addresses, token aliases preserved)
|
|
@@ -19425,13 +19593,16 @@ async function resolveTokenDecimals(context, resolvedParams) {
|
|
|
19425
19593
|
// Step 5: Execute swap via provider
|
|
19426
19594
|
const swapParams = buildServiceSwapParams(resolvedParams, paramsWithFees);
|
|
19427
19595
|
const providerResult = await provider.swap(swapParams);
|
|
19596
|
+
// `correlationId` is an internal telemetry join key, not part of the public
|
|
19597
|
+
// SwapResult — strip it here so it never leaks into the formatted result.
|
|
19598
|
+
const { correlationId, ...providerResultPublic } = providerResult;
|
|
19428
19599
|
// A throwing `onBroadcast` must never strand the caller after a
|
|
19429
19600
|
// successful swap broadcast — the chain has moved. `safeInvokeCallback`
|
|
19430
19601
|
// swallows the error and surfaces a `console.warn` prefixed with
|
|
19431
19602
|
// `[stablecoin-kits swap-kit] callback threw and was swallowed:` so a
|
|
19432
19603
|
// kit-side closure bug stays debuggable rather than vanishing.
|
|
19433
19604
|
safeInvokeCallback('swap-kit', ()=>{
|
|
19434
|
-
onBroadcast?.(
|
|
19605
|
+
onBroadcast?.(providerResultPublic.txHash, correlationId);
|
|
19435
19606
|
});
|
|
19436
19607
|
const { tokenInDecimals, tokenOutDecimals } = await resolveTokenDecimals(context, resolvedParams);
|
|
19437
19608
|
// Step 6: Compose chain identity (owned by the kit, derived from the
|
|
@@ -19440,10 +19611,10 @@ async function resolveTokenDecimals(context, resolvedParams) {
|
|
|
19440
19611
|
// resolves `progress` — the provider's snapshot, or a terminal `'DONE'` for
|
|
19441
19612
|
// a provider that omits it (a synchronous same-chain completion).
|
|
19442
19613
|
const composedResult = {
|
|
19443
|
-
...
|
|
19614
|
+
...providerResultPublic,
|
|
19444
19615
|
chainIn: resolvedParams.from.chain,
|
|
19445
19616
|
chainOut: resolvedParams.toChain ?? resolvedParams.from.chain,
|
|
19446
|
-
progress:
|
|
19617
|
+
progress: providerResultPublic.progress ?? {
|
|
19447
19618
|
status: 'DONE'
|
|
19448
19619
|
}
|
|
19449
19620
|
};
|
|
@@ -20296,7 +20467,13 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20296
20467
|
*/ class SwapKit {
|
|
20297
20468
|
context;
|
|
20298
20469
|
/** Whether error telemetry is disabled. */ disableErrorReporting;
|
|
20299
|
-
/** Per-kit telemetry identity for
|
|
20470
|
+
/** Per-kit telemetry identity for error reporting. */ telemetryConfig;
|
|
20471
|
+
/**
|
|
20472
|
+
* Per-kit telemetry identity for success/analytics events. Gated by
|
|
20473
|
+
* `disableAnalytics` (independent of `disableErrorReporting`) so a developer
|
|
20474
|
+
* can opt out of volume analytics without also silencing error reports —
|
|
20475
|
+
* mirrors EarnKit.
|
|
20476
|
+
*/ analyticsTelemetryConfig;
|
|
20300
20477
|
/**
|
|
20301
20478
|
* Create a new SwapKit instance.
|
|
20302
20479
|
*
|
|
@@ -20350,6 +20527,11 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20350
20527
|
sdkVersion: pkg$1.version,
|
|
20351
20528
|
disabled: this.disableErrorReporting
|
|
20352
20529
|
};
|
|
20530
|
+
this.analyticsTelemetryConfig = {
|
|
20531
|
+
sdkName: SDK_NAME,
|
|
20532
|
+
sdkVersion: pkg$1.version,
|
|
20533
|
+
disabled: config.disableAnalytics === true
|
|
20534
|
+
};
|
|
20353
20535
|
}
|
|
20354
20536
|
/**
|
|
20355
20537
|
* Estimate the output amount and fees for a swap operation.
|
|
@@ -20390,8 +20572,12 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20390
20572
|
* console.log(`Fees:`, quote.fees)
|
|
20391
20573
|
* ```
|
|
20392
20574
|
*/ async estimate(params) {
|
|
20575
|
+
const destinationChain = params.to?.chain ? resolveChainName(params.to.chain) : undefined;
|
|
20393
20576
|
return withErrorTelemetry(async ()=>estimate(this.context, params), SWAP_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
|
|
20394
20577
|
sourceChain: resolveChainName(params.from.chain),
|
|
20578
|
+
...destinationChain != null && {
|
|
20579
|
+
destinationChain
|
|
20580
|
+
},
|
|
20395
20581
|
tokenIn: params.tokenIn,
|
|
20396
20582
|
tokenOut: params.tokenOut
|
|
20397
20583
|
});
|
|
@@ -20450,16 +20636,54 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20450
20636
|
* ```
|
|
20451
20637
|
*/ async swap(params) {
|
|
20452
20638
|
let txHash;
|
|
20453
|
-
|
|
20454
|
-
|
|
20455
|
-
|
|
20639
|
+
let correlationId;
|
|
20640
|
+
// Shared context builder so the error resolver and the success emit stay in
|
|
20641
|
+
// lockstep — a field added here reaches both call sites. Reads the per-call
|
|
20642
|
+
// locals lazily, so txHash/correlationId (set during the swap) are captured
|
|
20643
|
+
// whenever it is invoked.
|
|
20644
|
+
// Destination chain is the primary attribution dimension for cross-chain
|
|
20645
|
+
// swaps; resolved once from the (static) params. Omitted for same-chain
|
|
20646
|
+
// swaps that leave `to.chain` unset (destination == source).
|
|
20647
|
+
const destinationChain = params.to?.chain ? resolveChainName(params.to.chain) : undefined;
|
|
20648
|
+
const buildTelemetryContext = ()=>({
|
|
20456
20649
|
sourceChain: resolveChainName(params.from.chain),
|
|
20650
|
+
...destinationChain != null && {
|
|
20651
|
+
destinationChain
|
|
20652
|
+
},
|
|
20457
20653
|
tokenIn: params.tokenIn,
|
|
20458
20654
|
tokenOut: params.tokenOut,
|
|
20459
20655
|
...txHash != null && {
|
|
20460
20656
|
txHash
|
|
20657
|
+
},
|
|
20658
|
+
...correlationId != null && {
|
|
20659
|
+
correlationId
|
|
20461
20660
|
}
|
|
20462
|
-
})
|
|
20661
|
+
});
|
|
20662
|
+
const result = await withErrorTelemetry(async ()=>swap(this.context, params, (h, cId)=>{
|
|
20663
|
+
txHash = h;
|
|
20664
|
+
correlationId = cId;
|
|
20665
|
+
}), SWAP_EVENT_TYPES.SWAP, this.telemetryConfig, buildTelemetryContext);
|
|
20666
|
+
// withErrorTelemetry only emits on failure. Record the successful swap here
|
|
20667
|
+
// so the backend can attribute swap volume to a developer: the client event
|
|
20668
|
+
// carries the (burn) txHash + correlationId, which joins to the
|
|
20669
|
+
// server-emitted event carrying entity_id. Best-effort; never throws.
|
|
20670
|
+
//
|
|
20671
|
+
// Emit whenever a broadcast happened, i.e. we have the source/burn txHash.
|
|
20672
|
+
// For a cross-chain swap that is the source-chain burn (progress is still
|
|
20673
|
+
// PENDING while the destination mint settles) — we intentionally attribute
|
|
20674
|
+
// at broadcast using the burn txHash rather than tracking the destination
|
|
20675
|
+
// leg, which keeps the capture simple and self-contained in swap().
|
|
20676
|
+
//
|
|
20677
|
+
// Guard against a terminal-failure result: the EVM provider throws on
|
|
20678
|
+
// revert today, but the kit is provider-agnostic, so a provider that
|
|
20679
|
+
// returns a FAILED/NOT_FOUND result without throwing must not be recorded
|
|
20680
|
+
// as a successful swap. Routed through analyticsTelemetryConfig so it is
|
|
20681
|
+
// gated by disableAnalytics, independent of error reporting.
|
|
20682
|
+
const status = result.progress?.status;
|
|
20683
|
+
if (txHash != null && status !== 'FAILED' && status !== 'NOT_FOUND') {
|
|
20684
|
+
emitSuccessTelemetry(SWAP_EVENT_TYPES.SWAP, this.analyticsTelemetryConfig, buildTelemetryContext());
|
|
20685
|
+
}
|
|
20686
|
+
return result;
|
|
20463
20687
|
}
|
|
20464
20688
|
/**
|
|
20465
20689
|
* Fetch the current status of a swap from the Stablecoin Service.
|
|
@@ -20838,6 +21062,9 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
20838
21062
|
const kit = new SwapKit({
|
|
20839
21063
|
...context.disableErrorReporting != null && {
|
|
20840
21064
|
disableErrorReporting: context.disableErrorReporting
|
|
21065
|
+
},
|
|
21066
|
+
...context.disableAnalytics != null && {
|
|
21067
|
+
disableAnalytics: context.disableAnalytics
|
|
20841
21068
|
}
|
|
20842
21069
|
});
|
|
20843
21070
|
if (hasBoth) {
|
|
@@ -20899,7 +21126,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
20899
21126
|
};
|
|
20900
21127
|
|
|
20901
21128
|
var name = "@circle-fin/earn-kit";
|
|
20902
|
-
var version = "1.
|
|
21129
|
+
var version = "1.4.0";
|
|
20903
21130
|
var pkg = {
|
|
20904
21131
|
name: name,
|
|
20905
21132
|
version: version};
|
|
@@ -22363,6 +22590,8 @@ function hasCrossChainDepositQuoteShape(params) {
|
|
|
22363
22590
|
config: earnConfigSchema.optional()
|
|
22364
22591
|
});
|
|
22365
22592
|
|
|
22593
|
+
/** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg.name);
|
|
22594
|
+
|
|
22366
22595
|
// Auto-register this kit for user agent tracking
|
|
22367
22596
|
registerKit(`${pkg.name}/${pkg.version}`);
|
|
22368
22597
|
|