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