@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/earn.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
|
require('@ethersproject/bytes');
|
|
@@ -28,8 +39,8 @@ require('bn.js');
|
|
|
28
39
|
require('@coral-xyz/anchor');
|
|
29
40
|
require('bs58');
|
|
30
41
|
require('@noble/curves/ed25519');
|
|
31
|
-
var keccak256 = require('@ethersproject/keccak256');
|
|
32
42
|
var units = require('@ethersproject/units');
|
|
43
|
+
var keccak256 = require('@ethersproject/keccak256');
|
|
33
44
|
|
|
34
45
|
// Import global type declarations
|
|
35
46
|
/**
|
|
@@ -46,6 +57,51 @@ var units = require('@ethersproject/units');
|
|
|
46
57
|
* }
|
|
47
58
|
* ```
|
|
48
59
|
*/ const isNodeEnvironment = ()=>typeof process !== 'undefined' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
|
|
60
|
+
/**
|
|
61
|
+
* Check whether the current runtime exposes a browser DOM.
|
|
62
|
+
*
|
|
63
|
+
* @remarks
|
|
64
|
+
* This intentionally does not treat every non-Node runtime as a browser.
|
|
65
|
+
* Server-side edge runtimes such as Cloudflare Workers, Deno, and Supabase
|
|
66
|
+
* Edge Functions do not expose Node globals but can safely use server
|
|
67
|
+
* credentials. A Node.js runtime remains server-side even when a test or SSR
|
|
68
|
+
* environment provides a DOM shim.
|
|
69
|
+
*
|
|
70
|
+
* @returns `true` when running in a browser window, `false` otherwise.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* import { isBrowserEnvironment } from '@core/utils'
|
|
75
|
+
*
|
|
76
|
+
* if (isBrowserEnvironment()) {
|
|
77
|
+
* throw new Error('Server-only secrets must not be used in the browser')
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/ const isBrowserEnvironment = ()=>{
|
|
81
|
+
const browserWindow = globalThis.window;
|
|
82
|
+
return !isNodeEnvironment() && browserWindow?.document !== undefined;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Return the SDK User-Agent request header only when running in Node.js.
|
|
86
|
+
*
|
|
87
|
+
* Browsers forbid manually setting `User-Agent`, and a custom fallback header
|
|
88
|
+
* can trigger CORS preflight. Non-Node server runtimes also omit this optional
|
|
89
|
+
* attribution header because they cannot set it reliably.
|
|
90
|
+
*
|
|
91
|
+
* @returns A User-Agent header in Node.js, or an empty object otherwise.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* import { getNodeUserAgentHeader } from '@core/utils'
|
|
96
|
+
*
|
|
97
|
+
* const headers = {
|
|
98
|
+
* 'Content-Type': 'application/json',
|
|
99
|
+
* ...getNodeUserAgentHeader(),
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/ const getNodeUserAgentHeader = ()=>isNodeEnvironment() ? {
|
|
103
|
+
'User-Agent': getUserAgent()
|
|
104
|
+
} : {};
|
|
49
105
|
/**
|
|
50
106
|
* Detect the runtime environment and return a shortened identifier.
|
|
51
107
|
*
|
|
@@ -6394,6 +6450,39 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
6394
6450
|
throw new Error(`Invalid chain identifier type: ${typeof chainIdentifier}. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
6395
6451
|
}
|
|
6396
6452
|
|
|
6453
|
+
/**
|
|
6454
|
+
* Resolve a chain identifier to a plain chain-name string.
|
|
6455
|
+
*
|
|
6456
|
+
* Accept a string literal (`'Ethereum'`), a `ChainDefinition`-like
|
|
6457
|
+
* object (`{ chain: 'Ethereum' }`), or `null`/`undefined` and return
|
|
6458
|
+
* the chain name as a string. Return `undefined` when the value
|
|
6459
|
+
* cannot be resolved.
|
|
6460
|
+
*
|
|
6461
|
+
* @remarks
|
|
6462
|
+
* Unlike `resolveChainIdentifier` (which returns a full `ChainDefinition`
|
|
6463
|
+
* and throws on invalid input), this helper is intentionally lenient and
|
|
6464
|
+
* never throws — it is safe to call in error-handling and telemetry paths.
|
|
6465
|
+
*
|
|
6466
|
+
* @param value - A string, chain-definition object, or nullish value.
|
|
6467
|
+
* @returns The chain name string, or `undefined`.
|
|
6468
|
+
*
|
|
6469
|
+
* @example
|
|
6470
|
+
* ```typescript
|
|
6471
|
+
* import { resolveChainName } from '@core/chains'
|
|
6472
|
+
*
|
|
6473
|
+
* resolveChainName('Ethereum') // 'Ethereum'
|
|
6474
|
+
* resolveChainName({ chain: 'Ethereum' }) // 'Ethereum'
|
|
6475
|
+
* resolveChainName(undefined) // undefined
|
|
6476
|
+
* ```
|
|
6477
|
+
*/ function resolveChainName(value) {
|
|
6478
|
+
if (value == null) return undefined;
|
|
6479
|
+
if (typeof value === 'string') return value;
|
|
6480
|
+
if (typeof value === 'object' && 'chain' in value && typeof value.chain === 'string') {
|
|
6481
|
+
return value.chain;
|
|
6482
|
+
}
|
|
6483
|
+
return undefined;
|
|
6484
|
+
}
|
|
6485
|
+
|
|
6397
6486
|
/**
|
|
6398
6487
|
* Extracts chain information including name, display name, and expected address format.
|
|
6399
6488
|
*
|
|
@@ -6778,13 +6867,12 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
6778
6867
|
headers: {
|
|
6779
6868
|
...DEFAULT_CONFIG$1.headers,
|
|
6780
6869
|
...config.headers ?? {},
|
|
6781
|
-
//
|
|
6782
|
-
//
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
}
|
|
6870
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
6871
|
+
// fallback header the SDK used instead trips CORS preflight against the
|
|
6872
|
+
// Circle APIs (it isn't in their `Access-Control-Allow-Headers`),
|
|
6873
|
+
// blocking the request. So send the SDK user agent only in Node;
|
|
6874
|
+
// browsers omit it entirely.
|
|
6875
|
+
...getNodeUserAgentHeader()
|
|
6788
6876
|
}
|
|
6789
6877
|
};
|
|
6790
6878
|
let lastError;
|
|
@@ -8050,6 +8138,216 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8050
8138
|
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
8051
8139
|
*/ const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
8052
8140
|
|
|
8141
|
+
/**
|
|
8142
|
+
* Project an arbitrary payload onto the exact set of fields the telemetry
|
|
8143
|
+
* endpoint accepts.
|
|
8144
|
+
*
|
|
8145
|
+
* @remarks
|
|
8146
|
+
* Defense-in-depth before the last network hop: rather than
|
|
8147
|
+
* `JSON.stringify`-ing the caller's object verbatim, only the
|
|
8148
|
+
* allowlisted {@link ClientLogPayload} fields (and the allowlisted
|
|
8149
|
+
* sub-fields of `errorDetails` / `clientContext`) are copied across.
|
|
8150
|
+
* A regressing upstream mapper — or a plain-JS caller that bypasses the
|
|
8151
|
+
* type — therefore cannot exfiltrate stray properties (secrets, PII,
|
|
8152
|
+
* raw error stacks) through the analytics channel. Optional fields are
|
|
8153
|
+
* only included when present so the serialised shape matches the
|
|
8154
|
+
* server's strict schema.
|
|
8155
|
+
*
|
|
8156
|
+
* @internal
|
|
8157
|
+
*/ function toSafePayload(payload) {
|
|
8158
|
+
const clientContext = {
|
|
8159
|
+
platform: payload.clientContext.platform,
|
|
8160
|
+
os: payload.clientContext.os,
|
|
8161
|
+
runtimeName: payload.clientContext.runtimeName
|
|
8162
|
+
};
|
|
8163
|
+
const safe = {
|
|
8164
|
+
sdkName: payload.sdkName,
|
|
8165
|
+
sdkVersion: payload.sdkVersion,
|
|
8166
|
+
eventType: payload.eventType,
|
|
8167
|
+
timestamp: payload.timestamp,
|
|
8168
|
+
clientContext
|
|
8169
|
+
};
|
|
8170
|
+
if (payload.sourceChain !== undefined) safe['sourceChain'] = payload.sourceChain;
|
|
8171
|
+
if (payload.destinationChain !== undefined) safe['destinationChain'] = payload.destinationChain;
|
|
8172
|
+
if (payload.tokenIn !== undefined) safe['tokenIn'] = payload.tokenIn;
|
|
8173
|
+
if (payload.tokenOut !== undefined) safe['tokenOut'] = payload.tokenOut;
|
|
8174
|
+
if (payload.txHash !== undefined) safe['txHash'] = payload.txHash;
|
|
8175
|
+
if (payload.correlationId !== undefined) safe['correlationId'] = payload.correlationId;
|
|
8176
|
+
if (payload.errorDetails !== undefined) {
|
|
8177
|
+
const errorDetails = {
|
|
8178
|
+
...payload.errorDetails.errorCode !== undefined && {
|
|
8179
|
+
errorCode: payload.errorDetails.errorCode
|
|
8180
|
+
},
|
|
8181
|
+
...payload.errorDetails.errorType !== undefined && {
|
|
8182
|
+
errorType: payload.errorDetails.errorType
|
|
8183
|
+
}
|
|
8184
|
+
};
|
|
8185
|
+
safe['errorDetails'] = errorDetails;
|
|
8186
|
+
}
|
|
8187
|
+
return safe;
|
|
8188
|
+
}
|
|
8189
|
+
/**
|
|
8190
|
+
* Default telemetry endpoint.
|
|
8191
|
+
*
|
|
8192
|
+
* Override via the `STABLECOIN_KITS_TELEMETRY_URL` environment variable
|
|
8193
|
+
* (e.g. for staging or local development).
|
|
8194
|
+
*
|
|
8195
|
+
* @internal
|
|
8196
|
+
*/ const DEFAULT_LOGS_URL = 'https://api.circle.com/v1/stablecoinKits/logs';
|
|
8197
|
+
/**
|
|
8198
|
+
* Resolve the telemetry endpoint URL.
|
|
8199
|
+
*
|
|
8200
|
+
* @internal
|
|
8201
|
+
*/ function getLogsUrl() {
|
|
8202
|
+
if (isNodeEnvironment() && typeof process.env['STABLECOIN_KITS_TELEMETRY_URL'] === 'string' && process.env['STABLECOIN_KITS_TELEMETRY_URL'].length > 0) {
|
|
8203
|
+
return process.env['STABLECOIN_KITS_TELEMETRY_URL'];
|
|
8204
|
+
}
|
|
8205
|
+
return DEFAULT_LOGS_URL;
|
|
8206
|
+
}
|
|
8207
|
+
/**
|
|
8208
|
+
* Send a telemetry event to the proxy service.
|
|
8209
|
+
*
|
|
8210
|
+
* @remarks
|
|
8211
|
+
* Fire-and-forget: the returned promise is intentionally not awaited
|
|
8212
|
+
* by the caller. A fetch failure (network error, non-2xx, timeout)
|
|
8213
|
+
* is silently swallowed so telemetry never blocks or fails user
|
|
8214
|
+
* operations.
|
|
8215
|
+
*
|
|
8216
|
+
* @param payload - The structured log payload matching the server schema.
|
|
8217
|
+
*
|
|
8218
|
+
* @example
|
|
8219
|
+
* ```typescript
|
|
8220
|
+
* import { emitAnalyticsLog } from '@core/utils'
|
|
8221
|
+
*
|
|
8222
|
+
* // Fire-and-forget — do not await
|
|
8223
|
+
* void emitAnalyticsLog(payload)
|
|
8224
|
+
* ```
|
|
8225
|
+
*/ async function emitAnalyticsLog(payload) {
|
|
8226
|
+
// Hand-rolled timeout via `AbortController` + `setTimeout` rather than
|
|
8227
|
+
// `AbortSignal.timeout(...)` so we can `clearTimeout` the handle in a
|
|
8228
|
+
// `finally`. `AbortSignal.timeout` registers a timer that stays on the
|
|
8229
|
+
// event loop until it fires even if the fetch already settled, which
|
|
8230
|
+
// manifests as spurious `TimeoutError` unhandled rejections during
|
|
8231
|
+
// process teardown (notably between e2e test fork lifecycles). See
|
|
8232
|
+
// nodejs/node#48298 for the underlying issue.
|
|
8233
|
+
const controller = new AbortController();
|
|
8234
|
+
const timeoutHandle = setTimeout(()=>{
|
|
8235
|
+
controller.abort(new DOMException('Telemetry request timed out', 'TimeoutError'));
|
|
8236
|
+
}, 5_000);
|
|
8237
|
+
// Don't let the timer keep the Node event loop alive in short-lived
|
|
8238
|
+
// CLIs / test processes; telemetry is best-effort and must never
|
|
8239
|
+
// block clean process exit. `unref` only exists on Node's `Timeout`
|
|
8240
|
+
// object, not on the `number` returned by the browser's `setTimeout`,
|
|
8241
|
+
// so we feature-detect rather than call unconditionally.
|
|
8242
|
+
if (typeof timeoutHandle.unref === 'function') {
|
|
8243
|
+
timeoutHandle.unref();
|
|
8244
|
+
}
|
|
8245
|
+
try {
|
|
8246
|
+
await fetch(getLogsUrl(), {
|
|
8247
|
+
method: 'POST',
|
|
8248
|
+
headers: {
|
|
8249
|
+
'Content-Type': 'application/json',
|
|
8250
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
8251
|
+
// fallback header the SDK used instead trips CORS preflight (it isn't
|
|
8252
|
+
// in the telemetry endpoint's `Access-Control-Allow-Headers`), so send
|
|
8253
|
+
// it only in Node; browsers omit it entirely.
|
|
8254
|
+
...getNodeUserAgentHeader()
|
|
8255
|
+
},
|
|
8256
|
+
body: JSON.stringify(toSafePayload(payload)),
|
|
8257
|
+
signal: controller.signal
|
|
8258
|
+
});
|
|
8259
|
+
} catch {
|
|
8260
|
+
// Silently swallow — telemetry must never break user operations.
|
|
8261
|
+
} finally{
|
|
8262
|
+
clearTimeout(timeoutHandle);
|
|
8263
|
+
}
|
|
8264
|
+
}
|
|
8265
|
+
|
|
8266
|
+
/**
|
|
8267
|
+
* Build the `clientContext` object for telemetry payloads.
|
|
8268
|
+
*
|
|
8269
|
+
* @remarks
|
|
8270
|
+
* Use the exported `getRuntime()` and `isNodeEnvironment()` from
|
|
8271
|
+
* `@core/utils` to detect the runtime environment. The returned
|
|
8272
|
+
* string is parsed into the structured `ClientContext` fields
|
|
8273
|
+
* expected by the server schema.
|
|
8274
|
+
*
|
|
8275
|
+
* @returns A {@link ClientContext} with platform, OS, and runtime name
|
|
8276
|
+
* populated from the current environment.
|
|
8277
|
+
*
|
|
8278
|
+
* @example
|
|
8279
|
+
* ```typescript
|
|
8280
|
+
* import { buildClientContext } from '@core/utils'
|
|
8281
|
+
*
|
|
8282
|
+
* const ctx = buildClientContext()
|
|
8283
|
+
* // Node: { platform: 'node', os: 'darwin', runtimeName: null }
|
|
8284
|
+
* // Browser: { platform: 'browser', os: null, runtimeName: 'chrome' }
|
|
8285
|
+
* ```
|
|
8286
|
+
*/ function buildClientContext() {
|
|
8287
|
+
const runtime = getRuntime();
|
|
8288
|
+
if (runtime.startsWith('browser/')) {
|
|
8289
|
+
return {
|
|
8290
|
+
platform: 'browser',
|
|
8291
|
+
os: null,
|
|
8292
|
+
runtimeName: runtime.slice('browser/'.length).toLowerCase()
|
|
8293
|
+
};
|
|
8294
|
+
}
|
|
8295
|
+
if (runtime.startsWith('node/')) {
|
|
8296
|
+
return {
|
|
8297
|
+
platform: 'node',
|
|
8298
|
+
os: isNodeEnvironment() ? process.platform : null,
|
|
8299
|
+
runtimeName: null
|
|
8300
|
+
};
|
|
8301
|
+
}
|
|
8302
|
+
return {
|
|
8303
|
+
platform: 'node',
|
|
8304
|
+
os: null,
|
|
8305
|
+
runtimeName: null
|
|
8306
|
+
};
|
|
8307
|
+
}
|
|
8308
|
+
|
|
8309
|
+
/**
|
|
8310
|
+
* Extract structured error details from an unknown error value.
|
|
8311
|
+
*
|
|
8312
|
+
* @remarks
|
|
8313
|
+
* Handle three cases:
|
|
8314
|
+
* - `KitError` — extract `code` and `name`.
|
|
8315
|
+
* - `Error` — extract `name`.
|
|
8316
|
+
* - Anything else — return empty details.
|
|
8317
|
+
*
|
|
8318
|
+
* Only structured, bounded fields (`errorCode`, `errorType`) are
|
|
8319
|
+
* included. Free-text fields (`message`, `stack`) are intentionally
|
|
8320
|
+
* omitted to avoid leaking secrets or PII through vendor telemetry.
|
|
8321
|
+
*
|
|
8322
|
+
* @param error - The thrown value to extract details from.
|
|
8323
|
+
* @returns A {@link ErrorDetails} object suitable for telemetry payloads.
|
|
8324
|
+
*
|
|
8325
|
+
* @example
|
|
8326
|
+
* ```typescript
|
|
8327
|
+
* import { extractErrorDetails } from '@core/utils'
|
|
8328
|
+
*
|
|
8329
|
+
* try {
|
|
8330
|
+
* await riskyOperation()
|
|
8331
|
+
* } catch (error) {
|
|
8332
|
+
* const details = extractErrorDetails(error)
|
|
8333
|
+
* // { errorCode: '1001', errorType: 'INPUT_NETWORK_MISMATCH' }
|
|
8334
|
+
* }
|
|
8335
|
+
* ```
|
|
8336
|
+
*/ function extractErrorDetails(error) {
|
|
8337
|
+
if (error instanceof KitError) {
|
|
8338
|
+
return {
|
|
8339
|
+
errorCode: String(error.code),
|
|
8340
|
+
errorType: error.name
|
|
8341
|
+
};
|
|
8342
|
+
}
|
|
8343
|
+
if (error instanceof Error) {
|
|
8344
|
+
return {
|
|
8345
|
+
errorType: error.name
|
|
8346
|
+
};
|
|
8347
|
+
}
|
|
8348
|
+
return {};
|
|
8349
|
+
}
|
|
8350
|
+
|
|
8053
8351
|
/**
|
|
8054
8352
|
* Strip the `@circle-fin/` scope from a kit package name to produce the
|
|
8055
8353
|
* short SDK name used in telemetry payloads.
|
|
@@ -8068,8 +8366,154 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8068
8366
|
return pkgName.replace('@circle-fin/', '');
|
|
8069
8367
|
}
|
|
8070
8368
|
|
|
8369
|
+
/**
|
|
8370
|
+
* Soft signal for the case where building or emitting a telemetry payload
|
|
8371
|
+
* threw — for example, a buggy `TelemetryContextResolver`, a regression in
|
|
8372
|
+
* `extractErrorDetails`, or a synchronous failure inside `emitAnalyticsLog`
|
|
8373
|
+
* before it could swallow the error itself. Logged with a stable prefix so
|
|
8374
|
+
* consumers can grep for it. We deliberately do not re-throw: the caller's
|
|
8375
|
+
* original operation error must always win.
|
|
8376
|
+
*
|
|
8377
|
+
* @internal
|
|
8378
|
+
*/ function warnTelemetryDrop(eventType, cause) {
|
|
8379
|
+
try {
|
|
8380
|
+
// Pass `cause` as the second console.warn argument rather than
|
|
8381
|
+
// string-coercing it. `String(err)` (and `err.message` alone)
|
|
8382
|
+
// discards the stack trace, nested `cause`, and any custom Error
|
|
8383
|
+
// properties — exactly the context an on-call needs when a
|
|
8384
|
+
// resolver-closure regression triggers this path.
|
|
8385
|
+
console.warn(`[stablecoin-kits telemetry] dropped event '${eventType}':`, cause);
|
|
8386
|
+
} catch {
|
|
8387
|
+
// console.warn itself throwing is the user's environment; nothing more we
|
|
8388
|
+
// can do without risking the original operation error.
|
|
8389
|
+
}
|
|
8390
|
+
}
|
|
8391
|
+
/**
|
|
8392
|
+
* Build a telemetry payload from common fields.
|
|
8393
|
+
*
|
|
8394
|
+
* @internal
|
|
8395
|
+
*/ function buildPayload(config, eventType, errorDetails, context) {
|
|
8396
|
+
return {
|
|
8397
|
+
sdkName: config.sdkName,
|
|
8398
|
+
sdkVersion: config.sdkVersion,
|
|
8399
|
+
eventType,
|
|
8400
|
+
timestamp: new Date().toISOString(),
|
|
8401
|
+
...errorDetails !== undefined && {
|
|
8402
|
+
errorDetails
|
|
8403
|
+
},
|
|
8404
|
+
clientContext: buildClientContext(),
|
|
8405
|
+
...context?.sourceChain != null && {
|
|
8406
|
+
sourceChain: context.sourceChain
|
|
8407
|
+
},
|
|
8408
|
+
...context?.destinationChain != null && {
|
|
8409
|
+
destinationChain: context.destinationChain
|
|
8410
|
+
},
|
|
8411
|
+
...context?.tokenIn != null && {
|
|
8412
|
+
tokenIn: context.tokenIn
|
|
8413
|
+
},
|
|
8414
|
+
...context?.tokenOut != null && {
|
|
8415
|
+
tokenOut: context.tokenOut
|
|
8416
|
+
},
|
|
8417
|
+
...context?.txHash != null && {
|
|
8418
|
+
txHash: context.txHash
|
|
8419
|
+
},
|
|
8420
|
+
...context?.correlationId != null && {
|
|
8421
|
+
correlationId: context.correlationId
|
|
8422
|
+
}
|
|
8423
|
+
};
|
|
8424
|
+
}
|
|
8425
|
+
/**
|
|
8426
|
+
* Emit telemetry for a completed operation without affecting its caller.
|
|
8427
|
+
*
|
|
8428
|
+
* No-ops when `config.disabled` is `true`. Like {@link withErrorTelemetry},
|
|
8429
|
+
* failures while constructing or submitting the telemetry payload are reported
|
|
8430
|
+
* as a soft warning and never change a completed operation's result.
|
|
8431
|
+
*
|
|
8432
|
+
* @param eventType - The telemetry event type for the completed operation.
|
|
8433
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
8434
|
+
* @param context - Optional chain, token, and transaction context.
|
|
8435
|
+
* @returns Nothing.
|
|
8436
|
+
* @throws Never — telemetry failures are reported as warnings.
|
|
8437
|
+
*
|
|
8438
|
+
* @example
|
|
8439
|
+
* ```typescript
|
|
8440
|
+
* import { emitSuccessTelemetry } from '@core/utils'
|
|
8441
|
+
*
|
|
8442
|
+
* emitSuccessTelemetry(
|
|
8443
|
+
* 'bridge_bridge',
|
|
8444
|
+
* { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
|
|
8445
|
+
* { sourceChain: 'Ethereum', destinationChain: 'Base', tokenIn: 'USDC' },
|
|
8446
|
+
* )
|
|
8447
|
+
* ```
|
|
8448
|
+
*/ function emitSuccessTelemetry(eventType, config, context) {
|
|
8449
|
+
if (config.disabled) {
|
|
8450
|
+
return;
|
|
8451
|
+
}
|
|
8452
|
+
try {
|
|
8453
|
+
void emitAnalyticsLog(buildPayload(config, eventType, undefined, context));
|
|
8454
|
+
} catch (telemetryError) {
|
|
8455
|
+
warnTelemetryDrop(eventType, telemetryError);
|
|
8456
|
+
}
|
|
8457
|
+
}
|
|
8458
|
+
/**
|
|
8459
|
+
* Wrap an async operation with error telemetry.
|
|
8460
|
+
*
|
|
8461
|
+
* Execute `fn` and, if it throws, emit an error telemetry payload
|
|
8462
|
+
* before re-throwing. No-ops when `config.disabled` is `true`.
|
|
8463
|
+
*
|
|
8464
|
+
* `context` may be a static {@link TelemetryContext} or a
|
|
8465
|
+
* {@link TelemetryContextResolver}. The resolver is invoked in the
|
|
8466
|
+
* catch branch, so it can read state — most importantly `txHash` —
|
|
8467
|
+
* that the wrapped operation set after a successful broadcast. The
|
|
8468
|
+
* resolver must close over per-call locals only; passing instance
|
|
8469
|
+
* state would break isolation between concurrent invocations.
|
|
8470
|
+
*
|
|
8471
|
+
* @param fn - The async operation to execute.
|
|
8472
|
+
* @param eventType - The telemetry event type for this operation.
|
|
8473
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
8474
|
+
* @param context - Optional context, static or lazily resolved.
|
|
8475
|
+
* @returns The result of the operation.
|
|
8476
|
+
* @throws Re-throws any error after emitting telemetry.
|
|
8477
|
+
*
|
|
8478
|
+
* @example
|
|
8479
|
+
* ```typescript
|
|
8480
|
+
* import { withErrorTelemetry } from '@core/utils'
|
|
8481
|
+
*
|
|
8482
|
+
* let txHash: string | undefined
|
|
8483
|
+
* const result = await withErrorTelemetry(
|
|
8484
|
+
* () => provider.swap(params, h => { txHash = h }),
|
|
8485
|
+
* 'swap_swap',
|
|
8486
|
+
* { sdkName: 'swap-kit', sdkVersion: '1.0.0', disabled: false },
|
|
8487
|
+
* () => ({
|
|
8488
|
+
* sourceChain: 'Ethereum',
|
|
8489
|
+
* tokenIn: 'USDC',
|
|
8490
|
+
* tokenOut: 'EURC',
|
|
8491
|
+
* ...(txHash != null && { txHash }),
|
|
8492
|
+
* }),
|
|
8493
|
+
* )
|
|
8494
|
+
* ```
|
|
8495
|
+
*/ async function withErrorTelemetry(fn, eventType, config, context) {
|
|
8496
|
+
try {
|
|
8497
|
+
return await fn();
|
|
8498
|
+
} catch (error) {
|
|
8499
|
+
if (!config.disabled) {
|
|
8500
|
+
try {
|
|
8501
|
+
const resolved = typeof context === 'function' ? context() : context;
|
|
8502
|
+
void emitAnalyticsLog(buildPayload(config, eventType, extractErrorDetails(error), resolved));
|
|
8503
|
+
} catch (telemetryError) {
|
|
8504
|
+
// Never let telemetry emission mask the original operation error.
|
|
8505
|
+
// But surface a soft signal so silent telemetry drops are
|
|
8506
|
+
// discoverable (e.g. a regression in a resolver closure or in
|
|
8507
|
+
// `extractErrorDetails`) instead of vanishing without any trace.
|
|
8508
|
+
warnTelemetryDrop(eventType, telemetryError);
|
|
8509
|
+
}
|
|
8510
|
+
}
|
|
8511
|
+
throw error;
|
|
8512
|
+
}
|
|
8513
|
+
}
|
|
8514
|
+
|
|
8071
8515
|
var name$3 = "@circle-fin/bridge-kit";
|
|
8072
|
-
var version$3 = "1.12.
|
|
8516
|
+
var version$3 = "1.12.2";
|
|
8073
8517
|
var pkg$3 = {
|
|
8074
8518
|
name: name$3,
|
|
8075
8519
|
version: version$3};
|
|
@@ -8897,7 +9341,13 @@ var TransferSpeed;
|
|
|
8897
9341
|
/**
|
|
8898
9342
|
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
8899
9343
|
* hookData must start with.
|
|
8900
|
-
|
|
9344
|
+
*
|
|
9345
|
+
* Encoded with `TextEncoder` (a browser-safe Web API) rather than `Buffer.from`
|
|
9346
|
+
* so this module-level constant does not reference the Node `Buffer` global at
|
|
9347
|
+
* import time. App Kit inlines this provider into its bundle without a Buffer polyfill, and a
|
|
9348
|
+
* bare `Buffer` here crashes browser bundles (e.g. Vite) on load — even for apps
|
|
9349
|
+
* that never touch the prepaid FORWARD path. Mirrors `buildForwardingHookData`.
|
|
9350
|
+
*/ Array.from(new TextEncoder().encode(CCTP_FORWARD_MAGIC_PREFIX)).map((byte)=>byte.toString(16).padStart(2, '0')).join('');
|
|
8901
9351
|
|
|
8902
9352
|
/**
|
|
8903
9353
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
@@ -8931,7 +9381,7 @@ var TransferSpeed;
|
|
|
8931
9381
|
registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
8932
9382
|
|
|
8933
9383
|
var name$2 = "@circle-fin/swap-kit";
|
|
8934
|
-
var version$2 = "1.
|
|
9384
|
+
var version$2 = "1.5.0";
|
|
8935
9385
|
var pkg$2 = {
|
|
8936
9386
|
name: name$2,
|
|
8937
9387
|
version: version$2};
|
|
@@ -9672,6 +10122,16 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9672
10122
|
required_error: 'estimatedAmount is required',
|
|
9673
10123
|
invalid_type_error: 'estimatedAmount must be a string'
|
|
9674
10124
|
}).min(1, 'estimatedAmount must be a non-empty string'),
|
|
10125
|
+
// Per-swap join key echoed back verbatim on success telemetry. Optional so a
|
|
10126
|
+
// not-yet-upgraded service (no field) still validates during rollout. A
|
|
10127
|
+
// malformed/non-UUID value is coerced to `undefined` (no telemetry id) rather
|
|
10128
|
+
// than throwing: this is a telemetry-only field (stripped from the developer
|
|
10129
|
+
// result, never used for control flow), so it must not be able to abort the
|
|
10130
|
+
// swap via `parseCreateSwapResponse().parse()`. Mirrors the best-effort,
|
|
10131
|
+
// never-throw contract of the rest of the telemetry stack. Implemented with
|
|
10132
|
+
// `preprocess` rather than Zod's `.catch()` because static analysis misreads
|
|
10133
|
+
// `.catch` on the schema chain as an unhandled Promise (S7785).
|
|
10134
|
+
correlationId: zod.z.preprocess((value)=>zod.z.string().uuid().safeParse(value).success ? value : undefined, zod.z.string().optional()),
|
|
9675
10135
|
config: createSwapRequestBaseSchema.shape.config.optional(),
|
|
9676
10136
|
fees: createSwapFeesSchema.optional(),
|
|
9677
10137
|
transaction: createSwapTransactionSchema
|
|
@@ -12230,7 +12690,7 @@ new Set(Object.values(Blockchain));
|
|
|
12230
12690
|
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
12231
12691
|
|
|
12232
12692
|
var name$1 = "@circle-fin/earn-kit";
|
|
12233
|
-
var version$1 = "1.
|
|
12693
|
+
var version$1 = "1.4.0";
|
|
12234
12694
|
var pkg$1 = {
|
|
12235
12695
|
name: name$1,
|
|
12236
12696
|
version: version$1};
|
|
@@ -14229,7 +14689,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
14229
14689
|
}
|
|
14230
14690
|
|
|
14231
14691
|
var name = "@circle-fin/provider-earn-service";
|
|
14232
|
-
var version = "1.3.
|
|
14692
|
+
var version = "1.3.1";
|
|
14233
14693
|
var pkg = {
|
|
14234
14694
|
name: name,
|
|
14235
14695
|
version: version};
|
|
@@ -14291,15 +14751,25 @@ var pkg = {
|
|
|
14291
14751
|
*
|
|
14292
14752
|
* @internal
|
|
14293
14753
|
*/ function buildConfig(serviceConfig) {
|
|
14754
|
+
// The kit key is a server-only secret. Reject it in the browser so it cannot
|
|
14755
|
+
// leak into a client bundle (no-op in Node.js). Keyless usage stays allowed.
|
|
14756
|
+
if (serviceConfig?.kitKey !== undefined && isBrowserEnvironment()) {
|
|
14757
|
+
throw createValidationFailedError('kitKey', '[redacted]', 'kitKey must not be provided in a browser environment — it is a server-only secret. Run EarnKit operations that use a kit key on your server, or omit kitKey to use the permissionless (keyless) client path');
|
|
14758
|
+
}
|
|
14294
14759
|
const baseUrl = serviceConfig?.baseUrl ?? EARN_SERVICE_BASE_URL;
|
|
14295
|
-
|
|
14760
|
+
// The API CORS policy does not allow this custom header. Keep the existing
|
|
14761
|
+
// per-request version attribution for Node callers, but omit it in browsers
|
|
14762
|
+
// so public EarnKit endpoints do not fail at CORS preflight.
|
|
14763
|
+
const sdkVersionHeader = isNodeEnvironment() ? {
|
|
14764
|
+
[SDK_VERSION_HEADER]: resolveSdkVersionHeader()
|
|
14765
|
+
} : {};
|
|
14296
14766
|
if (serviceConfig?.kitKey === undefined) {
|
|
14297
14767
|
return {
|
|
14298
14768
|
pollingConfig: {
|
|
14299
14769
|
...DEFAULT_CONFIG,
|
|
14300
14770
|
headers: {
|
|
14301
14771
|
...DEFAULT_CONFIG.headers,
|
|
14302
|
-
|
|
14772
|
+
...sdkVersionHeader
|
|
14303
14773
|
}
|
|
14304
14774
|
},
|
|
14305
14775
|
baseUrl
|
|
@@ -14317,7 +14787,7 @@ var pkg = {
|
|
|
14317
14787
|
...DEFAULT_CONFIG,
|
|
14318
14788
|
headers: {
|
|
14319
14789
|
...DEFAULT_CONFIG.headers,
|
|
14320
|
-
|
|
14790
|
+
...sdkVersionHeader,
|
|
14321
14791
|
Authorization: `Bearer ${serviceConfig.kitKey}`
|
|
14322
14792
|
}
|
|
14323
14793
|
},
|
|
@@ -16421,6 +16891,12 @@ function createUnsupportedCrossChainDepositError(chain, reason) {
|
|
|
16421
16891
|
if (config.providers !== undefined && !Array.isArray(config.providers)) {
|
|
16422
16892
|
throw createValidationFailedError('config.providers', config.providers, 'providers must be an array of earn providers when provided');
|
|
16423
16893
|
}
|
|
16894
|
+
if (config.disableAnalytics !== undefined && typeof config.disableAnalytics !== 'boolean') {
|
|
16895
|
+
throw createValidationFailedError('config.disableAnalytics', config.disableAnalytics, 'disableAnalytics must be a boolean when provided');
|
|
16896
|
+
}
|
|
16897
|
+
if (config.disableErrorReporting !== undefined && typeof config.disableErrorReporting !== 'boolean') {
|
|
16898
|
+
throw createValidationFailedError('config.disableErrorReporting', config.disableErrorReporting, 'disableErrorReporting must be a boolean when provided');
|
|
16899
|
+
}
|
|
16424
16900
|
const defaultProviders = getDefaultProviders();
|
|
16425
16901
|
const providers = [
|
|
16426
16902
|
...config.providers ?? [],
|
|
@@ -16432,6 +16908,31 @@ function createUnsupportedCrossChainDepositError(chain, reason) {
|
|
|
16432
16908
|
return context;
|
|
16433
16909
|
}
|
|
16434
16910
|
|
|
16911
|
+
/**
|
|
16912
|
+
* Register Earn Kit telemetry event type strings with the shared registry so
|
|
16913
|
+
* error telemetry helpers remain compile-time checked.
|
|
16914
|
+
*
|
|
16915
|
+
* @internal
|
|
16916
|
+
*/ /**
|
|
16917
|
+
* Telemetry event type identifiers for Earn Kit operations.
|
|
16918
|
+
*
|
|
16919
|
+
* @internal
|
|
16920
|
+
*/ const EARN_EVENT_TYPES = {
|
|
16921
|
+
GET_VAULTS: 'earn_get_vaults',
|
|
16922
|
+
EXPLORE_VAULTS: 'earn_explore_vaults',
|
|
16923
|
+
GET_POSITION: 'earn_get_position',
|
|
16924
|
+
GET_CROSS_CHAIN_DEPOSIT_STATUS: 'earn_get_cross_chain_deposit_status',
|
|
16925
|
+
WAIT_FOR_CROSS_CHAIN_DEPOSIT: 'earn_wait_for_cross_chain_deposit',
|
|
16926
|
+
DEPOSIT: 'earn_deposit',
|
|
16927
|
+
CROSS_CHAIN_DEPOSIT: 'earn_cross_chain_deposit',
|
|
16928
|
+
WITHDRAW: 'earn_withdraw',
|
|
16929
|
+
CLAIM_REWARDS: 'earn_claim_rewards',
|
|
16930
|
+
GET_DEPOSIT_QUOTE: 'earn_get_deposit_quote',
|
|
16931
|
+
GET_WITHDRAWAL_QUOTE: 'earn_get_withdrawal_quote',
|
|
16932
|
+
GET_CLAIM_REWARDS_QUOTE: 'earn_get_claim_rewards_quote',
|
|
16933
|
+
RETRY: 'earn_retry'
|
|
16934
|
+
};
|
|
16935
|
+
|
|
16435
16936
|
/**
|
|
16436
16937
|
* Format a provider amount object as a human-readable decimal string.
|
|
16437
16938
|
*
|
|
@@ -17947,6 +18448,14 @@ function hasCrossChainDestination(params) {
|
|
|
17947
18448
|
return formatClaimRewardsQuoteInfo(result);
|
|
17948
18449
|
}
|
|
17949
18450
|
|
|
18451
|
+
/** SDK name used in telemetry payloads. */ const SDK_NAME = resolveKitSdkName(pkg$1.name);
|
|
18452
|
+
/**
|
|
18453
|
+
* Determine whether deposit parameters target a destination chain.
|
|
18454
|
+
*
|
|
18455
|
+
* @internal
|
|
18456
|
+
*/ function isCrossChainDeposit(params) {
|
|
18457
|
+
return 'to' in params && params.to !== undefined;
|
|
18458
|
+
}
|
|
17950
18459
|
function formatRetryResult(operation, result) {
|
|
17951
18460
|
switch(operation){
|
|
17952
18461
|
case 'deposit':
|
|
@@ -17961,6 +18470,70 @@ function formatRetryResult(operation, result) {
|
|
|
17961
18470
|
}
|
|
17962
18471
|
}
|
|
17963
18472
|
}
|
|
18473
|
+
/**
|
|
18474
|
+
* Emit the success event corresponding to a completed retry.
|
|
18475
|
+
*
|
|
18476
|
+
* @internal
|
|
18477
|
+
*/ function emitRetrySuccessTelemetry(trace, result, config) {
|
|
18478
|
+
switch(trace.operation){
|
|
18479
|
+
case 'deposit':
|
|
18480
|
+
{
|
|
18481
|
+
const sourceChain = resolveChainName(trace.params.from.chain);
|
|
18482
|
+
if ('to' in trace.params && trace.params.to !== undefined) {
|
|
18483
|
+
const destinationChain = resolveChainName(trace.params.to.chain);
|
|
18484
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.CROSS_CHAIN_DEPOSIT, config, {
|
|
18485
|
+
...sourceChain != null && {
|
|
18486
|
+
sourceChain
|
|
18487
|
+
},
|
|
18488
|
+
...destinationChain != null && {
|
|
18489
|
+
destinationChain
|
|
18490
|
+
}
|
|
18491
|
+
});
|
|
18492
|
+
return;
|
|
18493
|
+
}
|
|
18494
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.DEPOSIT, config, {
|
|
18495
|
+
...sourceChain != null && {
|
|
18496
|
+
sourceChain
|
|
18497
|
+
},
|
|
18498
|
+
...'txHash' in result && {
|
|
18499
|
+
txHash: result.txHash
|
|
18500
|
+
}
|
|
18501
|
+
});
|
|
18502
|
+
return;
|
|
18503
|
+
}
|
|
18504
|
+
case 'withdraw':
|
|
18505
|
+
{
|
|
18506
|
+
const sourceChain = resolveChainName(trace.params.from.chain);
|
|
18507
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.WITHDRAW, config, {
|
|
18508
|
+
...sourceChain != null && {
|
|
18509
|
+
sourceChain
|
|
18510
|
+
},
|
|
18511
|
+
...'txHash' in result && {
|
|
18512
|
+
txHash: result.txHash
|
|
18513
|
+
}
|
|
18514
|
+
});
|
|
18515
|
+
return;
|
|
18516
|
+
}
|
|
18517
|
+
case 'claimRewards':
|
|
18518
|
+
{
|
|
18519
|
+
if ('rewards' in result && result.status === 'claimed') {
|
|
18520
|
+
const sourceChain = resolveChainName(trace.params.from.chain);
|
|
18521
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.CLAIM_REWARDS, config, {
|
|
18522
|
+
...sourceChain != null && {
|
|
18523
|
+
sourceChain
|
|
18524
|
+
},
|
|
18525
|
+
txHash: result.txHash
|
|
18526
|
+
});
|
|
18527
|
+
}
|
|
18528
|
+
return;
|
|
18529
|
+
}
|
|
18530
|
+
default:
|
|
18531
|
+
{
|
|
18532
|
+
const exhaustive = trace;
|
|
18533
|
+
throw createValidationFailedError('error.cause.trace', exhaustive, 'EarnKit.retry() does not support this earn operation');
|
|
18534
|
+
}
|
|
18535
|
+
}
|
|
18536
|
+
}
|
|
17964
18537
|
/**
|
|
17965
18538
|
* A high-level class-based interface for DeFi lending vault operations.
|
|
17966
18539
|
*
|
|
@@ -18019,6 +18592,8 @@ function formatRetryResult(operation, result) {
|
|
|
18019
18592
|
* ```
|
|
18020
18593
|
*/ class EarnKit {
|
|
18021
18594
|
context;
|
|
18595
|
+
/** Per-kit identity and opt-out state for error telemetry. */ telemetryConfig;
|
|
18596
|
+
/** Per-kit identity and opt-out state for success telemetry. */ analyticsTelemetryConfig;
|
|
18022
18597
|
/**
|
|
18023
18598
|
* Event dispatcher for step-level events emitted during multi-phase earn
|
|
18024
18599
|
* operations. Prefer {@link EarnKit.on} / {@link EarnKit.off} over using
|
|
@@ -18043,6 +18618,16 @@ function formatRetryResult(operation, result) {
|
|
|
18043
18618
|
*/ constructor(config = {}){
|
|
18044
18619
|
this.context = createEarnKitContext(config);
|
|
18045
18620
|
this.actionDispatcher = new Actionable();
|
|
18621
|
+
this.telemetryConfig = {
|
|
18622
|
+
sdkName: SDK_NAME,
|
|
18623
|
+
sdkVersion: pkg$1.version,
|
|
18624
|
+
disabled: config.disableErrorReporting === true
|
|
18625
|
+
};
|
|
18626
|
+
this.analyticsTelemetryConfig = {
|
|
18627
|
+
sdkName: SDK_NAME,
|
|
18628
|
+
sdkVersion: pkg$1.version,
|
|
18629
|
+
disabled: config.disableAnalytics === true
|
|
18630
|
+
};
|
|
18046
18631
|
for (const provider of this.context.providers){
|
|
18047
18632
|
provider.registerDispatcher(this.actionDispatcher);
|
|
18048
18633
|
}
|
|
@@ -18103,29 +18688,36 @@ function formatRetryResult(operation, result) {
|
|
|
18103
18688
|
* }
|
|
18104
18689
|
* ```
|
|
18105
18690
|
*/ async retry(error) {
|
|
18106
|
-
|
|
18107
|
-
|
|
18108
|
-
|
|
18109
|
-
|
|
18110
|
-
|
|
18111
|
-
|
|
18112
|
-
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
|
|
18116
|
-
|
|
18117
|
-
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18123
|
-
|
|
18124
|
-
|
|
18125
|
-
|
|
18691
|
+
const result = await withErrorTelemetry(async ()=>{
|
|
18692
|
+
if (!isKitError(error)) {
|
|
18693
|
+
throw createValidationFailedError('error', error, 'EarnKit.retry() requires a KitError thrown by a previous earn operation');
|
|
18694
|
+
}
|
|
18695
|
+
if (!isRetryableError$1(error)) {
|
|
18696
|
+
throw createValidationFailedError('error.recoverability', error.recoverability, 'EarnKit.retry() requires a retryable or resumable error — check isRetryableError(error) first');
|
|
18697
|
+
}
|
|
18698
|
+
const trace = error.cause?.trace;
|
|
18699
|
+
if (!isEarnErrorTrace(trace)) {
|
|
18700
|
+
throw createValidationFailedError('error.cause.trace', trace, 'EarnKit.retry() requires a KitError carrying earn retry context (operation, steps, provider, params)');
|
|
18701
|
+
}
|
|
18702
|
+
const provider = this.context.providers.find((candidate)=>candidate.name === trace.provider);
|
|
18703
|
+
if (provider === undefined) {
|
|
18704
|
+
throw createValidationFailedError('error.cause.trace.provider', trace.provider, `No earn provider named "${trace.provider}" is registered with this kit`);
|
|
18705
|
+
}
|
|
18706
|
+
const result = await provider.retry(error);
|
|
18707
|
+
// `provider.retry` returns a flat result union with no compile-time link to
|
|
18708
|
+
// `trace.operation`, so narrow the operation here to select the matching
|
|
18709
|
+
// overload. The result cast in each branch is sound: the provider always
|
|
18710
|
+
// returns the result type corresponding to the resumed operation.
|
|
18711
|
+
if (trace.operation === 'claimRewards') {
|
|
18712
|
+
return formatRetryResult(trace.operation, result);
|
|
18713
|
+
}
|
|
18126
18714
|
return formatRetryResult(trace.operation, result);
|
|
18715
|
+
}, EARN_EVENT_TYPES.RETRY, this.telemetryConfig);
|
|
18716
|
+
const trace = isKitError(error) ? error.cause?.trace : undefined;
|
|
18717
|
+
if (isEarnErrorTrace(trace)) {
|
|
18718
|
+
emitRetrySuccessTelemetry(trace, result, this.analyticsTelemetryConfig);
|
|
18127
18719
|
}
|
|
18128
|
-
return
|
|
18720
|
+
return result;
|
|
18129
18721
|
}
|
|
18130
18722
|
/**
|
|
18131
18723
|
* Return the chains supported by configured earn providers.
|
|
@@ -18159,7 +18751,9 @@ function formatRetryResult(operation, result) {
|
|
|
18159
18751
|
* result.vaults.forEach(v => console.log(`${v.name}: ${(v.currentApy * 100).toFixed(2)}% APY`))
|
|
18160
18752
|
* ```
|
|
18161
18753
|
*/ async getVaults(params) {
|
|
18162
|
-
|
|
18754
|
+
const result = await withErrorTelemetry(async ()=>getVaults$1(this.context, params), EARN_EVENT_TYPES.GET_VAULTS, this.telemetryConfig);
|
|
18755
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.GET_VAULTS, this.analyticsTelemetryConfig, {});
|
|
18756
|
+
return result;
|
|
18163
18757
|
}
|
|
18164
18758
|
/**
|
|
18165
18759
|
* Discover vaults available on a chain.
|
|
@@ -18184,7 +18778,12 @@ function formatRetryResult(operation, result) {
|
|
|
18184
18778
|
* const guarded = result.vaults.filter(v => v.circleGuarded) // Circle-guarded vaults only
|
|
18185
18779
|
* ```
|
|
18186
18780
|
*/ async exploreVaults(params) {
|
|
18187
|
-
|
|
18781
|
+
const context = {
|
|
18782
|
+
sourceChain: resolveChainName(params.chain)
|
|
18783
|
+
};
|
|
18784
|
+
const result = await withErrorTelemetry(async ()=>exploreVaults$1(this.context, params), EARN_EVENT_TYPES.EXPLORE_VAULTS, this.telemetryConfig, context);
|
|
18785
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.EXPLORE_VAULTS, this.analyticsTelemetryConfig, context);
|
|
18786
|
+
return result;
|
|
18188
18787
|
}
|
|
18189
18788
|
/**
|
|
18190
18789
|
* Lazily iterate every vault available on a chain.
|
|
@@ -18231,7 +18830,9 @@ function formatRetryResult(operation, result) {
|
|
|
18231
18830
|
* }
|
|
18232
18831
|
* ```
|
|
18233
18832
|
*/ async getPosition(params) {
|
|
18234
|
-
return getPosition$1(this.context, params)
|
|
18833
|
+
return withErrorTelemetry(async ()=>getPosition$1(this.context, params), EARN_EVENT_TYPES.GET_POSITION, this.telemetryConfig, {
|
|
18834
|
+
sourceChain: resolveChainName(params.from.chain)
|
|
18835
|
+
});
|
|
18235
18836
|
}
|
|
18236
18837
|
/**
|
|
18237
18838
|
* Fetch the current status of a cross-chain deposit by execution ID.
|
|
@@ -18256,7 +18857,7 @@ function formatRetryResult(operation, result) {
|
|
|
18256
18857
|
* console.log(`Bridge ${status.execId} is ${status.status}`)
|
|
18257
18858
|
* ```
|
|
18258
18859
|
*/ async getCrossChainDepositStatus(params) {
|
|
18259
|
-
return getCrossChainDepositStatus$1(this.context, params);
|
|
18860
|
+
return withErrorTelemetry(async ()=>getCrossChainDepositStatus$1(this.context, params), EARN_EVENT_TYPES.GET_CROSS_CHAIN_DEPOSIT_STATUS, this.telemetryConfig);
|
|
18260
18861
|
}
|
|
18261
18862
|
/**
|
|
18262
18863
|
* Poll a cross-chain deposit until it reaches a terminal bridge state.
|
|
@@ -18283,10 +18884,30 @@ function formatRetryResult(operation, result) {
|
|
|
18283
18884
|
* console.log(`Bridge ended as ${result.outcome}`)
|
|
18284
18885
|
* ```
|
|
18285
18886
|
*/ async waitForCrossChainDeposit(params) {
|
|
18286
|
-
return waitForCrossChainDeposit$1(this.context, params);
|
|
18887
|
+
return withErrorTelemetry(async ()=>waitForCrossChainDeposit$1(this.context, params), EARN_EVENT_TYPES.WAIT_FOR_CROSS_CHAIN_DEPOSIT, this.telemetryConfig);
|
|
18287
18888
|
}
|
|
18288
18889
|
async deposit(params) {
|
|
18289
|
-
|
|
18890
|
+
const isCrossChain = isCrossChainDeposit(params);
|
|
18891
|
+
const context = {
|
|
18892
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
18893
|
+
...isCrossChain && {
|
|
18894
|
+
destinationChain: resolveChainName(params.to.chain)
|
|
18895
|
+
}
|
|
18896
|
+
};
|
|
18897
|
+
const eventType = isCrossChain ? EARN_EVENT_TYPES.CROSS_CHAIN_DEPOSIT : EARN_EVENT_TYPES.DEPOSIT;
|
|
18898
|
+
const result = await withErrorTelemetry(async ()=>deposit$1(this.context, params), eventType, this.telemetryConfig, context);
|
|
18899
|
+
if (result.kind === 'cross-chain') {
|
|
18900
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.CROSS_CHAIN_DEPOSIT, this.analyticsTelemetryConfig, {
|
|
18901
|
+
sourceChain: resolveChainName(result.sourceChain),
|
|
18902
|
+
destinationChain: resolveChainName(result.destinationChain)
|
|
18903
|
+
});
|
|
18904
|
+
} else {
|
|
18905
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.DEPOSIT, this.analyticsTelemetryConfig, {
|
|
18906
|
+
...context,
|
|
18907
|
+
txHash: result.txHash
|
|
18908
|
+
});
|
|
18909
|
+
}
|
|
18910
|
+
return result;
|
|
18290
18911
|
}
|
|
18291
18912
|
/**
|
|
18292
18913
|
* Execute a withdrawal from a DeFi lending vault.
|
|
@@ -18312,7 +18933,15 @@ function formatRetryResult(operation, result) {
|
|
|
18312
18933
|
* console.log(`Withdrew ${result.amount} from ${result.vaultAddress}, tx: ${result.txHash}`)
|
|
18313
18934
|
* ```
|
|
18314
18935
|
*/ async withdraw(params) {
|
|
18315
|
-
|
|
18936
|
+
const context = {
|
|
18937
|
+
sourceChain: resolveChainName(params.from.chain)
|
|
18938
|
+
};
|
|
18939
|
+
const result = await withErrorTelemetry(async ()=>withdraw$1(this.context, params), EARN_EVENT_TYPES.WITHDRAW, this.telemetryConfig, context);
|
|
18940
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.WITHDRAW, this.analyticsTelemetryConfig, {
|
|
18941
|
+
...context,
|
|
18942
|
+
txHash: result.txHash
|
|
18943
|
+
});
|
|
18944
|
+
return result;
|
|
18316
18945
|
}
|
|
18317
18946
|
/**
|
|
18318
18947
|
* Claim rewards from earn vaults.
|
|
@@ -18339,7 +18968,17 @@ function formatRetryResult(operation, result) {
|
|
|
18339
18968
|
*
|
|
18340
18969
|
* @internal
|
|
18341
18970
|
*/ async claimRewards(params) {
|
|
18342
|
-
|
|
18971
|
+
const context = {
|
|
18972
|
+
sourceChain: resolveChainName(params.from.chain)
|
|
18973
|
+
};
|
|
18974
|
+
const result = await withErrorTelemetry(async ()=>claimRewards$1(this.context, params), EARN_EVENT_TYPES.CLAIM_REWARDS, this.telemetryConfig, context);
|
|
18975
|
+
if (result.status === 'claimed') {
|
|
18976
|
+
emitSuccessTelemetry(EARN_EVENT_TYPES.CLAIM_REWARDS, this.analyticsTelemetryConfig, {
|
|
18977
|
+
...context,
|
|
18978
|
+
txHash: result.txHash
|
|
18979
|
+
});
|
|
18980
|
+
}
|
|
18981
|
+
return result;
|
|
18343
18982
|
}
|
|
18344
18983
|
/**
|
|
18345
18984
|
* Get an informational quote for a deposit into a vault.
|
|
@@ -18361,7 +19000,9 @@ function formatRetryResult(operation, result) {
|
|
|
18361
19000
|
* console.log(`Expected shares: ${quote.expectedShares.amount}`)
|
|
18362
19001
|
* ```
|
|
18363
19002
|
*/ async getDepositQuote(params) {
|
|
18364
|
-
return getDepositQuote$1(this.context, params)
|
|
19003
|
+
return withErrorTelemetry(async ()=>getDepositQuote$1(this.context, params), EARN_EVENT_TYPES.GET_DEPOSIT_QUOTE, this.telemetryConfig, {
|
|
19004
|
+
sourceChain: resolveChainName(params.from.chain)
|
|
19005
|
+
});
|
|
18365
19006
|
}
|
|
18366
19007
|
/**
|
|
18367
19008
|
* Get an informational quote for a withdrawal from a vault.
|
|
@@ -18383,7 +19024,9 @@ function formatRetryResult(operation, result) {
|
|
|
18383
19024
|
* console.log(`Shares to redeem: ${quote.sharesToRedeem.amount}`)
|
|
18384
19025
|
* ```
|
|
18385
19026
|
*/ async getWithdrawalQuote(params) {
|
|
18386
|
-
return getWithdrawalQuote$1(this.context, params)
|
|
19027
|
+
return withErrorTelemetry(async ()=>getWithdrawalQuote$1(this.context, params), EARN_EVENT_TYPES.GET_WITHDRAWAL_QUOTE, this.telemetryConfig, {
|
|
19028
|
+
sourceChain: resolveChainName(params.from.chain)
|
|
19029
|
+
});
|
|
18387
19030
|
}
|
|
18388
19031
|
/**
|
|
18389
19032
|
* Get an informational quote for claiming rewards.
|
|
@@ -18405,7 +19048,9 @@ function formatRetryResult(operation, result) {
|
|
|
18405
19048
|
*
|
|
18406
19049
|
* @internal
|
|
18407
19050
|
*/ async getClaimRewardsQuote(params) {
|
|
18408
|
-
return getClaimRewardsQuote$1(this.context, params)
|
|
19051
|
+
return withErrorTelemetry(async ()=>getClaimRewardsQuote$1(this.context, params), EARN_EVENT_TYPES.GET_CLAIM_REWARDS_QUOTE, this.telemetryConfig, {
|
|
19052
|
+
sourceChain: resolveChainName(params.from.chain)
|
|
19053
|
+
});
|
|
18409
19054
|
}
|
|
18410
19055
|
}
|
|
18411
19056
|
|
|
@@ -18494,7 +19139,14 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
18494
19139
|
* const earnKit = createEarnKit(context)
|
|
18495
19140
|
* ```
|
|
18496
19141
|
*/ const createEarnKit = (context)=>{
|
|
18497
|
-
const kit = new EarnKit(
|
|
19142
|
+
const kit = new EarnKit({
|
|
19143
|
+
...context.disableErrorReporting != null && {
|
|
19144
|
+
disableErrorReporting: context.disableErrorReporting
|
|
19145
|
+
},
|
|
19146
|
+
...context.disableAnalytics != null && {
|
|
19147
|
+
disableAnalytics: context.disableAnalytics
|
|
19148
|
+
}
|
|
19149
|
+
});
|
|
18498
19150
|
registerActionHandlers(kit, context.actions.earn, 'earn');
|
|
18499
19151
|
return kit;
|
|
18500
19152
|
};
|