@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.cjs
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 libraries
|
|
23
|
+
const { Buffer } = require('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
|
require('pino');
|
|
23
34
|
var bytes = require('@ethersproject/bytes');
|
|
@@ -50,6 +61,51 @@ var bs58__default = /*#__PURE__*/_interopDefault(bs58);
|
|
|
50
61
|
* }
|
|
51
62
|
* ```
|
|
52
63
|
*/ const isNodeEnvironment = ()=>typeof process !== 'undefined' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
|
|
64
|
+
/**
|
|
65
|
+
* Check whether the current runtime exposes a browser DOM.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* This intentionally does not treat every non-Node runtime as a browser.
|
|
69
|
+
* Server-side edge runtimes such as Cloudflare Workers, Deno, and Supabase
|
|
70
|
+
* Edge Functions do not expose Node globals but can safely use server
|
|
71
|
+
* credentials. A Node.js runtime remains server-side even when a test or SSR
|
|
72
|
+
* environment provides a DOM shim.
|
|
73
|
+
*
|
|
74
|
+
* @returns `true` when running in a browser window, `false` otherwise.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* import { isBrowserEnvironment } from '@core/utils'
|
|
79
|
+
*
|
|
80
|
+
* if (isBrowserEnvironment()) {
|
|
81
|
+
* throw new Error('Server-only secrets must not be used in the browser')
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/ const isBrowserEnvironment = ()=>{
|
|
85
|
+
const browserWindow = globalThis.window;
|
|
86
|
+
return !isNodeEnvironment() && browserWindow?.document !== undefined;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Return the SDK User-Agent request header only when running in Node.js.
|
|
90
|
+
*
|
|
91
|
+
* Browsers forbid manually setting `User-Agent`, and a custom fallback header
|
|
92
|
+
* can trigger CORS preflight. Non-Node server runtimes also omit this optional
|
|
93
|
+
* attribution header because they cannot set it reliably.
|
|
94
|
+
*
|
|
95
|
+
* @returns A User-Agent header in Node.js, or an empty object otherwise.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* import { getNodeUserAgentHeader } from '@core/utils'
|
|
100
|
+
*
|
|
101
|
+
* const headers = {
|
|
102
|
+
* 'Content-Type': 'application/json',
|
|
103
|
+
* ...getNodeUserAgentHeader(),
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/ const getNodeUserAgentHeader = ()=>isNodeEnvironment() ? {
|
|
107
|
+
'User-Agent': getUserAgent()
|
|
108
|
+
} : {};
|
|
53
109
|
/**
|
|
54
110
|
* Detect the runtime environment and return a shortened identifier.
|
|
55
111
|
*
|
|
@@ -8027,13 +8083,12 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8027
8083
|
headers: {
|
|
8028
8084
|
...DEFAULT_CONFIG$1.headers,
|
|
8029
8085
|
...config.headers ?? {},
|
|
8030
|
-
//
|
|
8031
|
-
//
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
}
|
|
8086
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
8087
|
+
// fallback header the SDK used instead trips CORS preflight against the
|
|
8088
|
+
// Circle APIs (it isn't in their `Access-Control-Allow-Headers`),
|
|
8089
|
+
// blocking the request. So send the SDK user agent only in Node;
|
|
8090
|
+
// browsers omit it entirely.
|
|
8091
|
+
...getNodeUserAgentHeader()
|
|
8037
8092
|
}
|
|
8038
8093
|
};
|
|
8039
8094
|
let lastError;
|
|
@@ -9534,6 +9589,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9534
9589
|
if (payload.tokenIn !== undefined) safe['tokenIn'] = payload.tokenIn;
|
|
9535
9590
|
if (payload.tokenOut !== undefined) safe['tokenOut'] = payload.tokenOut;
|
|
9536
9591
|
if (payload.txHash !== undefined) safe['txHash'] = payload.txHash;
|
|
9592
|
+
if (payload.correlationId !== undefined) safe['correlationId'] = payload.correlationId;
|
|
9537
9593
|
if (payload.errorDetails !== undefined) {
|
|
9538
9594
|
const errorDetails = {
|
|
9539
9595
|
...payload.errorDetails.errorCode !== undefined && {
|
|
@@ -9604,18 +9660,15 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9604
9660
|
timeoutHandle.unref();
|
|
9605
9661
|
}
|
|
9606
9662
|
try {
|
|
9607
|
-
const isNode = isNodeEnvironment();
|
|
9608
|
-
const userAgent = getUserAgent();
|
|
9609
9663
|
await fetch(getLogsUrl(), {
|
|
9610
9664
|
method: 'POST',
|
|
9611
9665
|
headers: {
|
|
9612
9666
|
'Content-Type': 'application/json',
|
|
9613
|
-
//
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
}
|
|
9667
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
9668
|
+
// fallback header the SDK used instead trips CORS preflight (it isn't
|
|
9669
|
+
// in the telemetry endpoint's `Access-Control-Allow-Headers`), so send
|
|
9670
|
+
// it only in Node; browsers omit it entirely.
|
|
9671
|
+
...getNodeUserAgentHeader()
|
|
9619
9672
|
},
|
|
9620
9673
|
body: JSON.stringify(toSafePayload(payload)),
|
|
9621
9674
|
signal: controller.signal
|
|
@@ -9783,7 +9836,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9783
9836
|
// discards the stack trace, nested `cause`, and any custom Error
|
|
9784
9837
|
// properties — exactly the context an on-call needs when a
|
|
9785
9838
|
// resolver-closure regression triggers this path.
|
|
9786
|
-
console.warn(`[stablecoin-kits telemetry] dropped
|
|
9839
|
+
console.warn(`[stablecoin-kits telemetry] dropped event '${eventType}':`, cause);
|
|
9787
9840
|
} catch {
|
|
9788
9841
|
// console.warn itself throwing is the user's environment; nothing more we
|
|
9789
9842
|
// can do without risking the original operation error.
|
|
@@ -9799,7 +9852,9 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9799
9852
|
sdkVersion: config.sdkVersion,
|
|
9800
9853
|
eventType,
|
|
9801
9854
|
timestamp: new Date().toISOString(),
|
|
9802
|
-
errorDetails
|
|
9855
|
+
...errorDetails !== undefined && {
|
|
9856
|
+
errorDetails
|
|
9857
|
+
},
|
|
9803
9858
|
clientContext: buildClientContext(),
|
|
9804
9859
|
...context?.sourceChain != null && {
|
|
9805
9860
|
sourceChain: context.sourceChain
|
|
@@ -9815,9 +9870,45 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9815
9870
|
},
|
|
9816
9871
|
...context?.txHash != null && {
|
|
9817
9872
|
txHash: context.txHash
|
|
9873
|
+
},
|
|
9874
|
+
...context?.correlationId != null && {
|
|
9875
|
+
correlationId: context.correlationId
|
|
9818
9876
|
}
|
|
9819
9877
|
};
|
|
9820
9878
|
}
|
|
9879
|
+
/**
|
|
9880
|
+
* Emit telemetry for a completed operation without affecting its caller.
|
|
9881
|
+
*
|
|
9882
|
+
* No-ops when `config.disabled` is `true`. Like {@link withErrorTelemetry},
|
|
9883
|
+
* failures while constructing or submitting the telemetry payload are reported
|
|
9884
|
+
* as a soft warning and never change a completed operation's result.
|
|
9885
|
+
*
|
|
9886
|
+
* @param eventType - The telemetry event type for the completed operation.
|
|
9887
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
9888
|
+
* @param context - Optional chain, token, and transaction context.
|
|
9889
|
+
* @returns Nothing.
|
|
9890
|
+
* @throws Never — telemetry failures are reported as warnings.
|
|
9891
|
+
*
|
|
9892
|
+
* @example
|
|
9893
|
+
* ```typescript
|
|
9894
|
+
* import { emitSuccessTelemetry } from '@core/utils'
|
|
9895
|
+
*
|
|
9896
|
+
* emitSuccessTelemetry(
|
|
9897
|
+
* 'bridge_bridge',
|
|
9898
|
+
* { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
|
|
9899
|
+
* { sourceChain: 'Ethereum', destinationChain: 'Base', tokenIn: 'USDC' },
|
|
9900
|
+
* )
|
|
9901
|
+
* ```
|
|
9902
|
+
*/ function emitSuccessTelemetry(eventType, config, context) {
|
|
9903
|
+
if (config.disabled) {
|
|
9904
|
+
return;
|
|
9905
|
+
}
|
|
9906
|
+
try {
|
|
9907
|
+
void emitAnalyticsLog(buildPayload(config, eventType, undefined, context));
|
|
9908
|
+
} catch (telemetryError) {
|
|
9909
|
+
warnTelemetryDrop(eventType, telemetryError);
|
|
9910
|
+
}
|
|
9911
|
+
}
|
|
9821
9912
|
/**
|
|
9822
9913
|
* Wrap an async operation with error telemetry.
|
|
9823
9914
|
*
|
|
@@ -9876,7 +9967,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9876
9967
|
}
|
|
9877
9968
|
|
|
9878
9969
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9879
|
-
var version$2 = "1.12.
|
|
9970
|
+
var version$2 = "1.12.2";
|
|
9880
9971
|
var pkg$2 = {
|
|
9881
9972
|
name: name$2,
|
|
9882
9973
|
version: version$2};
|
|
@@ -10737,7 +10828,13 @@ var TransferSpeed;
|
|
|
10737
10828
|
/**
|
|
10738
10829
|
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
10739
10830
|
* hookData must start with.
|
|
10740
|
-
|
|
10831
|
+
*
|
|
10832
|
+
* Encoded with `TextEncoder` (a browser-safe Web API) rather than `Buffer.from`
|
|
10833
|
+
* so this module-level constant does not reference the Node `Buffer` global at
|
|
10834
|
+
* import time. App Kit inlines this provider into its bundle without a Buffer polyfill, and a
|
|
10835
|
+
* bare `Buffer` here crashes browser bundles (e.g. Vite) on load — even for apps
|
|
10836
|
+
* that never touch the prepaid FORWARD path. Mirrors `buildForwardingHookData`.
|
|
10837
|
+
*/ Array.from(new TextEncoder().encode(CCTP_FORWARD_MAGIC_PREFIX)).map((byte)=>byte.toString(16).padStart(2, '0')).join('');
|
|
10741
10838
|
|
|
10742
10839
|
/**
|
|
10743
10840
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
@@ -10771,7 +10868,7 @@ var TransferSpeed;
|
|
|
10771
10868
|
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
10772
10869
|
|
|
10773
10870
|
var name$1 = "@circle-fin/swap-kit";
|
|
10774
|
-
var version$1 = "1.
|
|
10871
|
+
var version$1 = "1.5.0";
|
|
10775
10872
|
var pkg$1 = {
|
|
10776
10873
|
name: name$1,
|
|
10777
10874
|
version: version$1};
|
|
@@ -11604,6 +11701,16 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11604
11701
|
required_error: 'estimatedAmount is required',
|
|
11605
11702
|
invalid_type_error: 'estimatedAmount must be a string'
|
|
11606
11703
|
}).min(1, 'estimatedAmount must be a non-empty string'),
|
|
11704
|
+
// Per-swap join key echoed back verbatim on success telemetry. Optional so a
|
|
11705
|
+
// not-yet-upgraded service (no field) still validates during rollout. A
|
|
11706
|
+
// malformed/non-UUID value is coerced to `undefined` (no telemetry id) rather
|
|
11707
|
+
// than throwing: this is a telemetry-only field (stripped from the developer
|
|
11708
|
+
// result, never used for control flow), so it must not be able to abort the
|
|
11709
|
+
// swap via `parseCreateSwapResponse().parse()`. Mirrors the best-effort,
|
|
11710
|
+
// never-throw contract of the rest of the telemetry stack. Implemented with
|
|
11711
|
+
// `preprocess` rather than Zod's `.catch()` because static analysis misreads
|
|
11712
|
+
// `.catch` on the schema chain as an unhandled Promise (S7785).
|
|
11713
|
+
correlationId: zod.z.preprocess((value)=>zod.z.string().uuid().safeParse(value).success ? value : undefined, zod.z.string().optional()),
|
|
11607
11714
|
config: createSwapRequestBaseSchema.shape.config.optional(),
|
|
11608
11715
|
fees: createSwapFeesSchema.optional(),
|
|
11609
11716
|
transaction: createSwapTransactionSchema
|
|
@@ -11690,6 +11797,45 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11690
11797
|
* }
|
|
11691
11798
|
* ```
|
|
11692
11799
|
*/ const isGetTokenRatesResponse = (obj)=>getTokenRatesResponseSchema.safeParse(obj).success;
|
|
11800
|
+
/**
|
|
11801
|
+
* Assert that a Stablecoin Service kit key is not being supplied from a browser.
|
|
11802
|
+
*
|
|
11803
|
+
* The kit key (`KIT_KEY:<id>:<secret>`) is a server-only secret. Every
|
|
11804
|
+
* Stablecoin Service request that attaches an `Authorization: Bearer` header
|
|
11805
|
+
* funnels through this package, so calling this guard before that header is
|
|
11806
|
+
* built prevents the secret from being sent from — and thus bundled into — a
|
|
11807
|
+
* client application. In Node.js the check is a no-op, preserving the
|
|
11808
|
+
* legitimate "hold the kit key on the server, forward the prepared transaction
|
|
11809
|
+
* to the client" flow. When no kit key is supplied the permissionless (keyless)
|
|
11810
|
+
* client path remains fully allowed.
|
|
11811
|
+
*
|
|
11812
|
+
* @param apiKey - The inline kit key for the request, or `undefined` when none
|
|
11813
|
+
* was supplied (permissionless mode).
|
|
11814
|
+
* @returns Nothing.
|
|
11815
|
+
* @throws KitError with VALIDATION_FAILED when a kit key is supplied while
|
|
11816
|
+
* running in a browser environment. The secret value is never echoed.
|
|
11817
|
+
*
|
|
11818
|
+
* @example
|
|
11819
|
+
* ```typescript
|
|
11820
|
+
* import { assertBrowserSafeApiKey } from '@core/service-client'
|
|
11821
|
+
*
|
|
11822
|
+
* // Server (Node.js): no-op, request proceeds with the Authorization header.
|
|
11823
|
+
* assertBrowserSafeApiKey('KIT_KEY:my-id:my-secret')
|
|
11824
|
+
*
|
|
11825
|
+
* // Browser: throws to stop the secret from leaking into the client bundle.
|
|
11826
|
+
* assertBrowserSafeApiKey('KIT_KEY:my-id:my-secret')
|
|
11827
|
+
*
|
|
11828
|
+
* // Browser, permissionless: allowed.
|
|
11829
|
+
* assertBrowserSafeApiKey(undefined)
|
|
11830
|
+
* ```
|
|
11831
|
+
*/ const assertBrowserSafeApiKey = (apiKey)=>{
|
|
11832
|
+
if (apiKey === undefined) {
|
|
11833
|
+
return;
|
|
11834
|
+
}
|
|
11835
|
+
if (isBrowserEnvironment()) {
|
|
11836
|
+
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');
|
|
11837
|
+
}
|
|
11838
|
+
};
|
|
11693
11839
|
|
|
11694
11840
|
/**
|
|
11695
11841
|
* Create a cross-chain bridge and swap transaction through the Stablecoin Service.
|
|
@@ -11747,6 +11893,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11747
11893
|
const url = new URL('/v1/stablecoinKits/swap', STABLECOIN_SERVICE_BASE_URL).toString();
|
|
11748
11894
|
// Remove the API key from the request body
|
|
11749
11895
|
const { apiKey, ...requestBody } = validatedParams;
|
|
11896
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
11897
|
+
assertBrowserSafeApiKey(apiKey);
|
|
11750
11898
|
const effectiveConfig = {
|
|
11751
11899
|
...DEFAULT_CONFIG,
|
|
11752
11900
|
headers: {
|
|
@@ -11901,6 +12049,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11901
12049
|
}
|
|
11902
12050
|
// Use validated data
|
|
11903
12051
|
const validatedParams = result.data;
|
|
12052
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
12053
|
+
assertBrowserSafeApiKey(validatedParams.apiKey);
|
|
11904
12054
|
// Build the API URL
|
|
11905
12055
|
const url = buildQuoteUrl(validatedParams);
|
|
11906
12056
|
// Merge default config with Authorization header
|
|
@@ -11973,6 +12123,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11973
12123
|
toChain: result.data.toChain
|
|
11974
12124
|
}
|
|
11975
12125
|
};
|
|
12126
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
12127
|
+
assertBrowserSafeApiKey(validatedParams.apiKey);
|
|
11976
12128
|
const url = buildSwapStatusUrl(validatedParams);
|
|
11977
12129
|
const effectiveConfig = {
|
|
11978
12130
|
...DEFAULT_CONFIG,
|
|
@@ -12077,6 +12229,8 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
12077
12229
|
addresses: result.data.addresses
|
|
12078
12230
|
}
|
|
12079
12231
|
};
|
|
12232
|
+
// Never let a server-only kit key leave a browser (no-op in Node.js).
|
|
12233
|
+
assertBrowserSafeApiKey(validatedParams.apiKey);
|
|
12080
12234
|
const url = buildTokenRatesUrl(validatedParams);
|
|
12081
12235
|
const effectiveConfig = {
|
|
12082
12236
|
...DEFAULT_CONFIG,
|
|
@@ -16503,6 +16657,11 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16503
16657
|
apiKey: serviceParams.apiKey
|
|
16504
16658
|
}
|
|
16505
16659
|
});
|
|
16660
|
+
// Per-swap correlation id returned by the service as a top-level response
|
|
16661
|
+
// field for every chain (EVM + Solana). Attached to success telemetry so a
|
|
16662
|
+
// swap can be correlated across records; never used for control flow.
|
|
16663
|
+
// Undefined only against a not-yet-upgraded service that omits it.
|
|
16664
|
+
const correlationId = serviceResponse.correlationId;
|
|
16506
16665
|
// Build and return SwapResult
|
|
16507
16666
|
return {
|
|
16508
16667
|
tokenIn,
|
|
@@ -16512,6 +16671,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16512
16671
|
fromAddress: serviceParams.fromAddress,
|
|
16513
16672
|
toAddress: serviceParams.toAddress,
|
|
16514
16673
|
txHash,
|
|
16674
|
+
...correlationId !== undefined && {
|
|
16675
|
+
correlationId
|
|
16676
|
+
},
|
|
16515
16677
|
executedTransactions,
|
|
16516
16678
|
...config !== undefined && {
|
|
16517
16679
|
config
|
|
@@ -19411,7 +19573,13 @@ async function resolveTokenDecimals(context, resolvedParams) {
|
|
|
19411
19573
|
* amountIn: '50.00'
|
|
19412
19574
|
* })
|
|
19413
19575
|
* ```
|
|
19414
|
-
*/ async function swap(context, params, /**
|
|
19576
|
+
*/ async function swap(context, params, /**
|
|
19577
|
+
* @internal
|
|
19578
|
+
* Invoked after a successful broadcast with the on-chain `txHash` and the
|
|
19579
|
+
* service-issued `correlationId` (join key for success telemetry). The
|
|
19580
|
+
* service returns `correlationId` for every chain (EVM + Solana); it is
|
|
19581
|
+
* undefined only against a not-yet-upgraded service that omits the field.
|
|
19582
|
+
*/ onBroadcast) {
|
|
19415
19583
|
// Step 1: Validate parameters using schema
|
|
19416
19584
|
assertSwapParams(params, swapParamsSchema);
|
|
19417
19585
|
// Step 2: Resolve parameters (chain definitions, wallet addresses, token aliases preserved)
|
|
@@ -19431,13 +19599,16 @@ async function resolveTokenDecimals(context, resolvedParams) {
|
|
|
19431
19599
|
// Step 5: Execute swap via provider
|
|
19432
19600
|
const swapParams = buildServiceSwapParams(resolvedParams, paramsWithFees);
|
|
19433
19601
|
const providerResult = await provider.swap(swapParams);
|
|
19602
|
+
// `correlationId` is an internal telemetry join key, not part of the public
|
|
19603
|
+
// SwapResult — strip it here so it never leaks into the formatted result.
|
|
19604
|
+
const { correlationId, ...providerResultPublic } = providerResult;
|
|
19434
19605
|
// A throwing `onBroadcast` must never strand the caller after a
|
|
19435
19606
|
// successful swap broadcast — the chain has moved. `safeInvokeCallback`
|
|
19436
19607
|
// swallows the error and surfaces a `console.warn` prefixed with
|
|
19437
19608
|
// `[stablecoin-kits swap-kit] callback threw and was swallowed:` so a
|
|
19438
19609
|
// kit-side closure bug stays debuggable rather than vanishing.
|
|
19439
19610
|
safeInvokeCallback('swap-kit', ()=>{
|
|
19440
|
-
onBroadcast?.(
|
|
19611
|
+
onBroadcast?.(providerResultPublic.txHash, correlationId);
|
|
19441
19612
|
});
|
|
19442
19613
|
const { tokenInDecimals, tokenOutDecimals } = await resolveTokenDecimals(context, resolvedParams);
|
|
19443
19614
|
// Step 6: Compose chain identity (owned by the kit, derived from the
|
|
@@ -19446,10 +19617,10 @@ async function resolveTokenDecimals(context, resolvedParams) {
|
|
|
19446
19617
|
// resolves `progress` — the provider's snapshot, or a terminal `'DONE'` for
|
|
19447
19618
|
// a provider that omits it (a synchronous same-chain completion).
|
|
19448
19619
|
const composedResult = {
|
|
19449
|
-
...
|
|
19620
|
+
...providerResultPublic,
|
|
19450
19621
|
chainIn: resolvedParams.from.chain,
|
|
19451
19622
|
chainOut: resolvedParams.toChain ?? resolvedParams.from.chain,
|
|
19452
|
-
progress:
|
|
19623
|
+
progress: providerResultPublic.progress ?? {
|
|
19453
19624
|
status: 'DONE'
|
|
19454
19625
|
}
|
|
19455
19626
|
};
|
|
@@ -20302,7 +20473,13 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20302
20473
|
*/ class SwapKit {
|
|
20303
20474
|
context;
|
|
20304
20475
|
/** Whether error telemetry is disabled. */ disableErrorReporting;
|
|
20305
|
-
/** Per-kit telemetry identity for
|
|
20476
|
+
/** Per-kit telemetry identity for error reporting. */ telemetryConfig;
|
|
20477
|
+
/**
|
|
20478
|
+
* Per-kit telemetry identity for success/analytics events. Gated by
|
|
20479
|
+
* `disableAnalytics` (independent of `disableErrorReporting`) so a developer
|
|
20480
|
+
* can opt out of volume analytics without also silencing error reports —
|
|
20481
|
+
* mirrors EarnKit.
|
|
20482
|
+
*/ analyticsTelemetryConfig;
|
|
20306
20483
|
/**
|
|
20307
20484
|
* Create a new SwapKit instance.
|
|
20308
20485
|
*
|
|
@@ -20356,6 +20533,11 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20356
20533
|
sdkVersion: pkg$1.version,
|
|
20357
20534
|
disabled: this.disableErrorReporting
|
|
20358
20535
|
};
|
|
20536
|
+
this.analyticsTelemetryConfig = {
|
|
20537
|
+
sdkName: SDK_NAME,
|
|
20538
|
+
sdkVersion: pkg$1.version,
|
|
20539
|
+
disabled: config.disableAnalytics === true
|
|
20540
|
+
};
|
|
20359
20541
|
}
|
|
20360
20542
|
/**
|
|
20361
20543
|
* Estimate the output amount and fees for a swap operation.
|
|
@@ -20396,8 +20578,12 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20396
20578
|
* console.log(`Fees:`, quote.fees)
|
|
20397
20579
|
* ```
|
|
20398
20580
|
*/ async estimate(params) {
|
|
20581
|
+
const destinationChain = params.to?.chain ? resolveChainName(params.to.chain) : undefined;
|
|
20399
20582
|
return withErrorTelemetry(async ()=>estimate(this.context, params), SWAP_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
|
|
20400
20583
|
sourceChain: resolveChainName(params.from.chain),
|
|
20584
|
+
...destinationChain != null && {
|
|
20585
|
+
destinationChain
|
|
20586
|
+
},
|
|
20401
20587
|
tokenIn: params.tokenIn,
|
|
20402
20588
|
tokenOut: params.tokenOut
|
|
20403
20589
|
});
|
|
@@ -20456,16 +20642,54 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
20456
20642
|
* ```
|
|
20457
20643
|
*/ async swap(params) {
|
|
20458
20644
|
let txHash;
|
|
20459
|
-
|
|
20460
|
-
|
|
20461
|
-
|
|
20645
|
+
let correlationId;
|
|
20646
|
+
// Shared context builder so the error resolver and the success emit stay in
|
|
20647
|
+
// lockstep — a field added here reaches both call sites. Reads the per-call
|
|
20648
|
+
// locals lazily, so txHash/correlationId (set during the swap) are captured
|
|
20649
|
+
// whenever it is invoked.
|
|
20650
|
+
// Destination chain is the primary attribution dimension for cross-chain
|
|
20651
|
+
// swaps; resolved once from the (static) params. Omitted for same-chain
|
|
20652
|
+
// swaps that leave `to.chain` unset (destination == source).
|
|
20653
|
+
const destinationChain = params.to?.chain ? resolveChainName(params.to.chain) : undefined;
|
|
20654
|
+
const buildTelemetryContext = ()=>({
|
|
20462
20655
|
sourceChain: resolveChainName(params.from.chain),
|
|
20656
|
+
...destinationChain != null && {
|
|
20657
|
+
destinationChain
|
|
20658
|
+
},
|
|
20463
20659
|
tokenIn: params.tokenIn,
|
|
20464
20660
|
tokenOut: params.tokenOut,
|
|
20465
20661
|
...txHash != null && {
|
|
20466
20662
|
txHash
|
|
20663
|
+
},
|
|
20664
|
+
...correlationId != null && {
|
|
20665
|
+
correlationId
|
|
20467
20666
|
}
|
|
20468
|
-
})
|
|
20667
|
+
});
|
|
20668
|
+
const result = await withErrorTelemetry(async ()=>swap(this.context, params, (h, cId)=>{
|
|
20669
|
+
txHash = h;
|
|
20670
|
+
correlationId = cId;
|
|
20671
|
+
}), SWAP_EVENT_TYPES.SWAP, this.telemetryConfig, buildTelemetryContext);
|
|
20672
|
+
// withErrorTelemetry only emits on failure. Record the successful swap here
|
|
20673
|
+
// so the backend can attribute swap volume to a developer: the client event
|
|
20674
|
+
// carries the (burn) txHash + correlationId, which joins to the
|
|
20675
|
+
// server-emitted event carrying entity_id. Best-effort; never throws.
|
|
20676
|
+
//
|
|
20677
|
+
// Emit whenever a broadcast happened, i.e. we have the source/burn txHash.
|
|
20678
|
+
// For a cross-chain swap that is the source-chain burn (progress is still
|
|
20679
|
+
// PENDING while the destination mint settles) — we intentionally attribute
|
|
20680
|
+
// at broadcast using the burn txHash rather than tracking the destination
|
|
20681
|
+
// leg, which keeps the capture simple and self-contained in swap().
|
|
20682
|
+
//
|
|
20683
|
+
// Guard against a terminal-failure result: the EVM provider throws on
|
|
20684
|
+
// revert today, but the kit is provider-agnostic, so a provider that
|
|
20685
|
+
// returns a FAILED/NOT_FOUND result without throwing must not be recorded
|
|
20686
|
+
// as a successful swap. Routed through analyticsTelemetryConfig so it is
|
|
20687
|
+
// gated by disableAnalytics, independent of error reporting.
|
|
20688
|
+
const status = result.progress?.status;
|
|
20689
|
+
if (txHash != null && status !== 'FAILED' && status !== 'NOT_FOUND') {
|
|
20690
|
+
emitSuccessTelemetry(SWAP_EVENT_TYPES.SWAP, this.analyticsTelemetryConfig, buildTelemetryContext());
|
|
20691
|
+
}
|
|
20692
|
+
return result;
|
|
20469
20693
|
}
|
|
20470
20694
|
/**
|
|
20471
20695
|
* Fetch the current status of a swap from the Stablecoin Service.
|
|
@@ -20844,6 +21068,9 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
20844
21068
|
const kit = new SwapKit({
|
|
20845
21069
|
...context.disableErrorReporting != null && {
|
|
20846
21070
|
disableErrorReporting: context.disableErrorReporting
|
|
21071
|
+
},
|
|
21072
|
+
...context.disableAnalytics != null && {
|
|
21073
|
+
disableAnalytics: context.disableAnalytics
|
|
20847
21074
|
}
|
|
20848
21075
|
});
|
|
20849
21076
|
if (hasBoth) {
|
|
@@ -20905,7 +21132,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
20905
21132
|
};
|
|
20906
21133
|
|
|
20907
21134
|
var name = "@circle-fin/earn-kit";
|
|
20908
|
-
var version = "1.
|
|
21135
|
+
var version = "1.4.0";
|
|
20909
21136
|
var pkg = {
|
|
20910
21137
|
name: name,
|
|
20911
21138
|
version: version};
|
|
@@ -22369,6 +22596,8 @@ function hasCrossChainDepositQuoteShape(params) {
|
|
|
22369
22596
|
config: earnConfigSchema.optional()
|
|
22370
22597
|
});
|
|
22371
22598
|
|
|
22599
|
+
/** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg.name);
|
|
22600
|
+
|
|
22372
22601
|
// Auto-register this kit for user agent tracking
|
|
22373
22602
|
registerKit(`${pkg.name}/${pkg.version}`);
|
|
22374
22603
|
|
package/estimateSwap.d.cts
CHANGED
|
@@ -6712,10 +6712,21 @@ interface AppKitContext {
|
|
|
6712
6712
|
* ```
|
|
6713
6713
|
*/
|
|
6714
6714
|
actions: Record<'bridge' | 'earn', Record<string, ((payload: unknown) => void)[]>>;
|
|
6715
|
+
/**
|
|
6716
|
+
* Disable success analytics for the underlying EarnKit, SwapKit, and
|
|
6717
|
+
* UnifiedBalanceKit.
|
|
6718
|
+
*
|
|
6719
|
+
* When `true`, completed earn, swap, and unified balance operations will not
|
|
6720
|
+
* POST analytics events. This does not disable error reporting; use
|
|
6721
|
+
* {@link AppKitContext.disableErrorReporting} for that. Defaults to `false`.
|
|
6722
|
+
*
|
|
6723
|
+
* @defaultValue false
|
|
6724
|
+
*/
|
|
6725
|
+
disableAnalytics?: boolean;
|
|
6715
6726
|
/**
|
|
6716
6727
|
* Disable error telemetry for all sub-kits.
|
|
6717
6728
|
*
|
|
6718
|
-
* When `true`, none of the underlying kits (BridgeKit, SwapKit,
|
|
6729
|
+
* When `true`, none of the underlying kits (BridgeKit, SwapKit, EarnKit,
|
|
6719
6730
|
* UnifiedBalanceKit) will POST error details to the telemetry
|
|
6720
6731
|
* endpoint when operations throw. Defaults to `false` (enabled).
|
|
6721
6732
|
*
|
package/estimateSwap.d.mts
CHANGED
|
@@ -6712,10 +6712,21 @@ interface AppKitContext {
|
|
|
6712
6712
|
* ```
|
|
6713
6713
|
*/
|
|
6714
6714
|
actions: Record<'bridge' | 'earn', Record<string, ((payload: unknown) => void)[]>>;
|
|
6715
|
+
/**
|
|
6716
|
+
* Disable success analytics for the underlying EarnKit, SwapKit, and
|
|
6717
|
+
* UnifiedBalanceKit.
|
|
6718
|
+
*
|
|
6719
|
+
* When `true`, completed earn, swap, and unified balance operations will not
|
|
6720
|
+
* POST analytics events. This does not disable error reporting; use
|
|
6721
|
+
* {@link AppKitContext.disableErrorReporting} for that. Defaults to `false`.
|
|
6722
|
+
*
|
|
6723
|
+
* @defaultValue false
|
|
6724
|
+
*/
|
|
6725
|
+
disableAnalytics?: boolean;
|
|
6715
6726
|
/**
|
|
6716
6727
|
* Disable error telemetry for all sub-kits.
|
|
6717
6728
|
*
|
|
6718
|
-
* When `true`, none of the underlying kits (BridgeKit, SwapKit,
|
|
6729
|
+
* When `true`, none of the underlying kits (BridgeKit, SwapKit, EarnKit,
|
|
6719
6730
|
* UnifiedBalanceKit) will POST error details to the telemetry
|
|
6720
6731
|
* endpoint when operations throw. Defaults to `false` (enabled).
|
|
6721
6732
|
*
|
package/estimateSwap.d.ts
CHANGED
|
@@ -6712,10 +6712,21 @@ interface AppKitContext {
|
|
|
6712
6712
|
* ```
|
|
6713
6713
|
*/
|
|
6714
6714
|
actions: Record<'bridge' | 'earn', Record<string, ((payload: unknown) => void)[]>>;
|
|
6715
|
+
/**
|
|
6716
|
+
* Disable success analytics for the underlying EarnKit, SwapKit, and
|
|
6717
|
+
* UnifiedBalanceKit.
|
|
6718
|
+
*
|
|
6719
|
+
* When `true`, completed earn, swap, and unified balance operations will not
|
|
6720
|
+
* POST analytics events. This does not disable error reporting; use
|
|
6721
|
+
* {@link AppKitContext.disableErrorReporting} for that. Defaults to `false`.
|
|
6722
|
+
*
|
|
6723
|
+
* @defaultValue false
|
|
6724
|
+
*/
|
|
6725
|
+
disableAnalytics?: boolean;
|
|
6715
6726
|
/**
|
|
6716
6727
|
* Disable error telemetry for all sub-kits.
|
|
6717
6728
|
*
|
|
6718
|
-
* When `true`, none of the underlying kits (BridgeKit, SwapKit,
|
|
6729
|
+
* When `true`, none of the underlying kits (BridgeKit, SwapKit, EarnKit,
|
|
6719
6730
|
* UnifiedBalanceKit) will POST error details to the telemetry
|
|
6720
6731
|
* endpoint when operations throw. Defaults to `false` (enabled).
|
|
6721
6732
|
*
|