@circle-fin/app-kit 1.4.2 → 1.5.1
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 +15 -0
- package/README.md +3 -3
- package/chains.cjs +96 -0
- package/chains.d.ts +2 -0
- package/chains.mjs +96 -0
- package/index.cjs +896 -224
- package/index.d.ts +153 -0
- package/index.mjs +896 -224
- package/package.json +5 -5
package/index.cjs
CHANGED
|
@@ -3405,6 +3405,8 @@ exports.Blockchain = void 0;
|
|
|
3405
3405
|
Blockchain["Hedera_Testnet"] = "Hedera_Testnet";
|
|
3406
3406
|
Blockchain["HyperEVM"] = "HyperEVM";
|
|
3407
3407
|
Blockchain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
3408
|
+
Blockchain["Injective"] = "Injective";
|
|
3409
|
+
Blockchain["Injective_Testnet"] = "Injective_Testnet";
|
|
3408
3410
|
Blockchain["Ink"] = "Ink";
|
|
3409
3411
|
Blockchain["Ink_Testnet"] = "Ink_Testnet";
|
|
3410
3412
|
Blockchain["Linea"] = "Linea";
|
|
@@ -3624,6 +3626,7 @@ exports.BridgeChain = void 0;
|
|
|
3624
3626
|
BridgeChain["Edge"] = "Edge";
|
|
3625
3627
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
3626
3628
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
3629
|
+
BridgeChain["Injective"] = "Injective";
|
|
3627
3630
|
BridgeChain["Ink"] = "Ink";
|
|
3628
3631
|
BridgeChain["Linea"] = "Linea";
|
|
3629
3632
|
BridgeChain["Monad"] = "Monad";
|
|
@@ -3647,6 +3650,7 @@ exports.BridgeChain = void 0;
|
|
|
3647
3650
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
3648
3651
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
3649
3652
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
3653
|
+
BridgeChain["Injective_Testnet"] = "Injective_Testnet";
|
|
3650
3654
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
3651
3655
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
3652
3656
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
@@ -5091,6 +5095,98 @@ const HyperEVMTestnet = defineChain({
|
|
|
5091
5095
|
},
|
|
5092
5096
|
});
|
|
5093
5097
|
|
|
5098
|
+
/**
|
|
5099
|
+
* Injective Mainnet chain definition
|
|
5100
|
+
* @remarks
|
|
5101
|
+
* This represents the official production network for the Injective blockchain.
|
|
5102
|
+
* Injective is a high-performance, interoperable Layer-1 blockchain built for
|
|
5103
|
+
* finance, with an EVM execution layer on top of a Cosmos SDK base and
|
|
5104
|
+
* sub-second block finality.
|
|
5105
|
+
*/
|
|
5106
|
+
const Injective = defineChain({
|
|
5107
|
+
type: 'evm',
|
|
5108
|
+
chain: exports.Blockchain.Injective,
|
|
5109
|
+
name: 'Injective',
|
|
5110
|
+
title: 'Injective Mainnet',
|
|
5111
|
+
nativeCurrency: {
|
|
5112
|
+
name: 'Injective',
|
|
5113
|
+
symbol: 'INJ',
|
|
5114
|
+
decimals: 18,
|
|
5115
|
+
},
|
|
5116
|
+
chainId: 1776,
|
|
5117
|
+
isTestnet: false,
|
|
5118
|
+
explorerUrl: 'https://injscan.com/transaction/{hash}',
|
|
5119
|
+
rpcEndpoints: ['https://sentry.evm-rpc.injective.network'],
|
|
5120
|
+
eurcAddress: null,
|
|
5121
|
+
usdcAddress: '0xa00C59fF5a080D2b954d0c75e46E22a0c371235a',
|
|
5122
|
+
usdtAddress: null,
|
|
5123
|
+
cctp: {
|
|
5124
|
+
domain: 29,
|
|
5125
|
+
contracts: {
|
|
5126
|
+
v2: {
|
|
5127
|
+
type: 'split',
|
|
5128
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
5129
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
5130
|
+
confirmations: 1,
|
|
5131
|
+
fastConfirmations: 1,
|
|
5132
|
+
},
|
|
5133
|
+
},
|
|
5134
|
+
forwarderSupported: {
|
|
5135
|
+
source: false,
|
|
5136
|
+
destination: false,
|
|
5137
|
+
},
|
|
5138
|
+
},
|
|
5139
|
+
kitContracts: {
|
|
5140
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
5141
|
+
},
|
|
5142
|
+
});
|
|
5143
|
+
|
|
5144
|
+
/**
|
|
5145
|
+
* Injective Testnet chain definition
|
|
5146
|
+
* @remarks
|
|
5147
|
+
* This represents the official test network for the Injective blockchain.
|
|
5148
|
+
* Injective is a high-performance, interoperable Layer-1 blockchain built for
|
|
5149
|
+
* finance, with an EVM execution layer on top of a Cosmos SDK base and
|
|
5150
|
+
* sub-second block finality.
|
|
5151
|
+
*/
|
|
5152
|
+
const InjectiveTestnet = defineChain({
|
|
5153
|
+
type: 'evm',
|
|
5154
|
+
chain: exports.Blockchain.Injective_Testnet,
|
|
5155
|
+
name: 'Injective Testnet',
|
|
5156
|
+
title: 'Injective Testnet',
|
|
5157
|
+
nativeCurrency: {
|
|
5158
|
+
name: 'Injective',
|
|
5159
|
+
symbol: 'INJ',
|
|
5160
|
+
decimals: 18,
|
|
5161
|
+
},
|
|
5162
|
+
chainId: 1439,
|
|
5163
|
+
isTestnet: true,
|
|
5164
|
+
explorerUrl: 'https://testnet.explorer.injective.network/transaction/{hash}',
|
|
5165
|
+
rpcEndpoints: ['https://k8s.testnet.json-rpc.injective.network'],
|
|
5166
|
+
eurcAddress: null,
|
|
5167
|
+
usdcAddress: '0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d',
|
|
5168
|
+
usdtAddress: null,
|
|
5169
|
+
cctp: {
|
|
5170
|
+
domain: 29,
|
|
5171
|
+
contracts: {
|
|
5172
|
+
v2: {
|
|
5173
|
+
type: 'split',
|
|
5174
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5175
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5176
|
+
confirmations: 1,
|
|
5177
|
+
fastConfirmations: 1,
|
|
5178
|
+
},
|
|
5179
|
+
},
|
|
5180
|
+
forwarderSupported: {
|
|
5181
|
+
source: false,
|
|
5182
|
+
destination: false,
|
|
5183
|
+
},
|
|
5184
|
+
},
|
|
5185
|
+
kitContracts: {
|
|
5186
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
5187
|
+
},
|
|
5188
|
+
});
|
|
5189
|
+
|
|
5094
5190
|
/**
|
|
5095
5191
|
* Ink Mainnet chain definition
|
|
5096
5192
|
* @remarks
|
|
@@ -6933,6 +7029,8 @@ var Chains = {
|
|
|
6933
7029
|
HederaTestnet: HederaTestnet,
|
|
6934
7030
|
HyperEVM: HyperEVM,
|
|
6935
7031
|
HyperEVMTestnet: HyperEVMTestnet,
|
|
7032
|
+
Injective: Injective,
|
|
7033
|
+
InjectiveTestnet: InjectiveTestnet,
|
|
6936
7034
|
Ink: Ink,
|
|
6937
7035
|
InkTestnet: InkTestnet,
|
|
6938
7036
|
Linea: Linea,
|
|
@@ -7554,6 +7652,44 @@ function resolveChainIdentifier(chainIdentifier) {
|
|
|
7554
7652
|
throw new Error(`Invalid chain identifier type: ${typeof chainIdentifier}. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
7555
7653
|
}
|
|
7556
7654
|
|
|
7655
|
+
/**
|
|
7656
|
+
* Resolve a chain identifier to a plain chain-name string.
|
|
7657
|
+
*
|
|
7658
|
+
* Accept a string literal (`'Ethereum'`), a `ChainDefinition`-like
|
|
7659
|
+
* object (`{ chain: 'Ethereum' }`), or `null`/`undefined` and return
|
|
7660
|
+
* the chain name as a string. Return `undefined` when the value
|
|
7661
|
+
* cannot be resolved.
|
|
7662
|
+
*
|
|
7663
|
+
* @remarks
|
|
7664
|
+
* Unlike `resolveChainIdentifier` (which returns a full `ChainDefinition`
|
|
7665
|
+
* and throws on invalid input), this helper is intentionally lenient and
|
|
7666
|
+
* never throws — it is safe to call in error-handling and telemetry paths.
|
|
7667
|
+
*
|
|
7668
|
+
* @param value - A string, chain-definition object, or nullish value.
|
|
7669
|
+
* @returns The chain name string, or `undefined`.
|
|
7670
|
+
*
|
|
7671
|
+
* @example
|
|
7672
|
+
* ```typescript
|
|
7673
|
+
* import { resolveChainName } from '@core/chains'
|
|
7674
|
+
*
|
|
7675
|
+
* resolveChainName('Ethereum') // 'Ethereum'
|
|
7676
|
+
* resolveChainName({ chain: 'Ethereum' }) // 'Ethereum'
|
|
7677
|
+
* resolveChainName(undefined) // undefined
|
|
7678
|
+
* ```
|
|
7679
|
+
*/
|
|
7680
|
+
function resolveChainName(value) {
|
|
7681
|
+
if (value == null)
|
|
7682
|
+
return undefined;
|
|
7683
|
+
if (typeof value === 'string')
|
|
7684
|
+
return value;
|
|
7685
|
+
if (typeof value === 'object' &&
|
|
7686
|
+
'chain' in value &&
|
|
7687
|
+
typeof value.chain === 'string') {
|
|
7688
|
+
return value.chain;
|
|
7689
|
+
}
|
|
7690
|
+
return undefined;
|
|
7691
|
+
}
|
|
7692
|
+
|
|
7557
7693
|
/**
|
|
7558
7694
|
* @packageDocumentation
|
|
7559
7695
|
* @module SwapTokenUtils
|
|
@@ -9210,6 +9346,7 @@ const USDC = {
|
|
|
9210
9346
|
[exports.Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
9211
9347
|
[exports.Blockchain.Hedera]: '0.0.456858',
|
|
9212
9348
|
[exports.Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
9349
|
+
[exports.Blockchain.Injective]: '0xa00C59fF5a080D2b954d0c75e46E22a0c371235a',
|
|
9213
9350
|
[exports.Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
9214
9351
|
[exports.Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
9215
9352
|
[exports.Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
@@ -9242,6 +9379,7 @@ const USDC = {
|
|
|
9242
9379
|
[exports.Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
9243
9380
|
[exports.Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
9244
9381
|
[exports.Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
9382
|
+
[exports.Blockchain.Injective_Testnet]: '0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d',
|
|
9245
9383
|
[exports.Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
9246
9384
|
[exports.Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
9247
9385
|
[exports.Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
@@ -10343,8 +10481,325 @@ async function retryAsync(fn, options) {
|
|
|
10343
10481
|
throw new Error('retryAsync: unreachable');
|
|
10344
10482
|
}
|
|
10345
10483
|
|
|
10484
|
+
/**
|
|
10485
|
+
* Default telemetry endpoint.
|
|
10486
|
+
*
|
|
10487
|
+
* Override via the `STABLECOIN_KITS_TELEMETRY_URL` environment variable
|
|
10488
|
+
* (e.g. for staging or local development).
|
|
10489
|
+
*
|
|
10490
|
+
* @internal
|
|
10491
|
+
*/
|
|
10492
|
+
const DEFAULT_LOGS_URL = 'https://api.circle.com/v1/stablecoinKits/logs';
|
|
10493
|
+
/**
|
|
10494
|
+
* Resolve the telemetry endpoint URL.
|
|
10495
|
+
*
|
|
10496
|
+
* @internal
|
|
10497
|
+
*/
|
|
10498
|
+
function getLogsUrl() {
|
|
10499
|
+
if (isNodeEnvironment() &&
|
|
10500
|
+
typeof process.env['STABLECOIN_KITS_TELEMETRY_URL'] === 'string' &&
|
|
10501
|
+
process.env['STABLECOIN_KITS_TELEMETRY_URL'].length > 0) {
|
|
10502
|
+
return process.env['STABLECOIN_KITS_TELEMETRY_URL'];
|
|
10503
|
+
}
|
|
10504
|
+
return DEFAULT_LOGS_URL;
|
|
10505
|
+
}
|
|
10506
|
+
/**
|
|
10507
|
+
* Send a telemetry event to the proxy service.
|
|
10508
|
+
*
|
|
10509
|
+
* @remarks
|
|
10510
|
+
* Fire-and-forget: the returned promise is intentionally not awaited
|
|
10511
|
+
* by the caller. A fetch failure (network error, non-2xx, timeout)
|
|
10512
|
+
* is silently swallowed so telemetry never blocks or fails user
|
|
10513
|
+
* operations.
|
|
10514
|
+
*
|
|
10515
|
+
* @param payload - The structured log payload matching the server schema.
|
|
10516
|
+
*
|
|
10517
|
+
* @example
|
|
10518
|
+
* ```typescript
|
|
10519
|
+
* import { emitAnalyticsLog } from '@core/utils'
|
|
10520
|
+
*
|
|
10521
|
+
* // Fire-and-forget — do not await
|
|
10522
|
+
* void emitAnalyticsLog(payload)
|
|
10523
|
+
* ```
|
|
10524
|
+
*/
|
|
10525
|
+
async function emitAnalyticsLog(payload) {
|
|
10526
|
+
try {
|
|
10527
|
+
const isNode = isNodeEnvironment();
|
|
10528
|
+
const userAgent = getUserAgent();
|
|
10529
|
+
await fetch(getLogsUrl(), {
|
|
10530
|
+
method: 'POST',
|
|
10531
|
+
headers: {
|
|
10532
|
+
'Content-Type': 'application/json',
|
|
10533
|
+
// Browser restricts setting User-Agent; use X-User-Agent instead.
|
|
10534
|
+
...(isNode
|
|
10535
|
+
? { 'User-Agent': userAgent }
|
|
10536
|
+
: { 'X-User-Agent': userAgent }),
|
|
10537
|
+
},
|
|
10538
|
+
body: JSON.stringify(payload),
|
|
10539
|
+
signal: AbortSignal.timeout(5_000),
|
|
10540
|
+
});
|
|
10541
|
+
}
|
|
10542
|
+
catch {
|
|
10543
|
+
// Silently swallow — telemetry must never break user operations.
|
|
10544
|
+
}
|
|
10545
|
+
}
|
|
10546
|
+
|
|
10547
|
+
/**
|
|
10548
|
+
* Build the `clientContext` object for telemetry payloads.
|
|
10549
|
+
*
|
|
10550
|
+
* @remarks
|
|
10551
|
+
* Use the exported `getRuntime()` and `isNodeEnvironment()` from
|
|
10552
|
+
* `@core/utils` to detect the runtime environment. The returned
|
|
10553
|
+
* string is parsed into the structured `ClientContext` fields
|
|
10554
|
+
* expected by the server schema.
|
|
10555
|
+
*
|
|
10556
|
+
* @returns A {@link ClientContext} with platform, OS, and runtime name
|
|
10557
|
+
* populated from the current environment.
|
|
10558
|
+
*
|
|
10559
|
+
* @example
|
|
10560
|
+
* ```typescript
|
|
10561
|
+
* import { buildClientContext } from '@core/utils'
|
|
10562
|
+
*
|
|
10563
|
+
* const ctx = buildClientContext()
|
|
10564
|
+
* // Node: { platform: 'node', os: 'darwin', runtimeName: null }
|
|
10565
|
+
* // Browser: { platform: 'browser', os: null, runtimeName: 'chrome' }
|
|
10566
|
+
* ```
|
|
10567
|
+
*/
|
|
10568
|
+
function buildClientContext() {
|
|
10569
|
+
const runtime = getRuntime();
|
|
10570
|
+
if (runtime.startsWith('browser/')) {
|
|
10571
|
+
return {
|
|
10572
|
+
platform: 'browser',
|
|
10573
|
+
os: null,
|
|
10574
|
+
runtimeName: runtime.slice('browser/'.length).toLowerCase(),
|
|
10575
|
+
};
|
|
10576
|
+
}
|
|
10577
|
+
if (runtime.startsWith('node/')) {
|
|
10578
|
+
return {
|
|
10579
|
+
platform: 'node',
|
|
10580
|
+
os: isNodeEnvironment() ? process.platform : null,
|
|
10581
|
+
runtimeName: null,
|
|
10582
|
+
};
|
|
10583
|
+
}
|
|
10584
|
+
return {
|
|
10585
|
+
platform: 'node',
|
|
10586
|
+
os: null,
|
|
10587
|
+
runtimeName: null,
|
|
10588
|
+
};
|
|
10589
|
+
}
|
|
10590
|
+
|
|
10591
|
+
/**
|
|
10592
|
+
* Extract structured error details from an unknown error value.
|
|
10593
|
+
*
|
|
10594
|
+
* @remarks
|
|
10595
|
+
* Handle three cases:
|
|
10596
|
+
* - `KitError` — extract `code` and `name`.
|
|
10597
|
+
* - `Error` — extract `name`.
|
|
10598
|
+
* - Anything else — return empty details.
|
|
10599
|
+
*
|
|
10600
|
+
* Only structured, bounded fields (`errorCode`, `errorType`) are
|
|
10601
|
+
* included. Free-text fields (`message`, `stack`) are intentionally
|
|
10602
|
+
* omitted to avoid leaking secrets or PII through vendor telemetry.
|
|
10603
|
+
*
|
|
10604
|
+
* @param error - The thrown value to extract details from.
|
|
10605
|
+
* @returns A {@link ErrorDetails} object suitable for telemetry payloads.
|
|
10606
|
+
*
|
|
10607
|
+
* @example
|
|
10608
|
+
* ```typescript
|
|
10609
|
+
* import { extractErrorDetails } from '@core/utils'
|
|
10610
|
+
*
|
|
10611
|
+
* try {
|
|
10612
|
+
* await riskyOperation()
|
|
10613
|
+
* } catch (error) {
|
|
10614
|
+
* const details = extractErrorDetails(error)
|
|
10615
|
+
* // { errorCode: '1001', errorType: 'INPUT_NETWORK_MISMATCH' }
|
|
10616
|
+
* }
|
|
10617
|
+
* ```
|
|
10618
|
+
*/
|
|
10619
|
+
function extractErrorDetails(error) {
|
|
10620
|
+
if (error instanceof KitError) {
|
|
10621
|
+
return {
|
|
10622
|
+
errorCode: String(error.code),
|
|
10623
|
+
errorType: error.name,
|
|
10624
|
+
};
|
|
10625
|
+
}
|
|
10626
|
+
if (error instanceof Error) {
|
|
10627
|
+
return {
|
|
10628
|
+
errorType: error.name,
|
|
10629
|
+
};
|
|
10630
|
+
}
|
|
10631
|
+
return {};
|
|
10632
|
+
}
|
|
10633
|
+
|
|
10634
|
+
/**
|
|
10635
|
+
* Register event handlers on an action dispatcher that emit analytics
|
|
10636
|
+
* telemetry for the configured events.
|
|
10637
|
+
*
|
|
10638
|
+
* @remarks
|
|
10639
|
+
* Subscribe to each action name in `actionEventMap`, call `mapEventToPayload`
|
|
10640
|
+
* for each event, and fire-and-forget `emitAnalyticsLog` if a non-null
|
|
10641
|
+
* payload is returned. All errors are silently swallowed so telemetry
|
|
10642
|
+
* never blocks or fails user operations.
|
|
10643
|
+
*
|
|
10644
|
+
* @param dispatcher - The `Actionable` instance from the kit.
|
|
10645
|
+
* @param sdkName - SDK package name (e.g. `'unified-balance-kit'`).
|
|
10646
|
+
* @param sdkVersion - SDK version string (e.g. `'1.0.0'`).
|
|
10647
|
+
* @param actionEventMap - Map of action names to subscribe to.
|
|
10648
|
+
* @param mapEventToPayload - Function that maps an action name and payload
|
|
10649
|
+
* to a {@link ClientLogPayload}, or `null` to skip logging.
|
|
10650
|
+
*
|
|
10651
|
+
* @example
|
|
10652
|
+
* ```typescript
|
|
10653
|
+
* import { registerTelemetryHandler } from '@core/utils'
|
|
10654
|
+
*
|
|
10655
|
+
* registerTelemetryHandler(
|
|
10656
|
+
* dispatcher,
|
|
10657
|
+
* 'unified-balance-kit',
|
|
10658
|
+
* '1.0.0',
|
|
10659
|
+
* VERB_EVENT_MAP,
|
|
10660
|
+
* mapSucceededEventToLog,
|
|
10661
|
+
* )
|
|
10662
|
+
* ```
|
|
10663
|
+
*/
|
|
10664
|
+
function registerTelemetryHandler$1(dispatcher, sdkName, sdkVersion, actionEventMap, mapEventToPayload) {
|
|
10665
|
+
for (const actionName of Object.keys(actionEventMap)) {
|
|
10666
|
+
dispatcher.on(actionName, (payload) => {
|
|
10667
|
+
try {
|
|
10668
|
+
const log = mapEventToPayload(actionName, payload, sdkName, sdkVersion);
|
|
10669
|
+
if (log) {
|
|
10670
|
+
// Fire-and-forget — intentionally not awaited.
|
|
10671
|
+
void emitAnalyticsLog(log);
|
|
10672
|
+
}
|
|
10673
|
+
}
|
|
10674
|
+
catch {
|
|
10675
|
+
// Silently swallow — telemetry must never break user operations.
|
|
10676
|
+
}
|
|
10677
|
+
});
|
|
10678
|
+
}
|
|
10679
|
+
}
|
|
10680
|
+
|
|
10681
|
+
/**
|
|
10682
|
+
* Strip the `@circle-fin/` scope from a kit package name to produce the
|
|
10683
|
+
* short SDK name used in telemetry payloads.
|
|
10684
|
+
*
|
|
10685
|
+
* @param pkgName - The full npm package name (e.g. `@circle-fin/bridge-kit`).
|
|
10686
|
+
* @returns The unscoped kit name (e.g. `bridge-kit`).
|
|
10687
|
+
*
|
|
10688
|
+
* @example
|
|
10689
|
+
* ```typescript
|
|
10690
|
+
* import pkg from '../../package.json'
|
|
10691
|
+
* import { resolveKitSdkName } from '@core/utils'
|
|
10692
|
+
*
|
|
10693
|
+
* const SDK_NAME = resolveKitSdkName(pkg.name) // 'bridge-kit'
|
|
10694
|
+
* ```
|
|
10695
|
+
*/
|
|
10696
|
+
function resolveKitSdkName(pkgName) {
|
|
10697
|
+
return pkgName.replace('@circle-fin/', '');
|
|
10698
|
+
}
|
|
10699
|
+
|
|
10700
|
+
/**
|
|
10701
|
+
* Build a telemetry payload from common fields.
|
|
10702
|
+
*
|
|
10703
|
+
* @internal
|
|
10704
|
+
*/
|
|
10705
|
+
function buildPayload$1(config, eventType, errorDetails, context) {
|
|
10706
|
+
return {
|
|
10707
|
+
sdkName: config.sdkName,
|
|
10708
|
+
sdkVersion: config.sdkVersion,
|
|
10709
|
+
eventType,
|
|
10710
|
+
timestamp: new Date().toISOString(),
|
|
10711
|
+
errorDetails,
|
|
10712
|
+
clientContext: buildClientContext(),
|
|
10713
|
+
...(context?.sourceChain != null && {
|
|
10714
|
+
sourceChain: context.sourceChain,
|
|
10715
|
+
}),
|
|
10716
|
+
...(context?.destinationChain != null && {
|
|
10717
|
+
destinationChain: context.destinationChain,
|
|
10718
|
+
}),
|
|
10719
|
+
...(context?.tokenIn != null && { tokenIn: context.tokenIn }),
|
|
10720
|
+
...(context?.tokenOut != null && { tokenOut: context.tokenOut }),
|
|
10721
|
+
};
|
|
10722
|
+
}
|
|
10723
|
+
/**
|
|
10724
|
+
* Wrap an async operation with error telemetry.
|
|
10725
|
+
*
|
|
10726
|
+
* Execute `fn` and, if it throws, emit an error telemetry payload
|
|
10727
|
+
* before re-throwing. No-ops when `config.disabled` is `true`.
|
|
10728
|
+
*
|
|
10729
|
+
* @param fn - The async operation to execute.
|
|
10730
|
+
* @param eventType - The telemetry event type for this operation.
|
|
10731
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
10732
|
+
* @param context - Optional chain/token context.
|
|
10733
|
+
* @returns The result of the operation.
|
|
10734
|
+
* @throws Re-throws any error after emitting telemetry.
|
|
10735
|
+
*
|
|
10736
|
+
* @example
|
|
10737
|
+
* ```typescript
|
|
10738
|
+
* import { withErrorTelemetry } from '@core/utils'
|
|
10739
|
+
*
|
|
10740
|
+
* const result = await withErrorTelemetry(
|
|
10741
|
+
* () => provider.bridge(params),
|
|
10742
|
+
* 'bridge_bridge',
|
|
10743
|
+
* { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
|
|
10744
|
+
* { sourceChain: 'Ethereum', destinationChain: 'Base', tokenIn: 'USDC' },
|
|
10745
|
+
* )
|
|
10746
|
+
* ```
|
|
10747
|
+
*/
|
|
10748
|
+
async function withErrorTelemetry(fn, eventType, config, context) {
|
|
10749
|
+
try {
|
|
10750
|
+
return await fn();
|
|
10751
|
+
}
|
|
10752
|
+
catch (error) {
|
|
10753
|
+
if (!config.disabled) {
|
|
10754
|
+
void emitAnalyticsLog(buildPayload$1(config, eventType, extractErrorDetails(error), context));
|
|
10755
|
+
}
|
|
10756
|
+
throw error;
|
|
10757
|
+
}
|
|
10758
|
+
}
|
|
10759
|
+
/**
|
|
10760
|
+
* Emit error telemetry for a result-reported step error.
|
|
10761
|
+
*
|
|
10762
|
+
* Handle the case where a provider reports a step failure inside a
|
|
10763
|
+
* result object (e.g. `BridgeResult.state === 'error'`) rather than
|
|
10764
|
+
* throwing. The caller extracts the failed step as a simple
|
|
10765
|
+
* {@link FailedStepInfo} — this function handles sanitization,
|
|
10766
|
+
* step-to-event mapping, and emission.
|
|
10767
|
+
*
|
|
10768
|
+
* No-ops when `config.disabled` is `true`.
|
|
10769
|
+
*
|
|
10770
|
+
* @param failedStep - The failed step info, or undefined if none found.
|
|
10771
|
+
* @param stepEventMap - Ordered mapping from step names to event types.
|
|
10772
|
+
* @param fallbackEventType - Event type when step is not in the map.
|
|
10773
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
10774
|
+
* @param context - Optional chain/token context.
|
|
10775
|
+
*
|
|
10776
|
+
* @example
|
|
10777
|
+
* ```typescript
|
|
10778
|
+
* import { emitResultStepErrorTelemetry } from '@core/utils'
|
|
10779
|
+
*
|
|
10780
|
+
* const failedStep = result.steps.find((s) => s.state === 'error')
|
|
10781
|
+
* emitResultStepErrorTelemetry(
|
|
10782
|
+
* failedStep,
|
|
10783
|
+
* BRIDGE_STEP_EVENT_MAP,
|
|
10784
|
+
* 'bridge_bridge',
|
|
10785
|
+
* { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
|
|
10786
|
+
* { sourceChain: 'Ethereum', tokenIn: 'USDC' },
|
|
10787
|
+
* )
|
|
10788
|
+
* ```
|
|
10789
|
+
*/
|
|
10790
|
+
function emitResultStepErrorTelemetry(failedStep, stepEventMap, fallbackEventType, config, context) {
|
|
10791
|
+
if (config.disabled) {
|
|
10792
|
+
return;
|
|
10793
|
+
}
|
|
10794
|
+
const stepEntry = stepEventMap.find(([name]) => name === failedStep?.name);
|
|
10795
|
+
const errorDetails = {
|
|
10796
|
+
...(failedStep?.name != null && { errorType: failedStep.name }),
|
|
10797
|
+
};
|
|
10798
|
+
void emitAnalyticsLog(buildPayload$1(config, stepEntry?.[1] ?? fallbackEventType, errorDetails, context));
|
|
10799
|
+
}
|
|
10800
|
+
|
|
10346
10801
|
var name$2 = "@circle-fin/bridge-kit";
|
|
10347
|
-
var version$3 = "1.
|
|
10802
|
+
var version$3 = "1.10.0";
|
|
10348
10803
|
var pkg$3 = {
|
|
10349
10804
|
name: name$2,
|
|
10350
10805
|
version: version$3};
|
|
@@ -13309,18 +13764,16 @@ const buildIrisUrl = (sourceDomainId, transactionHash, isTestnet) => {
|
|
|
13309
13764
|
};
|
|
13310
13765
|
/**
|
|
13311
13766
|
* Fetches attestation data from the IRIS API with retry and timeout handling.
|
|
13312
|
-
* Since fetching starts after a confirmed burn transaction, we attempt up to 10 retries.
|
|
13313
|
-
* Implements a conservative delay between requests to respect the API rate
|
|
13314
|
-
* limit of 35 requests per second. To avoid rate limiting when multiple processes are
|
|
13315
|
-
* running concurrently, we enforce a 200ms delay between retries.
|
|
13316
13767
|
*
|
|
13317
|
-
*
|
|
13318
|
-
*
|
|
13768
|
+
* Polls the IRIS API until a complete attestation is available. The default
|
|
13769
|
+
* window is sized for slow source chains where finality may take many
|
|
13770
|
+
* confirmations.
|
|
13319
13771
|
*
|
|
13320
|
-
*
|
|
13321
|
-
* - Per
|
|
13322
|
-
* - Retry
|
|
13323
|
-
* -
|
|
13772
|
+
* Defaults (see `DEFAULT_CONFIG`):
|
|
13773
|
+
* - Per-attempt timeout: 2 000 ms (each HTTP request aborts after 2 s)
|
|
13774
|
+
* - Retry delay: 2 000 ms between attempts
|
|
13775
|
+
* - Max retries: 600 (30 × 20)
|
|
13776
|
+
* - Total worst-case polling window: 600 × (2 000 ms + 2 000 ms) ≈ 40 minutes
|
|
13324
13777
|
*
|
|
13325
13778
|
* @param sourceDomainId - The CCTP domain ID.
|
|
13326
13779
|
* @param transactionHash - The transaction hash to fetch attestation for.
|
|
@@ -15297,7 +15750,7 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain, statusCo
|
|
|
15297
15750
|
return step;
|
|
15298
15751
|
}
|
|
15299
15752
|
|
|
15300
|
-
var version$2 = "1.
|
|
15753
|
+
var version$2 = "1.8.1";
|
|
15301
15754
|
var pkg$2 = {
|
|
15302
15755
|
version: version$2};
|
|
15303
15756
|
|
|
@@ -16963,6 +17416,35 @@ const formatBridgeResult = (result, formatDirection) => {
|
|
|
16963
17416
|
};
|
|
16964
17417
|
};
|
|
16965
17418
|
|
|
17419
|
+
/**
|
|
17420
|
+
* Telemetry event type identifiers for bridge-kit operations.
|
|
17421
|
+
*
|
|
17422
|
+
* @internal
|
|
17423
|
+
*/
|
|
17424
|
+
const BRIDGE_EVENT_TYPES = {
|
|
17425
|
+
BRIDGE: 'bridge_bridge',
|
|
17426
|
+
RETRY: 'bridge_retry',
|
|
17427
|
+
ESTIMATE: 'bridge_estimate',
|
|
17428
|
+
};
|
|
17429
|
+
/**
|
|
17430
|
+
* Ordered mapping from provider step event names to telemetry event types.
|
|
17431
|
+
*
|
|
17432
|
+
* @remarks
|
|
17433
|
+
* The order matches the CCTP v2 bridge execution sequence. During
|
|
17434
|
+
* `bridge()`, completed step events are counted so the failing step
|
|
17435
|
+
* can be identified by its index.
|
|
17436
|
+
*
|
|
17437
|
+
* @internal
|
|
17438
|
+
*/
|
|
17439
|
+
const BRIDGE_STEP_EVENT_MAP = [
|
|
17440
|
+
['approve', 'bridge_approve'],
|
|
17441
|
+
['burn', 'bridge_burn'],
|
|
17442
|
+
['fetchAttestation', 'bridge_fetch_attestation'],
|
|
17443
|
+
['mint', 'bridge_mint'],
|
|
17444
|
+
];
|
|
17445
|
+
|
|
17446
|
+
/** SDK name used in telemetry payloads. */
|
|
17447
|
+
const SDK_NAME$2 = resolveKitSdkName(pkg$3.name);
|
|
16966
17448
|
/**
|
|
16967
17449
|
* BridgeKit caller component for retry and estimate operations.
|
|
16968
17450
|
*/
|
|
@@ -17046,6 +17528,10 @@ class BridgeKit {
|
|
|
17046
17528
|
* A custom fee policy for the kit.
|
|
17047
17529
|
*/
|
|
17048
17530
|
customFeePolicy;
|
|
17531
|
+
/** Whether error telemetry is disabled. */
|
|
17532
|
+
disableErrorReporting;
|
|
17533
|
+
/** Per-kit telemetry identity for shared helpers. */
|
|
17534
|
+
telemetryConfig;
|
|
17049
17535
|
/**
|
|
17050
17536
|
* Create a new BridgeKit instance.
|
|
17051
17537
|
*
|
|
@@ -17063,6 +17549,12 @@ class BridgeKit {
|
|
|
17063
17549
|
const defaultProviders = getDefaultProviders$2();
|
|
17064
17550
|
this.providers = [...defaultProviders, ...(config.providers ?? [])];
|
|
17065
17551
|
this.actionDispatcher = new Actionable();
|
|
17552
|
+
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
17553
|
+
this.telemetryConfig = {
|
|
17554
|
+
sdkName: SDK_NAME$2,
|
|
17555
|
+
sdkVersion: pkg$3.version,
|
|
17556
|
+
disabled: this.disableErrorReporting,
|
|
17557
|
+
};
|
|
17066
17558
|
for (const provider of this.providers) {
|
|
17067
17559
|
provider.registerDispatcher(this.actionDispatcher);
|
|
17068
17560
|
}
|
|
@@ -17136,19 +17628,36 @@ class BridgeKit {
|
|
|
17136
17628
|
* ```
|
|
17137
17629
|
*/
|
|
17138
17630
|
async bridge(params) {
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
|
|
17631
|
+
return withErrorTelemetry(async () => {
|
|
17632
|
+
// First validate the parameters
|
|
17633
|
+
assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
|
|
17634
|
+
// Then resolve chain definitions (includes adapter chain support validation)
|
|
17635
|
+
const resolvedParams = await resolveBridgeParams(params);
|
|
17636
|
+
// Validate network compatibility
|
|
17637
|
+
this.validateNetworkCompatibility(resolvedParams);
|
|
17638
|
+
// Merge the custom fee config into the resolved params
|
|
17639
|
+
const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
|
|
17640
|
+
// Find a provider that supports this route
|
|
17641
|
+
const provider = this.findProviderForRoute(finalResolvedParams);
|
|
17642
|
+
// Execute the transfer using the provider
|
|
17643
|
+
// Format the bridge result into human-readable string values for the user
|
|
17644
|
+
const result = formatBridgeResult(await provider.bridge(finalResolvedParams), 'to-human-readable');
|
|
17645
|
+
// Emit error telemetry when the provider returns an error state
|
|
17646
|
+
// (provider records step failures in the result instead of throwing).
|
|
17647
|
+
if (result.state === 'error') {
|
|
17648
|
+
const failedStep = result.steps.find((s) => s.state === 'error');
|
|
17649
|
+
emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
|
|
17650
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
17651
|
+
destinationChain: resolveChainName(params.to.chain),
|
|
17652
|
+
tokenIn: params.token,
|
|
17653
|
+
});
|
|
17654
|
+
}
|
|
17655
|
+
return result;
|
|
17656
|
+
}, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
|
|
17657
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
17658
|
+
destinationChain: resolveChainName(params.to.chain),
|
|
17659
|
+
tokenIn: params.token,
|
|
17660
|
+
});
|
|
17152
17661
|
}
|
|
17153
17662
|
/**
|
|
17154
17663
|
* Retry a failed or incomplete cross-chain USDC bridge operation.
|
|
@@ -17220,17 +17729,33 @@ class BridgeKit {
|
|
|
17220
17729
|
* ```
|
|
17221
17730
|
*/
|
|
17222
17731
|
async retry(result, context, invocationMeta) {
|
|
17223
|
-
|
|
17224
|
-
|
|
17225
|
-
|
|
17226
|
-
|
|
17227
|
-
|
|
17228
|
-
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
|
|
17732
|
+
return withErrorTelemetry(async () => {
|
|
17733
|
+
const provider = this.providers.find((p) => p.name === result.provider);
|
|
17734
|
+
if (!provider) {
|
|
17735
|
+
throw new Error(`Provider ${result.provider} not found`);
|
|
17736
|
+
}
|
|
17737
|
+
// Merge BridgeKit caller into invocation metadata for retry operation
|
|
17738
|
+
const mergedMeta = mergeRetryInvocationMeta(invocationMeta);
|
|
17739
|
+
// Format the bridge result into bigint string values for internal use
|
|
17740
|
+
const formattedBridgeResultInternal = formatBridgeResult(result, 'to-internal');
|
|
17741
|
+
// Execute the retry using the provider
|
|
17742
|
+
// Format the bridge result into human-readable string values for the user
|
|
17743
|
+
const retryResult = formatBridgeResult(await provider.retry(formattedBridgeResultInternal, context, mergedMeta), 'to-human-readable');
|
|
17744
|
+
// Emit error telemetry when the provider returns an error state.
|
|
17745
|
+
if (retryResult.state === 'error') {
|
|
17746
|
+
const failedStep = retryResult.steps.find((s) => s.state === 'error');
|
|
17747
|
+
emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
|
|
17748
|
+
sourceChain: result.source.chain.chain,
|
|
17749
|
+
destinationChain: result.destination.chain.chain,
|
|
17750
|
+
tokenIn: result.token,
|
|
17751
|
+
});
|
|
17752
|
+
}
|
|
17753
|
+
return retryResult;
|
|
17754
|
+
}, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
|
|
17755
|
+
sourceChain: result.source.chain.chain,
|
|
17756
|
+
destinationChain: result.destination.chain.chain,
|
|
17757
|
+
tokenIn: result.token,
|
|
17758
|
+
});
|
|
17234
17759
|
}
|
|
17235
17760
|
/**
|
|
17236
17761
|
* Estimate the cost and fees for a cross-chain USDC bridge operation.
|
|
@@ -17269,18 +17794,24 @@ class BridgeKit {
|
|
|
17269
17794
|
* ```
|
|
17270
17795
|
*/
|
|
17271
17796
|
async estimate(params) {
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17279
|
-
|
|
17280
|
-
|
|
17281
|
-
|
|
17282
|
-
|
|
17283
|
-
|
|
17797
|
+
return withErrorTelemetry(async () => {
|
|
17798
|
+
// First validate the parameters
|
|
17799
|
+
assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
|
|
17800
|
+
// Then resolve chain definitions (includes adapter chain support validation)
|
|
17801
|
+
const resolvedParams = await resolveBridgeParams(params);
|
|
17802
|
+
// Validate network compatibility
|
|
17803
|
+
this.validateNetworkCompatibility(resolvedParams);
|
|
17804
|
+
// Merge the custom fee config into the resolved params
|
|
17805
|
+
const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
|
|
17806
|
+
// Find a provider that supports this route
|
|
17807
|
+
const provider = this.findProviderForRoute(finalResolvedParams);
|
|
17808
|
+
// Estimate the transfer using the provider and format amounts to human-readable strings
|
|
17809
|
+
return formatBridgeResult(await provider.estimate(finalResolvedParams), 'to-human-readable');
|
|
17810
|
+
}, BRIDGE_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
|
|
17811
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
17812
|
+
destinationChain: resolveChainName(params.to.chain),
|
|
17813
|
+
tokenIn: params.token,
|
|
17814
|
+
});
|
|
17284
17815
|
}
|
|
17285
17816
|
/**
|
|
17286
17817
|
* Get all chains supported by any provider in the kit, with optional filtering.
|
|
@@ -17597,7 +18128,11 @@ const createBridgeKit = (context) => {
|
|
|
17597
18128
|
const getFee = context.getFee?.bind(context);
|
|
17598
18129
|
const getFeeRecipient = context.getFeeRecipient?.bind(context);
|
|
17599
18130
|
const hasBoth = typeof getFee === 'function' && typeof getFeeRecipient === 'function';
|
|
17600
|
-
const kit = new BridgeKit(
|
|
18131
|
+
const kit = new BridgeKit({
|
|
18132
|
+
...(context.disableErrorReporting != null && {
|
|
18133
|
+
disableErrorReporting: context.disableErrorReporting,
|
|
18134
|
+
}),
|
|
18135
|
+
});
|
|
17601
18136
|
if (hasBoth) {
|
|
17602
18137
|
kit.setCustomFeePolicy({
|
|
17603
18138
|
calculateFee: async (params) => {
|
|
@@ -17614,7 +18149,7 @@ const createBridgeKit = (context) => {
|
|
|
17614
18149
|
};
|
|
17615
18150
|
|
|
17616
18151
|
var name$1 = "@circle-fin/swap-kit";
|
|
17617
|
-
var version$1 = "1.
|
|
18152
|
+
var version$1 = "1.2.1";
|
|
17618
18153
|
var pkg$1 = {
|
|
17619
18154
|
name: name$1,
|
|
17620
18155
|
version: version$1};
|
|
@@ -21494,6 +22029,119 @@ function evmSigningData(burnIntent) {
|
|
|
21494
22029
|
};
|
|
21495
22030
|
}
|
|
21496
22031
|
|
|
22032
|
+
/**
|
|
22033
|
+
* EIP-7702 delegation indicator. A 7702-delegated EOA's bytecode is
|
|
22034
|
+
* `0xef0100` followed by the 20-byte delegate address (23 bytes total).
|
|
22035
|
+
* The underlying secp256k1 key still produces `ecrecover`-verifiable
|
|
22036
|
+
* signatures, so for Gateway's purposes a 7702-delegated address is
|
|
22037
|
+
* an EOA, not an SCA.
|
|
22038
|
+
*
|
|
22039
|
+
* Spec: https://eips.ethereum.org/EIPS/eip-7702
|
|
22040
|
+
*/
|
|
22041
|
+
const EIP_7702_DELEGATION_PREFIX = '0xef0100';
|
|
22042
|
+
/**
|
|
22043
|
+
* Assert that `address` on `chain` can sign Gateway burn intents.
|
|
22044
|
+
*
|
|
22045
|
+
* Gateway verifies burn-intent signatures with plain `ecrecover` (see
|
|
22046
|
+
* `evm-gateway-contracts/src/lib/EIP712Domain.sol`). Smart-contract
|
|
22047
|
+
* accounts (SCAs) produce signatures over wrapped hashes (ERC-1271 /
|
|
22048
|
+
* ERC-6492 / ERC-6900 replay-safe hashes) that Gateway cannot verify.
|
|
22049
|
+
* Additionally, the Circle Wallets backend rejects SCA typed-data signing
|
|
22050
|
+
* against Gateway's chainId-less domain with an opaque
|
|
22051
|
+
* `invalid integer value <nil>/<nil> for type uint256` error.
|
|
22052
|
+
*
|
|
22053
|
+
* EIP-7702-delegated EOAs are exempt: they expose non-empty bytecode
|
|
22054
|
+
* (`0xef0100<delegate>`) but the underlying secp256k1 key still produces
|
|
22055
|
+
* `ecrecover`-verifiable signatures, so Gateway accepts them.
|
|
22056
|
+
*
|
|
22057
|
+
* When the signer is a true SCA, raises an `INPUT_UNSUPPORTED_ACTION`
|
|
22058
|
+
* error directing the caller to register an EOA delegate against the
|
|
22059
|
+
* SCA and then submit the spend with the delegate EOA as the signer
|
|
22060
|
+
* and the SCA as the source account. See the unified-balance / Gateway
|
|
22061
|
+
* docs for the exact API.
|
|
22062
|
+
*
|
|
22063
|
+
* If bytecode cannot be read (RPC failure, etc.) the pre-check is
|
|
22064
|
+
* skipped and downstream signing surfaces its own error — a warning is
|
|
22065
|
+
* logged so the skip is diagnosable.
|
|
22066
|
+
*
|
|
22067
|
+
* @param adapter - Anything exposing {@link EvmAdapterLike.readBytecode}.
|
|
22068
|
+
* @param address - Signer address to validate.
|
|
22069
|
+
* @param chain - EVM chain where the signer lives.
|
|
22070
|
+
* @throws {KitError} INPUT_UNSUPPORTED_ACTION when `address` is an SCA.
|
|
22071
|
+
*
|
|
22072
|
+
* @example
|
|
22073
|
+
* ```typescript
|
|
22074
|
+
* import { assertSignerIsEoa } from '@core/adapter-evm'
|
|
22075
|
+
* import { Ethereum } from '@core/chains'
|
|
22076
|
+
*
|
|
22077
|
+
* await assertSignerIsEoa(adapter, '0xabc...', Ethereum)
|
|
22078
|
+
* ```
|
|
22079
|
+
*/
|
|
22080
|
+
async function assertSignerIsEoa(adapter, address, chain) {
|
|
22081
|
+
let code;
|
|
22082
|
+
try {
|
|
22083
|
+
code = await adapter.readBytecode(address, chain);
|
|
22084
|
+
}
|
|
22085
|
+
catch (err) {
|
|
22086
|
+
console.warn(`[gateway] assertSignerIsEoa skipped (readBytecode failed for ` +
|
|
22087
|
+
`${address} on ${chain.name}): ` +
|
|
22088
|
+
(err instanceof Error ? err.message : String(err)));
|
|
22089
|
+
return;
|
|
22090
|
+
}
|
|
22091
|
+
if (code === undefined ||
|
|
22092
|
+
code === '0x' ||
|
|
22093
|
+
code.toLowerCase().startsWith(EIP_7702_DELEGATION_PREFIX)) {
|
|
22094
|
+
return;
|
|
22095
|
+
}
|
|
22096
|
+
throw new KitError({
|
|
22097
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
22098
|
+
recoverability: 'FATAL',
|
|
22099
|
+
message: `Gateway burn-intent signing requires an EOA signer (Gateway ` +
|
|
22100
|
+
`verifies signatures with ecrecover and does not support ERC-1271). ` +
|
|
22101
|
+
`The signer ${address} on ${chain.name} has on-chain bytecode, ` +
|
|
22102
|
+
`indicating it is a smart-contract account (SCA). Register an EOA ` +
|
|
22103
|
+
`delegate against the SCA, then submit the spend with the delegate ` +
|
|
22104
|
+
`EOA as the signer and the SCA as the source account. See DEVX-2774.`,
|
|
22105
|
+
cause: {
|
|
22106
|
+
trace: {
|
|
22107
|
+
operation: 'signEvmIntentGroup.assertSignerIsEoa',
|
|
22108
|
+
address,
|
|
22109
|
+
chain: chain.name,
|
|
22110
|
+
bytecodeBytes: (code.length - 2) / 2,
|
|
22111
|
+
bytecodePrefix: code.slice(0, 12),
|
|
22112
|
+
},
|
|
22113
|
+
},
|
|
22114
|
+
});
|
|
22115
|
+
}
|
|
22116
|
+
|
|
22117
|
+
/**
|
|
22118
|
+
* Duck-type test for an EVM adapter that exposes `readBytecode`.
|
|
22119
|
+
*
|
|
22120
|
+
* Used as a structural guard at package boundaries (e.g. the Circle Wallets
|
|
22121
|
+
* hybrid adapter calling into a chain adapter, or the Gateway sign path
|
|
22122
|
+
* receiving an arbitrary adapter implementation) where `instanceof EvmAdapter`
|
|
22123
|
+
* is unreliable because each consumer bundles its own copy of the base class.
|
|
22124
|
+
*
|
|
22125
|
+
* @param value - The value to test.
|
|
22126
|
+
* @returns `true` when `value` is an object exposing a callable
|
|
22127
|
+
* `readBytecode` method, narrowed to {@link EvmAdapterLike}.
|
|
22128
|
+
*
|
|
22129
|
+
* @example
|
|
22130
|
+
* ```typescript
|
|
22131
|
+
* import { isEvmAdapterLike } from '@core/adapter-evm'
|
|
22132
|
+
*
|
|
22133
|
+
* if (isEvmAdapterLike(adapter)) {
|
|
22134
|
+
* const code = await adapter.readBytecode('0xabc...', chain)
|
|
22135
|
+
* }
|
|
22136
|
+
* ```
|
|
22137
|
+
*/
|
|
22138
|
+
function isEvmAdapterLike(value) {
|
|
22139
|
+
return (typeof value === 'object' &&
|
|
22140
|
+
value !== null &&
|
|
22141
|
+
'readBytecode' in value &&
|
|
22142
|
+
typeof value.readBytecode === 'function');
|
|
22143
|
+
}
|
|
22144
|
+
|
|
21497
22145
|
/**
|
|
21498
22146
|
* Sign an EVM adapter group: batches all intents and produces a single
|
|
21499
22147
|
* EIP-712 ECDSA signature.
|
|
@@ -21501,6 +22149,12 @@ function evmSigningData(burnIntent) {
|
|
|
21501
22149
|
* For a single-intent group, `primaryType` is `'BurnIntent'`.
|
|
21502
22150
|
* For multi-intent groups, `primaryType` is `'BurnIntentSet'`.
|
|
21503
22151
|
*
|
|
22152
|
+
* Before signing, asserts that the signer address is an EOA. Gateway
|
|
22153
|
+
* verifies burn-intent signatures with plain `ecrecover` (no ERC-1271
|
|
22154
|
+
* fallback), so signatures produced by smart-contract accounts (SCAs)
|
|
22155
|
+
* cannot be verified. When an SCA is detected, a clear error is raised
|
|
22156
|
+
* directing the caller to the delegate workflow (DEVX-2774).
|
|
22157
|
+
*
|
|
21504
22158
|
* @param group - The adapter group containing the adapter, chain, and
|
|
21505
22159
|
* burn intents to sign.
|
|
21506
22160
|
* @returns A signed set with the intents and the ECDSA signature.
|
|
@@ -21521,6 +22175,22 @@ function evmSigningData(burnIntent) {
|
|
|
21521
22175
|
async function signEvmIntentGroup(group) {
|
|
21522
22176
|
const { adapter, intents: groupIntents, chain, address } = group;
|
|
21523
22177
|
const operationContext = address === undefined ? { chain } : { chain, address };
|
|
22178
|
+
// Gateway verifies burn-intent signatures with plain ecrecover. An SCA
|
|
22179
|
+
// signer silently produces a signature over a wrapped hash that Gateway
|
|
22180
|
+
// cannot verify, and Circle Wallets' KMS rejects the typed data up front
|
|
22181
|
+
// with an opaque `<nil>/<nil>` error. Short-circuit with a clear message
|
|
22182
|
+
// when we can detect bytecode at the signer address. See DEVX-2774.
|
|
22183
|
+
//
|
|
22184
|
+
// Duck-typed on readBytecode rather than `instanceof EvmAdapter` because
|
|
22185
|
+
// each consumer package bundles its own copy of the base class and the
|
|
22186
|
+
// `instanceof` identity check fails across package boundaries.
|
|
22187
|
+
//
|
|
22188
|
+
// Empty string is defended against because assertSignerIsEoa would
|
|
22189
|
+
// otherwise call eth_getCode('') on the RPC.
|
|
22190
|
+
const hasResolvedSigner = typeof address === 'string' && address.length > 0;
|
|
22191
|
+
if (hasResolvedSigner && chain.type === 'evm' && isEvmAdapterLike(adapter)) {
|
|
22192
|
+
await assertSignerIsEoa(adapter, address, chain);
|
|
22193
|
+
}
|
|
21524
22194
|
const firstIntent = groupIntents[0];
|
|
21525
22195
|
const typedData = groupIntents.length === 1 && firstIntent
|
|
21526
22196
|
? evmSigningData(firstIntent)
|
|
@@ -21790,9 +22460,10 @@ function getSolanaFeeRecipient() {
|
|
|
21790
22460
|
return CIRCLE_FEE_RECIPIENT_SOLANA;
|
|
21791
22461
|
}
|
|
21792
22462
|
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
|
|
22463
|
+
const enc = new TextEncoder();
|
|
22464
|
+
enc.encode('gateway_minter');
|
|
22465
|
+
enc.encode('gateway_minter_custody');
|
|
22466
|
+
enc.encode('used_transfer_spec_hash');
|
|
21796
22467
|
|
|
21797
22468
|
async function executeAndWait$1(adapter, request, chain) {
|
|
21798
22469
|
if (request.type === 'noop') {
|
|
@@ -28075,6 +28746,18 @@ function createSwapKitContext(config = {}) {
|
|
|
28075
28746
|
return context;
|
|
28076
28747
|
}
|
|
28077
28748
|
|
|
28749
|
+
/**
|
|
28750
|
+
* Telemetry event type identifiers for swap-kit operations.
|
|
28751
|
+
*
|
|
28752
|
+
* @internal
|
|
28753
|
+
*/
|
|
28754
|
+
const SWAP_EVENT_TYPES = {
|
|
28755
|
+
SWAP: 'swap_swap',
|
|
28756
|
+
ESTIMATE: 'swap_estimate',
|
|
28757
|
+
};
|
|
28758
|
+
|
|
28759
|
+
/** SDK name used in telemetry payloads. */
|
|
28760
|
+
const SDK_NAME$1 = resolveKitSdkName(pkg$1.name);
|
|
28078
28761
|
/**
|
|
28079
28762
|
* A high-level class-based interface for single-chain token swap operations.
|
|
28080
28763
|
*
|
|
@@ -28146,6 +28829,10 @@ function createSwapKitContext(config = {}) {
|
|
|
28146
28829
|
*/
|
|
28147
28830
|
class SwapKit {
|
|
28148
28831
|
context;
|
|
28832
|
+
/** Whether error telemetry is disabled. */
|
|
28833
|
+
disableErrorReporting;
|
|
28834
|
+
/** Per-kit telemetry identity for shared helpers. */
|
|
28835
|
+
telemetryConfig;
|
|
28149
28836
|
/**
|
|
28150
28837
|
* Create a new SwapKit instance.
|
|
28151
28838
|
*
|
|
@@ -28194,6 +28881,12 @@ class SwapKit {
|
|
|
28194
28881
|
*/
|
|
28195
28882
|
constructor(config = {}) {
|
|
28196
28883
|
this.context = createSwapKitContext(config);
|
|
28884
|
+
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
28885
|
+
this.telemetryConfig = {
|
|
28886
|
+
sdkName: SDK_NAME$1,
|
|
28887
|
+
sdkVersion: pkg$1.version,
|
|
28888
|
+
disabled: this.disableErrorReporting,
|
|
28889
|
+
};
|
|
28197
28890
|
}
|
|
28198
28891
|
/**
|
|
28199
28892
|
* Estimate the output amount and fees for a swap operation.
|
|
@@ -28235,7 +28928,11 @@ class SwapKit {
|
|
|
28235
28928
|
* ```
|
|
28236
28929
|
*/
|
|
28237
28930
|
async estimate(params) {
|
|
28238
|
-
return estimate(this.context, params)
|
|
28931
|
+
return withErrorTelemetry(async () => estimate(this.context, params), SWAP_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
|
|
28932
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
28933
|
+
tokenIn: params.tokenIn,
|
|
28934
|
+
tokenOut: params.tokenOut,
|
|
28935
|
+
});
|
|
28239
28936
|
}
|
|
28240
28937
|
/**
|
|
28241
28938
|
* Execute a token swap operation on a single chain.
|
|
@@ -28291,7 +28988,11 @@ class SwapKit {
|
|
|
28291
28988
|
* ```
|
|
28292
28989
|
*/
|
|
28293
28990
|
async swap(params) {
|
|
28294
|
-
return swap$1(this.context, params)
|
|
28991
|
+
return withErrorTelemetry(async () => swap$1(this.context, params), SWAP_EVENT_TYPES.SWAP, this.telemetryConfig, {
|
|
28992
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
28993
|
+
tokenIn: params.tokenIn,
|
|
28994
|
+
tokenOut: params.tokenOut,
|
|
28995
|
+
});
|
|
28295
28996
|
}
|
|
28296
28997
|
/**
|
|
28297
28998
|
* Get all chains supported by the configured swap providers.
|
|
@@ -28484,7 +29185,11 @@ const createSwapKit = (context) => {
|
|
|
28484
29185
|
const getFee = context.getFee?.bind(context);
|
|
28485
29186
|
const getFeeRecipient = context.getFeeRecipient?.bind(context);
|
|
28486
29187
|
const hasBoth = typeof getFee === 'function' && typeof getFeeRecipient === 'function';
|
|
28487
|
-
const kit = new SwapKit(
|
|
29188
|
+
const kit = new SwapKit({
|
|
29189
|
+
...(context.disableErrorReporting != null && {
|
|
29190
|
+
disableErrorReporting: context.disableErrorReporting,
|
|
29191
|
+
}),
|
|
29192
|
+
});
|
|
28488
29193
|
if (hasBoth) {
|
|
28489
29194
|
kit.setCustomFeePolicy({
|
|
28490
29195
|
computeFee: async (params) => {
|
|
@@ -29433,121 +30138,11 @@ const getSupportedChains$2 = (context, operationType, unifiedBalance) => {
|
|
|
29433
30138
|
};
|
|
29434
30139
|
|
|
29435
30140
|
var name = "@circle-fin/unified-balance-kit";
|
|
29436
|
-
var version = "1.
|
|
30141
|
+
var version = "1.1.1";
|
|
29437
30142
|
var pkg = {
|
|
29438
30143
|
name: name,
|
|
29439
30144
|
version: version};
|
|
29440
30145
|
|
|
29441
|
-
/**
|
|
29442
|
-
* Default telemetry endpoint.
|
|
29443
|
-
*
|
|
29444
|
-
* Override via the `STABLECOIN_KITS_TELEMETRY_URL` environment variable
|
|
29445
|
-
* (e.g. for staging or local development).
|
|
29446
|
-
*
|
|
29447
|
-
* @internal
|
|
29448
|
-
*/
|
|
29449
|
-
const DEFAULT_LOGS_URL = 'https://api.circle.com/v1/stablecoinKits/logs';
|
|
29450
|
-
/**
|
|
29451
|
-
* Resolve the telemetry endpoint URL.
|
|
29452
|
-
*
|
|
29453
|
-
* @internal
|
|
29454
|
-
*/
|
|
29455
|
-
function getLogsUrl() {
|
|
29456
|
-
if (isNodeEnvironment() &&
|
|
29457
|
-
typeof process.env['STABLECOIN_KITS_TELEMETRY_URL'] === 'string' &&
|
|
29458
|
-
process.env['STABLECOIN_KITS_TELEMETRY_URL'].length > 0) {
|
|
29459
|
-
return process.env['STABLECOIN_KITS_TELEMETRY_URL'];
|
|
29460
|
-
}
|
|
29461
|
-
return DEFAULT_LOGS_URL;
|
|
29462
|
-
}
|
|
29463
|
-
/**
|
|
29464
|
-
* Send a telemetry event to the proxy service.
|
|
29465
|
-
*
|
|
29466
|
-
* @remarks
|
|
29467
|
-
* Fire-and-forget: the returned promise is intentionally not awaited
|
|
29468
|
-
* by the caller. A fetch failure (network error, non-2xx, timeout)
|
|
29469
|
-
* is silently swallowed so telemetry never blocks or fails user
|
|
29470
|
-
* operations.
|
|
29471
|
-
*
|
|
29472
|
-
* @param payload - The structured log payload matching the server schema.
|
|
29473
|
-
*
|
|
29474
|
-
* @example
|
|
29475
|
-
* ```typescript
|
|
29476
|
-
* import { emitAnalyticsLog } from './emitLog'
|
|
29477
|
-
*
|
|
29478
|
-
* // Fire-and-forget — do not await
|
|
29479
|
-
* emitAnalyticsLog(payload).catch(() => {})
|
|
29480
|
-
* ```
|
|
29481
|
-
*
|
|
29482
|
-
* @internal
|
|
29483
|
-
*/
|
|
29484
|
-
async function emitAnalyticsLog(payload) {
|
|
29485
|
-
try {
|
|
29486
|
-
const isNode = isNodeEnvironment();
|
|
29487
|
-
const userAgent = getUserAgent();
|
|
29488
|
-
await fetch(getLogsUrl(), {
|
|
29489
|
-
method: 'POST',
|
|
29490
|
-
headers: {
|
|
29491
|
-
'Content-Type': 'application/json',
|
|
29492
|
-
// Browser restricts setting User-Agent; use X-User-Agent instead.
|
|
29493
|
-
...(isNode
|
|
29494
|
-
? { 'User-Agent': userAgent }
|
|
29495
|
-
: { 'X-User-Agent': userAgent }),
|
|
29496
|
-
},
|
|
29497
|
-
body: JSON.stringify(payload),
|
|
29498
|
-
signal: AbortSignal.timeout(5_000),
|
|
29499
|
-
});
|
|
29500
|
-
}
|
|
29501
|
-
catch {
|
|
29502
|
-
// Silently swallow — telemetry must never break user operations.
|
|
29503
|
-
}
|
|
29504
|
-
}
|
|
29505
|
-
|
|
29506
|
-
/**
|
|
29507
|
-
* Build the `clientContext` object for telemetry payloads.
|
|
29508
|
-
*
|
|
29509
|
-
* @remarks
|
|
29510
|
-
* Uses the exported `getRuntime()` and `isNodeEnvironment()` from
|
|
29511
|
-
* `@core/utils` to detect the runtime environment (per Dominik's
|
|
29512
|
-
* feedback to reuse existing infrastructure). The returned string
|
|
29513
|
-
* is parsed into the structured `ClientContext` fields expected by
|
|
29514
|
-
* the server schema.
|
|
29515
|
-
*
|
|
29516
|
-
* @returns A {@link ClientContext} with platform, OS, and runtime name
|
|
29517
|
-
* populated from the current environment.
|
|
29518
|
-
*
|
|
29519
|
-
* @example
|
|
29520
|
-
* ```typescript
|
|
29521
|
-
* import { buildClientContext } from './clientContext'
|
|
29522
|
-
*
|
|
29523
|
-
* const ctx = buildClientContext()
|
|
29524
|
-
* // Node: { platform: 'node', os: 'darwin', runtimeName: null }
|
|
29525
|
-
* // Browser: { platform: 'browser', os: null, runtimeName: 'chrome' }
|
|
29526
|
-
* ```
|
|
29527
|
-
*/
|
|
29528
|
-
function buildClientContext() {
|
|
29529
|
-
const runtime = getRuntime();
|
|
29530
|
-
if (runtime.startsWith('browser/')) {
|
|
29531
|
-
return {
|
|
29532
|
-
platform: 'browser',
|
|
29533
|
-
os: null,
|
|
29534
|
-
runtimeName: runtime.slice('browser/'.length).toLowerCase(),
|
|
29535
|
-
};
|
|
29536
|
-
}
|
|
29537
|
-
if (runtime.startsWith('node/')) {
|
|
29538
|
-
return {
|
|
29539
|
-
platform: 'node',
|
|
29540
|
-
os: isNodeEnvironment() ? process.platform : null,
|
|
29541
|
-
runtimeName: null,
|
|
29542
|
-
};
|
|
29543
|
-
}
|
|
29544
|
-
return {
|
|
29545
|
-
platform: 'node',
|
|
29546
|
-
os: null,
|
|
29547
|
-
runtimeName: null,
|
|
29548
|
-
};
|
|
29549
|
-
}
|
|
29550
|
-
|
|
29551
30146
|
/**
|
|
29552
30147
|
* Event type identifiers accepted by the server-side logs endpoint.
|
|
29553
30148
|
*
|
|
@@ -29560,6 +30155,11 @@ const EVENT_TYPES = {
|
|
|
29560
30155
|
DEPOSIT_FOR: 'unified_balance_deposit_for',
|
|
29561
30156
|
SPEND: 'unified_balance_spend',
|
|
29562
30157
|
SPEND_FORWARDER: 'unified_balance_spend_forwarder',
|
|
30158
|
+
ESTIMATE_SPEND: 'unified_balance_estimate_spend',
|
|
30159
|
+
GET_BALANCES: 'unified_balance_get_balances',
|
|
30160
|
+
ADD_DELEGATE: 'unified_balance_add_delegate',
|
|
30161
|
+
REMOVE_DELEGATE: 'unified_balance_remove_delegate',
|
|
30162
|
+
GET_DELEGATE_STATUS: 'unified_balance_get_delegate_status',
|
|
29563
30163
|
INITIATE_REMOVE_FUND: 'unified_balance_initiate_remove_fund',
|
|
29564
30164
|
REMOVE_FUND: 'unified_balance_remove_fund',
|
|
29565
30165
|
};
|
|
@@ -29597,33 +30197,29 @@ function extractSingleChainResult(data) {
|
|
|
29597
30197
|
txHash: data.txHash,
|
|
29598
30198
|
};
|
|
29599
30199
|
}
|
|
29600
|
-
/**
|
|
29601
|
-
* Resolve a chain identifier that may be a string or a
|
|
29602
|
-
* `ChainDefinition` object to a plain string.
|
|
29603
|
-
*
|
|
29604
|
-
* @internal
|
|
29605
|
-
*/
|
|
29606
|
-
function resolveChainString(chain) {
|
|
29607
|
-
if (typeof chain === 'string')
|
|
29608
|
-
return chain;
|
|
29609
|
-
return chain.chain;
|
|
29610
|
-
}
|
|
29611
30200
|
/**
|
|
29612
30201
|
* Extract log-relevant fields from a spend result.
|
|
29613
30202
|
*
|
|
30203
|
+
* @remarks
|
|
30204
|
+
* Collects all source chains from allocations and joins them with
|
|
30205
|
+
* commas so multi-chain spends are fully represented.
|
|
30206
|
+
*
|
|
29614
30207
|
* @internal
|
|
29615
30208
|
*/
|
|
29616
30209
|
function extractSpend(data) {
|
|
29617
|
-
const
|
|
29618
|
-
|
|
29619
|
-
|
|
29620
|
-
|
|
30210
|
+
const allocs = data.allocations ?? [];
|
|
30211
|
+
const chains = [];
|
|
30212
|
+
for (const alloc of allocs) {
|
|
30213
|
+
const name = resolveChainName(alloc.chain);
|
|
30214
|
+
if (name != null) {
|
|
30215
|
+
chains.push(name);
|
|
30216
|
+
}
|
|
29621
30217
|
}
|
|
29622
|
-
const
|
|
30218
|
+
const sourceChain = chains.length > 0 ? chains.join(',') : undefined;
|
|
29623
30219
|
return {
|
|
29624
|
-
...(
|
|
30220
|
+
...(sourceChain != null && { sourceChain }),
|
|
29625
30221
|
destinationChain: data.destinationChain,
|
|
29626
|
-
...(
|
|
30222
|
+
...(allocs.length > 0 && { tokenIn: 'USDC' }),
|
|
29627
30223
|
txHash: data.txHash,
|
|
29628
30224
|
};
|
|
29629
30225
|
}
|
|
@@ -29722,10 +30318,9 @@ function mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion) {
|
|
|
29722
30318
|
* telemetry for successful verb operations.
|
|
29723
30319
|
*
|
|
29724
30320
|
* @remarks
|
|
29725
|
-
*
|
|
29726
|
-
*
|
|
29727
|
-
*
|
|
29728
|
-
* subscribed to.
|
|
30321
|
+
* Registers a handler for each verb's `.succeeded` event using the
|
|
30322
|
+
* shared `registerTelemetryHandler` from `@core/utils`. Non-verb and
|
|
30323
|
+
* non-succeeded events are not subscribed to.
|
|
29729
30324
|
*
|
|
29730
30325
|
* The HTTP POST is fire-and-forget — telemetry never blocks or fails
|
|
29731
30326
|
* user operations.
|
|
@@ -29745,20 +30340,7 @@ function mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion) {
|
|
|
29745
30340
|
* @internal
|
|
29746
30341
|
*/
|
|
29747
30342
|
function registerTelemetryHandler(dispatcher, sdkName, sdkVersion) {
|
|
29748
|
-
|
|
29749
|
-
dispatcher.on(actionName, (payload) => {
|
|
29750
|
-
try {
|
|
29751
|
-
const log = mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion);
|
|
29752
|
-
if (log) {
|
|
29753
|
-
// Fire-and-forget — intentionally not awaited.
|
|
29754
|
-
void emitAnalyticsLog(log);
|
|
29755
|
-
}
|
|
29756
|
-
}
|
|
29757
|
-
catch {
|
|
29758
|
-
// Silently swallow — telemetry must never break user operations.
|
|
29759
|
-
}
|
|
29760
|
-
});
|
|
29761
|
-
}
|
|
30343
|
+
registerTelemetryHandler$1(dispatcher, sdkName, sdkVersion, VERB_EVENT_MAP, mapSucceededEventToLog);
|
|
29762
30344
|
}
|
|
29763
30345
|
|
|
29764
30346
|
/**
|
|
@@ -32861,13 +33443,20 @@ async function resolveAllocationsAndIntents(params, destChain, recipientAddress,
|
|
|
32861
33443
|
const sourcesArray = rawSources.filter((s) => s != null);
|
|
32862
33444
|
const networkType = destChain.isTestnet ? 'testnet' : 'mainnet';
|
|
32863
33445
|
const balanceResults = await Promise.all(sourcesArray.map(async (source) => {
|
|
32864
|
-
|
|
32865
|
-
|
|
32866
|
-
|
|
32867
|
-
|
|
32868
|
-
|
|
32869
|
-
|
|
32870
|
-
|
|
33446
|
+
// When sourceAccount is set (delegate flow), scope the balance
|
|
33447
|
+
// query to the Gateway depositor — not the signer. Using the
|
|
33448
|
+
// address-only path bypasses adapter address resolution, which
|
|
33449
|
+
// would otherwise return the signer's balance (developer-
|
|
33450
|
+
// controlled) or reject an explicit address (user-controlled).
|
|
33451
|
+
let querySource;
|
|
33452
|
+
if (source.sourceAccount) {
|
|
33453
|
+
querySource = { address: source.sourceAccount };
|
|
33454
|
+
}
|
|
33455
|
+
else {
|
|
33456
|
+
querySource = { adapter: source.adapter };
|
|
33457
|
+
if ('address' in source && source.address) {
|
|
33458
|
+
querySource['address'] = source.address;
|
|
33459
|
+
}
|
|
32871
33460
|
}
|
|
32872
33461
|
return getBalances$1({
|
|
32873
33462
|
token: params.token,
|
|
@@ -35788,6 +36377,8 @@ function getSupportedChains(context, token, options) {
|
|
|
35788
36377
|
return Object.values(Object.fromEntries(filtered.map((chain) => [chain.chain, chain])));
|
|
35789
36378
|
}
|
|
35790
36379
|
|
|
36380
|
+
/** SDK name used in telemetry payloads. */
|
|
36381
|
+
const SDK_NAME = resolveKitSdkName(pkg.name);
|
|
35791
36382
|
/**
|
|
35792
36383
|
* A high-level class-based interface for cross-chain USDC deposits,
|
|
35793
36384
|
* spending, balance queries, delegation management, and withdrawals.
|
|
@@ -35835,6 +36426,10 @@ class UnifiedBalanceKit {
|
|
|
35835
36426
|
* The action dispatcher for the kit.
|
|
35836
36427
|
*/
|
|
35837
36428
|
actionDispatcher;
|
|
36429
|
+
/** Whether error telemetry is disabled. */
|
|
36430
|
+
disableErrorReporting;
|
|
36431
|
+
/** Per-kit telemetry identity for shared helpers. */
|
|
36432
|
+
telemetryConfig;
|
|
35838
36433
|
/**
|
|
35839
36434
|
* Create a new UnifiedBalanceKit instance.
|
|
35840
36435
|
*
|
|
@@ -35847,14 +36442,49 @@ class UnifiedBalanceKit {
|
|
|
35847
36442
|
constructor(config = {}) {
|
|
35848
36443
|
this.context = createUnifiedBalanceKitContext(config);
|
|
35849
36444
|
this.actionDispatcher = new Actionable();
|
|
36445
|
+
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
36446
|
+
this.telemetryConfig = {
|
|
36447
|
+
sdkName: SDK_NAME,
|
|
36448
|
+
sdkVersion: pkg.version,
|
|
36449
|
+
disabled: this.disableErrorReporting,
|
|
36450
|
+
};
|
|
35850
36451
|
for (const provider of this.context.providers) {
|
|
35851
36452
|
provider.registerDispatcher(this.actionDispatcher);
|
|
35852
36453
|
}
|
|
35853
36454
|
if (!config.disableAnalytics) {
|
|
35854
|
-
|
|
35855
|
-
registerTelemetryHandler(this.actionDispatcher, sdkName, pkg.version);
|
|
36455
|
+
registerTelemetryHandler(this.actionDispatcher, SDK_NAME, pkg.version);
|
|
35856
36456
|
}
|
|
35857
36457
|
}
|
|
36458
|
+
/**
|
|
36459
|
+
* Extract comma-separated source chain names from spend params.
|
|
36460
|
+
*
|
|
36461
|
+
* @internal
|
|
36462
|
+
*/
|
|
36463
|
+
static extractSpendSourceChains(params) {
|
|
36464
|
+
if (params == null || typeof params !== 'object' || !('from' in params)) {
|
|
36465
|
+
return undefined;
|
|
36466
|
+
}
|
|
36467
|
+
const fromVal = params.from;
|
|
36468
|
+
const sources = Array.isArray(fromVal) ? fromVal : [fromVal];
|
|
36469
|
+
const chains = [];
|
|
36470
|
+
for (const src of sources) {
|
|
36471
|
+
const allocs = src?.allocations;
|
|
36472
|
+
let allocArr;
|
|
36473
|
+
if (allocs == null) {
|
|
36474
|
+
allocArr = [];
|
|
36475
|
+
}
|
|
36476
|
+
else {
|
|
36477
|
+
allocArr = Array.isArray(allocs) ? allocs : [allocs];
|
|
36478
|
+
}
|
|
36479
|
+
for (const alloc of allocArr) {
|
|
36480
|
+
const name = resolveChainName(alloc.chain);
|
|
36481
|
+
if (name != null) {
|
|
36482
|
+
chains.push(name);
|
|
36483
|
+
}
|
|
36484
|
+
}
|
|
36485
|
+
}
|
|
36486
|
+
return chains.length > 0 ? chains.join(',') : undefined;
|
|
36487
|
+
}
|
|
35858
36488
|
// implementation just forwards to the bus
|
|
35859
36489
|
on(actionOrWildcard, handler) {
|
|
35860
36490
|
this.actionDispatcher.on(actionOrWildcard, handler);
|
|
@@ -35877,7 +36507,10 @@ class UnifiedBalanceKit {
|
|
|
35877
36507
|
* @see UnifiedBalanceKit.depositFor to deposit into another account.
|
|
35878
36508
|
*/
|
|
35879
36509
|
async deposit(params) {
|
|
35880
|
-
return deposit(this.context, params)
|
|
36510
|
+
return withErrorTelemetry(async () => deposit(this.context, params), EVENT_TYPES.DEPOSIT, this.telemetryConfig, {
|
|
36511
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36512
|
+
tokenIn: params.token ?? 'USDC',
|
|
36513
|
+
});
|
|
35881
36514
|
}
|
|
35882
36515
|
/**
|
|
35883
36516
|
* Deposit USDC into another account (not the caller's).
|
|
@@ -35889,7 +36522,10 @@ class UnifiedBalanceKit {
|
|
|
35889
36522
|
* @see UnifiedBalanceKit.deposit to deposit into your own account.
|
|
35890
36523
|
*/
|
|
35891
36524
|
async depositFor(params) {
|
|
35892
|
-
return depositFor(this.context, params)
|
|
36525
|
+
return withErrorTelemetry(async () => depositFor(this.context, params), EVENT_TYPES.DEPOSIT_FOR, this.telemetryConfig, {
|
|
36526
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36527
|
+
tokenIn: params.token ?? 'USDC',
|
|
36528
|
+
});
|
|
35893
36529
|
}
|
|
35894
36530
|
/**
|
|
35895
36531
|
* Spend (mint) USDC on a destination chain by pulling funds from one
|
|
@@ -35902,7 +36538,17 @@ class UnifiedBalanceKit {
|
|
|
35902
36538
|
* @see UnifiedBalanceKit.estimateSpend to preview fees before spending.
|
|
35903
36539
|
*/
|
|
35904
36540
|
async spend(params) {
|
|
35905
|
-
|
|
36541
|
+
const destChain = 'to' in params
|
|
36542
|
+
? resolveChainName(params.to.chain)
|
|
36543
|
+
: undefined;
|
|
36544
|
+
const tokenIn = 'token' in params
|
|
36545
|
+
? (params.token ?? 'USDC')
|
|
36546
|
+
: 'USDC';
|
|
36547
|
+
return withErrorTelemetry(async () => spend(this.context, params), EVENT_TYPES.SPEND, this.telemetryConfig, {
|
|
36548
|
+
sourceChain: UnifiedBalanceKit.extractSpendSourceChains(params),
|
|
36549
|
+
...(destChain != null && { destinationChain: destChain }),
|
|
36550
|
+
tokenIn,
|
|
36551
|
+
});
|
|
35906
36552
|
}
|
|
35907
36553
|
/**
|
|
35908
36554
|
* Estimate the fees for a spend operation without executing it.
|
|
@@ -35912,7 +36558,17 @@ class UnifiedBalanceKit {
|
|
|
35912
36558
|
* @returns Promise resolving to the fee estimate.
|
|
35913
36559
|
*/
|
|
35914
36560
|
async estimateSpend(params) {
|
|
35915
|
-
|
|
36561
|
+
const destChain = 'to' in params
|
|
36562
|
+
? resolveChainName(params.to.chain)
|
|
36563
|
+
: undefined;
|
|
36564
|
+
const sourceChain = UnifiedBalanceKit.extractSpendSourceChains(params);
|
|
36565
|
+
return withErrorTelemetry(async () => estimateSpend(this.context, params), EVENT_TYPES.ESTIMATE_SPEND, this.telemetryConfig, {
|
|
36566
|
+
...(sourceChain != null && { sourceChain }),
|
|
36567
|
+
...(destChain != null && { destinationChain: destChain }),
|
|
36568
|
+
tokenIn: 'token' in params
|
|
36569
|
+
? (params.token ?? 'USDC')
|
|
36570
|
+
: 'USDC',
|
|
36571
|
+
});
|
|
35916
36572
|
}
|
|
35917
36573
|
/**
|
|
35918
36574
|
* Fetch aggregated and per-chain balances for one or more accounts.
|
|
@@ -35921,7 +36577,7 @@ class UnifiedBalanceKit {
|
|
|
35921
36577
|
* @returns Promise resolving to the aggregated balance result.
|
|
35922
36578
|
*/
|
|
35923
36579
|
async getBalances(params) {
|
|
35924
|
-
return getBalances(this.context, params);
|
|
36580
|
+
return withErrorTelemetry(async () => getBalances(this.context, params), EVENT_TYPES.GET_BALANCES, this.telemetryConfig);
|
|
35925
36581
|
}
|
|
35926
36582
|
/**
|
|
35927
36583
|
* Grant spending rights to another address on the owner's account.
|
|
@@ -35936,7 +36592,7 @@ class UnifiedBalanceKit {
|
|
|
35936
36592
|
* @see UnifiedBalanceKit.getDelegateStatus to check delegate status.
|
|
35937
36593
|
*/
|
|
35938
36594
|
async addDelegate(params) {
|
|
35939
|
-
return addDelegate(this.context, params);
|
|
36595
|
+
return withErrorTelemetry(async () => addDelegate(this.context, params), EVENT_TYPES.ADD_DELEGATE, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
|
|
35940
36596
|
}
|
|
35941
36597
|
/**
|
|
35942
36598
|
* Revoke spending rights from a delegate on the owner's account.
|
|
@@ -35951,7 +36607,7 @@ class UnifiedBalanceKit {
|
|
|
35951
36607
|
* @see UnifiedBalanceKit.getDelegateStatus to check delegate status.
|
|
35952
36608
|
*/
|
|
35953
36609
|
async removeDelegate(params) {
|
|
35954
|
-
return removeDelegate(this.context, params);
|
|
36610
|
+
return withErrorTelemetry(async () => removeDelegate(this.context, params), EVENT_TYPES.REMOVE_DELEGATE, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
|
|
35955
36611
|
}
|
|
35956
36612
|
/**
|
|
35957
36613
|
* Kick off a delayed fund removal from an account.
|
|
@@ -35963,7 +36619,10 @@ class UnifiedBalanceKit {
|
|
|
35963
36619
|
* @see UnifiedBalanceKit.removeFund to complete the fund removal.
|
|
35964
36620
|
*/
|
|
35965
36621
|
async initiateRemoveFund(params) {
|
|
35966
|
-
return initiateRemoveFund(this.context, params)
|
|
36622
|
+
return withErrorTelemetry(async () => initiateRemoveFund(this.context, params), EVENT_TYPES.INITIATE_REMOVE_FUND, this.telemetryConfig, {
|
|
36623
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36624
|
+
tokenIn: params.token ?? 'USDC',
|
|
36625
|
+
});
|
|
35967
36626
|
}
|
|
35968
36627
|
/**
|
|
35969
36628
|
* Complete a fund removal once the activation period has passed.
|
|
@@ -35975,7 +36634,10 @@ class UnifiedBalanceKit {
|
|
|
35975
36634
|
* @see UnifiedBalanceKit.initiateRemoveFund to start the process.
|
|
35976
36635
|
*/
|
|
35977
36636
|
async removeFund(params) {
|
|
35978
|
-
return removeFund(this.context, params)
|
|
36637
|
+
return withErrorTelemetry(async () => removeFund(this.context, params), EVENT_TYPES.REMOVE_FUND, this.telemetryConfig, {
|
|
36638
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36639
|
+
tokenIn: params.token ?? 'USDC',
|
|
36640
|
+
});
|
|
35979
36641
|
}
|
|
35980
36642
|
/**
|
|
35981
36643
|
* Check the finality-aware delegate status of an address.
|
|
@@ -36003,7 +36665,7 @@ class UnifiedBalanceKit {
|
|
|
36003
36665
|
* ```
|
|
36004
36666
|
*/
|
|
36005
36667
|
async getDelegateStatus(params) {
|
|
36006
|
-
return getDelegateStatus(this.context, params);
|
|
36668
|
+
return withErrorTelemetry(async () => getDelegateStatus(this.context, params), EVENT_TYPES.GET_DELEGATE_STATUS, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
|
|
36007
36669
|
}
|
|
36008
36670
|
/**
|
|
36009
36671
|
* Get all chains supported by the kit.
|
|
@@ -36493,8 +37155,18 @@ class AppKit {
|
|
|
36493
37155
|
* ```
|
|
36494
37156
|
*/
|
|
36495
37157
|
constructor(config = {}) {
|
|
36496
|
-
this.context = createContext(
|
|
36497
|
-
|
|
37158
|
+
this.context = createContext({
|
|
37159
|
+
...config,
|
|
37160
|
+
...(config.disableErrorReporting != null && {
|
|
37161
|
+
disableErrorReporting: config.disableErrorReporting,
|
|
37162
|
+
}),
|
|
37163
|
+
});
|
|
37164
|
+
this.unifiedBalance = new AppKitUnifiedBalance({
|
|
37165
|
+
...config.unifiedBalance,
|
|
37166
|
+
...(config.disableErrorReporting != null && {
|
|
37167
|
+
disableErrorReporting: config.disableErrorReporting,
|
|
37168
|
+
}),
|
|
37169
|
+
});
|
|
36498
37170
|
}
|
|
36499
37171
|
/**
|
|
36500
37172
|
* Execute a cross-chain USDC bridge transfer.
|