@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.mjs
CHANGED
|
@@ -3398,6 +3398,8 @@ var Blockchain;
|
|
|
3398
3398
|
Blockchain["Hedera_Testnet"] = "Hedera_Testnet";
|
|
3399
3399
|
Blockchain["HyperEVM"] = "HyperEVM";
|
|
3400
3400
|
Blockchain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
3401
|
+
Blockchain["Injective"] = "Injective";
|
|
3402
|
+
Blockchain["Injective_Testnet"] = "Injective_Testnet";
|
|
3401
3403
|
Blockchain["Ink"] = "Ink";
|
|
3402
3404
|
Blockchain["Ink_Testnet"] = "Ink_Testnet";
|
|
3403
3405
|
Blockchain["Linea"] = "Linea";
|
|
@@ -3617,6 +3619,7 @@ var BridgeChain;
|
|
|
3617
3619
|
BridgeChain["Edge"] = "Edge";
|
|
3618
3620
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
3619
3621
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
3622
|
+
BridgeChain["Injective"] = "Injective";
|
|
3620
3623
|
BridgeChain["Ink"] = "Ink";
|
|
3621
3624
|
BridgeChain["Linea"] = "Linea";
|
|
3622
3625
|
BridgeChain["Monad"] = "Monad";
|
|
@@ -3640,6 +3643,7 @@ var BridgeChain;
|
|
|
3640
3643
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
3641
3644
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
3642
3645
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
3646
|
+
BridgeChain["Injective_Testnet"] = "Injective_Testnet";
|
|
3643
3647
|
BridgeChain["Ink_Testnet"] = "Ink_Testnet";
|
|
3644
3648
|
BridgeChain["Linea_Sepolia"] = "Linea_Sepolia";
|
|
3645
3649
|
BridgeChain["Monad_Testnet"] = "Monad_Testnet";
|
|
@@ -5084,6 +5088,98 @@ const HyperEVMTestnet = defineChain({
|
|
|
5084
5088
|
},
|
|
5085
5089
|
});
|
|
5086
5090
|
|
|
5091
|
+
/**
|
|
5092
|
+
* Injective Mainnet chain definition
|
|
5093
|
+
* @remarks
|
|
5094
|
+
* This represents the official production network for the Injective blockchain.
|
|
5095
|
+
* Injective is a high-performance, interoperable Layer-1 blockchain built for
|
|
5096
|
+
* finance, with an EVM execution layer on top of a Cosmos SDK base and
|
|
5097
|
+
* sub-second block finality.
|
|
5098
|
+
*/
|
|
5099
|
+
const Injective = defineChain({
|
|
5100
|
+
type: 'evm',
|
|
5101
|
+
chain: Blockchain.Injective,
|
|
5102
|
+
name: 'Injective',
|
|
5103
|
+
title: 'Injective Mainnet',
|
|
5104
|
+
nativeCurrency: {
|
|
5105
|
+
name: 'Injective',
|
|
5106
|
+
symbol: 'INJ',
|
|
5107
|
+
decimals: 18,
|
|
5108
|
+
},
|
|
5109
|
+
chainId: 1776,
|
|
5110
|
+
isTestnet: false,
|
|
5111
|
+
explorerUrl: 'https://injscan.com/transaction/{hash}',
|
|
5112
|
+
rpcEndpoints: ['https://sentry.evm-rpc.injective.network'],
|
|
5113
|
+
eurcAddress: null,
|
|
5114
|
+
usdcAddress: '0xa00C59fF5a080D2b954d0c75e46E22a0c371235a',
|
|
5115
|
+
usdtAddress: null,
|
|
5116
|
+
cctp: {
|
|
5117
|
+
domain: 29,
|
|
5118
|
+
contracts: {
|
|
5119
|
+
v2: {
|
|
5120
|
+
type: 'split',
|
|
5121
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
5122
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
5123
|
+
confirmations: 1,
|
|
5124
|
+
fastConfirmations: 1,
|
|
5125
|
+
},
|
|
5126
|
+
},
|
|
5127
|
+
forwarderSupported: {
|
|
5128
|
+
source: false,
|
|
5129
|
+
destination: false,
|
|
5130
|
+
},
|
|
5131
|
+
},
|
|
5132
|
+
kitContracts: {
|
|
5133
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
5134
|
+
},
|
|
5135
|
+
});
|
|
5136
|
+
|
|
5137
|
+
/**
|
|
5138
|
+
* Injective Testnet chain definition
|
|
5139
|
+
* @remarks
|
|
5140
|
+
* This represents the official test network for the Injective blockchain.
|
|
5141
|
+
* Injective is a high-performance, interoperable Layer-1 blockchain built for
|
|
5142
|
+
* finance, with an EVM execution layer on top of a Cosmos SDK base and
|
|
5143
|
+
* sub-second block finality.
|
|
5144
|
+
*/
|
|
5145
|
+
const InjectiveTestnet = defineChain({
|
|
5146
|
+
type: 'evm',
|
|
5147
|
+
chain: Blockchain.Injective_Testnet,
|
|
5148
|
+
name: 'Injective Testnet',
|
|
5149
|
+
title: 'Injective Testnet',
|
|
5150
|
+
nativeCurrency: {
|
|
5151
|
+
name: 'Injective',
|
|
5152
|
+
symbol: 'INJ',
|
|
5153
|
+
decimals: 18,
|
|
5154
|
+
},
|
|
5155
|
+
chainId: 1439,
|
|
5156
|
+
isTestnet: true,
|
|
5157
|
+
explorerUrl: 'https://testnet.explorer.injective.network/transaction/{hash}',
|
|
5158
|
+
rpcEndpoints: ['https://k8s.testnet.json-rpc.injective.network'],
|
|
5159
|
+
eurcAddress: null,
|
|
5160
|
+
usdcAddress: '0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d',
|
|
5161
|
+
usdtAddress: null,
|
|
5162
|
+
cctp: {
|
|
5163
|
+
domain: 29,
|
|
5164
|
+
contracts: {
|
|
5165
|
+
v2: {
|
|
5166
|
+
type: 'split',
|
|
5167
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5168
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5169
|
+
confirmations: 1,
|
|
5170
|
+
fastConfirmations: 1,
|
|
5171
|
+
},
|
|
5172
|
+
},
|
|
5173
|
+
forwarderSupported: {
|
|
5174
|
+
source: false,
|
|
5175
|
+
destination: false,
|
|
5176
|
+
},
|
|
5177
|
+
},
|
|
5178
|
+
kitContracts: {
|
|
5179
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET,
|
|
5180
|
+
},
|
|
5181
|
+
});
|
|
5182
|
+
|
|
5087
5183
|
/**
|
|
5088
5184
|
* Ink Mainnet chain definition
|
|
5089
5185
|
* @remarks
|
|
@@ -6926,6 +7022,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
6926
7022
|
HederaTestnet: HederaTestnet,
|
|
6927
7023
|
HyperEVM: HyperEVM,
|
|
6928
7024
|
HyperEVMTestnet: HyperEVMTestnet,
|
|
7025
|
+
Injective: Injective,
|
|
7026
|
+
InjectiveTestnet: InjectiveTestnet,
|
|
6929
7027
|
Ink: Ink,
|
|
6930
7028
|
InkTestnet: InkTestnet,
|
|
6931
7029
|
Linea: Linea,
|
|
@@ -7547,6 +7645,44 @@ function resolveChainIdentifier(chainIdentifier) {
|
|
|
7547
7645
|
throw new Error(`Invalid chain identifier type: ${typeof chainIdentifier}. Expected ChainDefinition object, Blockchain enum, or string literal.`);
|
|
7548
7646
|
}
|
|
7549
7647
|
|
|
7648
|
+
/**
|
|
7649
|
+
* Resolve a chain identifier to a plain chain-name string.
|
|
7650
|
+
*
|
|
7651
|
+
* Accept a string literal (`'Ethereum'`), a `ChainDefinition`-like
|
|
7652
|
+
* object (`{ chain: 'Ethereum' }`), or `null`/`undefined` and return
|
|
7653
|
+
* the chain name as a string. Return `undefined` when the value
|
|
7654
|
+
* cannot be resolved.
|
|
7655
|
+
*
|
|
7656
|
+
* @remarks
|
|
7657
|
+
* Unlike `resolveChainIdentifier` (which returns a full `ChainDefinition`
|
|
7658
|
+
* and throws on invalid input), this helper is intentionally lenient and
|
|
7659
|
+
* never throws — it is safe to call in error-handling and telemetry paths.
|
|
7660
|
+
*
|
|
7661
|
+
* @param value - A string, chain-definition object, or nullish value.
|
|
7662
|
+
* @returns The chain name string, or `undefined`.
|
|
7663
|
+
*
|
|
7664
|
+
* @example
|
|
7665
|
+
* ```typescript
|
|
7666
|
+
* import { resolveChainName } from '@core/chains'
|
|
7667
|
+
*
|
|
7668
|
+
* resolveChainName('Ethereum') // 'Ethereum'
|
|
7669
|
+
* resolveChainName({ chain: 'Ethereum' }) // 'Ethereum'
|
|
7670
|
+
* resolveChainName(undefined) // undefined
|
|
7671
|
+
* ```
|
|
7672
|
+
*/
|
|
7673
|
+
function resolveChainName(value) {
|
|
7674
|
+
if (value == null)
|
|
7675
|
+
return undefined;
|
|
7676
|
+
if (typeof value === 'string')
|
|
7677
|
+
return value;
|
|
7678
|
+
if (typeof value === 'object' &&
|
|
7679
|
+
'chain' in value &&
|
|
7680
|
+
typeof value.chain === 'string') {
|
|
7681
|
+
return value.chain;
|
|
7682
|
+
}
|
|
7683
|
+
return undefined;
|
|
7684
|
+
}
|
|
7685
|
+
|
|
7550
7686
|
/**
|
|
7551
7687
|
* @packageDocumentation
|
|
7552
7688
|
* @module SwapTokenUtils
|
|
@@ -9203,6 +9339,7 @@ const USDC = {
|
|
|
9203
9339
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
9204
9340
|
[Blockchain.Hedera]: '0.0.456858',
|
|
9205
9341
|
[Blockchain.HyperEVM]: '0xb88339CB7199b77E23DB6E890353E22632Ba630f',
|
|
9342
|
+
[Blockchain.Injective]: '0xa00C59fF5a080D2b954d0c75e46E22a0c371235a',
|
|
9206
9343
|
[Blockchain.Ink]: '0x2D270e6886d130D724215A266106e6832161EAEd',
|
|
9207
9344
|
[Blockchain.Linea]: '0x176211869ca2b568f2a7d4ee941e073a821ee1ff',
|
|
9208
9345
|
[Blockchain.Monad]: '0x754704Bc059F8C67012fEd69BC8A327a5aafb603',
|
|
@@ -9235,6 +9372,7 @@ const USDC = {
|
|
|
9235
9372
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
9236
9373
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
9237
9374
|
[Blockchain.HyperEVM_Testnet]: '0x2B3370eE501B4a559b57D449569354196457D8Ab',
|
|
9375
|
+
[Blockchain.Injective_Testnet]: '0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d',
|
|
9238
9376
|
[Blockchain.Ink_Testnet]: '0xFabab97dCE620294D2B0b0e46C68964e326300Ac',
|
|
9239
9377
|
[Blockchain.Linea_Sepolia]: '0xfece4462d57bd51a6a552365a011b95f0e16d9b7',
|
|
9240
9378
|
[Blockchain.Monad_Testnet]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
@@ -10336,8 +10474,325 @@ async function retryAsync(fn, options) {
|
|
|
10336
10474
|
throw new Error('retryAsync: unreachable');
|
|
10337
10475
|
}
|
|
10338
10476
|
|
|
10477
|
+
/**
|
|
10478
|
+
* Default telemetry endpoint.
|
|
10479
|
+
*
|
|
10480
|
+
* Override via the `STABLECOIN_KITS_TELEMETRY_URL` environment variable
|
|
10481
|
+
* (e.g. for staging or local development).
|
|
10482
|
+
*
|
|
10483
|
+
* @internal
|
|
10484
|
+
*/
|
|
10485
|
+
const DEFAULT_LOGS_URL = 'https://api.circle.com/v1/stablecoinKits/logs';
|
|
10486
|
+
/**
|
|
10487
|
+
* Resolve the telemetry endpoint URL.
|
|
10488
|
+
*
|
|
10489
|
+
* @internal
|
|
10490
|
+
*/
|
|
10491
|
+
function getLogsUrl() {
|
|
10492
|
+
if (isNodeEnvironment() &&
|
|
10493
|
+
typeof process.env['STABLECOIN_KITS_TELEMETRY_URL'] === 'string' &&
|
|
10494
|
+
process.env['STABLECOIN_KITS_TELEMETRY_URL'].length > 0) {
|
|
10495
|
+
return process.env['STABLECOIN_KITS_TELEMETRY_URL'];
|
|
10496
|
+
}
|
|
10497
|
+
return DEFAULT_LOGS_URL;
|
|
10498
|
+
}
|
|
10499
|
+
/**
|
|
10500
|
+
* Send a telemetry event to the proxy service.
|
|
10501
|
+
*
|
|
10502
|
+
* @remarks
|
|
10503
|
+
* Fire-and-forget: the returned promise is intentionally not awaited
|
|
10504
|
+
* by the caller. A fetch failure (network error, non-2xx, timeout)
|
|
10505
|
+
* is silently swallowed so telemetry never blocks or fails user
|
|
10506
|
+
* operations.
|
|
10507
|
+
*
|
|
10508
|
+
* @param payload - The structured log payload matching the server schema.
|
|
10509
|
+
*
|
|
10510
|
+
* @example
|
|
10511
|
+
* ```typescript
|
|
10512
|
+
* import { emitAnalyticsLog } from '@core/utils'
|
|
10513
|
+
*
|
|
10514
|
+
* // Fire-and-forget — do not await
|
|
10515
|
+
* void emitAnalyticsLog(payload)
|
|
10516
|
+
* ```
|
|
10517
|
+
*/
|
|
10518
|
+
async function emitAnalyticsLog(payload) {
|
|
10519
|
+
try {
|
|
10520
|
+
const isNode = isNodeEnvironment();
|
|
10521
|
+
const userAgent = getUserAgent();
|
|
10522
|
+
await fetch(getLogsUrl(), {
|
|
10523
|
+
method: 'POST',
|
|
10524
|
+
headers: {
|
|
10525
|
+
'Content-Type': 'application/json',
|
|
10526
|
+
// Browser restricts setting User-Agent; use X-User-Agent instead.
|
|
10527
|
+
...(isNode
|
|
10528
|
+
? { 'User-Agent': userAgent }
|
|
10529
|
+
: { 'X-User-Agent': userAgent }),
|
|
10530
|
+
},
|
|
10531
|
+
body: JSON.stringify(payload),
|
|
10532
|
+
signal: AbortSignal.timeout(5_000),
|
|
10533
|
+
});
|
|
10534
|
+
}
|
|
10535
|
+
catch {
|
|
10536
|
+
// Silently swallow — telemetry must never break user operations.
|
|
10537
|
+
}
|
|
10538
|
+
}
|
|
10539
|
+
|
|
10540
|
+
/**
|
|
10541
|
+
* Build the `clientContext` object for telemetry payloads.
|
|
10542
|
+
*
|
|
10543
|
+
* @remarks
|
|
10544
|
+
* Use the exported `getRuntime()` and `isNodeEnvironment()` from
|
|
10545
|
+
* `@core/utils` to detect the runtime environment. The returned
|
|
10546
|
+
* string is parsed into the structured `ClientContext` fields
|
|
10547
|
+
* expected by the server schema.
|
|
10548
|
+
*
|
|
10549
|
+
* @returns A {@link ClientContext} with platform, OS, and runtime name
|
|
10550
|
+
* populated from the current environment.
|
|
10551
|
+
*
|
|
10552
|
+
* @example
|
|
10553
|
+
* ```typescript
|
|
10554
|
+
* import { buildClientContext } from '@core/utils'
|
|
10555
|
+
*
|
|
10556
|
+
* const ctx = buildClientContext()
|
|
10557
|
+
* // Node: { platform: 'node', os: 'darwin', runtimeName: null }
|
|
10558
|
+
* // Browser: { platform: 'browser', os: null, runtimeName: 'chrome' }
|
|
10559
|
+
* ```
|
|
10560
|
+
*/
|
|
10561
|
+
function buildClientContext() {
|
|
10562
|
+
const runtime = getRuntime();
|
|
10563
|
+
if (runtime.startsWith('browser/')) {
|
|
10564
|
+
return {
|
|
10565
|
+
platform: 'browser',
|
|
10566
|
+
os: null,
|
|
10567
|
+
runtimeName: runtime.slice('browser/'.length).toLowerCase(),
|
|
10568
|
+
};
|
|
10569
|
+
}
|
|
10570
|
+
if (runtime.startsWith('node/')) {
|
|
10571
|
+
return {
|
|
10572
|
+
platform: 'node',
|
|
10573
|
+
os: isNodeEnvironment() ? process.platform : null,
|
|
10574
|
+
runtimeName: null,
|
|
10575
|
+
};
|
|
10576
|
+
}
|
|
10577
|
+
return {
|
|
10578
|
+
platform: 'node',
|
|
10579
|
+
os: null,
|
|
10580
|
+
runtimeName: null,
|
|
10581
|
+
};
|
|
10582
|
+
}
|
|
10583
|
+
|
|
10584
|
+
/**
|
|
10585
|
+
* Extract structured error details from an unknown error value.
|
|
10586
|
+
*
|
|
10587
|
+
* @remarks
|
|
10588
|
+
* Handle three cases:
|
|
10589
|
+
* - `KitError` — extract `code` and `name`.
|
|
10590
|
+
* - `Error` — extract `name`.
|
|
10591
|
+
* - Anything else — return empty details.
|
|
10592
|
+
*
|
|
10593
|
+
* Only structured, bounded fields (`errorCode`, `errorType`) are
|
|
10594
|
+
* included. Free-text fields (`message`, `stack`) are intentionally
|
|
10595
|
+
* omitted to avoid leaking secrets or PII through vendor telemetry.
|
|
10596
|
+
*
|
|
10597
|
+
* @param error - The thrown value to extract details from.
|
|
10598
|
+
* @returns A {@link ErrorDetails} object suitable for telemetry payloads.
|
|
10599
|
+
*
|
|
10600
|
+
* @example
|
|
10601
|
+
* ```typescript
|
|
10602
|
+
* import { extractErrorDetails } from '@core/utils'
|
|
10603
|
+
*
|
|
10604
|
+
* try {
|
|
10605
|
+
* await riskyOperation()
|
|
10606
|
+
* } catch (error) {
|
|
10607
|
+
* const details = extractErrorDetails(error)
|
|
10608
|
+
* // { errorCode: '1001', errorType: 'INPUT_NETWORK_MISMATCH' }
|
|
10609
|
+
* }
|
|
10610
|
+
* ```
|
|
10611
|
+
*/
|
|
10612
|
+
function extractErrorDetails(error) {
|
|
10613
|
+
if (error instanceof KitError) {
|
|
10614
|
+
return {
|
|
10615
|
+
errorCode: String(error.code),
|
|
10616
|
+
errorType: error.name,
|
|
10617
|
+
};
|
|
10618
|
+
}
|
|
10619
|
+
if (error instanceof Error) {
|
|
10620
|
+
return {
|
|
10621
|
+
errorType: error.name,
|
|
10622
|
+
};
|
|
10623
|
+
}
|
|
10624
|
+
return {};
|
|
10625
|
+
}
|
|
10626
|
+
|
|
10627
|
+
/**
|
|
10628
|
+
* Register event handlers on an action dispatcher that emit analytics
|
|
10629
|
+
* telemetry for the configured events.
|
|
10630
|
+
*
|
|
10631
|
+
* @remarks
|
|
10632
|
+
* Subscribe to each action name in `actionEventMap`, call `mapEventToPayload`
|
|
10633
|
+
* for each event, and fire-and-forget `emitAnalyticsLog` if a non-null
|
|
10634
|
+
* payload is returned. All errors are silently swallowed so telemetry
|
|
10635
|
+
* never blocks or fails user operations.
|
|
10636
|
+
*
|
|
10637
|
+
* @param dispatcher - The `Actionable` instance from the kit.
|
|
10638
|
+
* @param sdkName - SDK package name (e.g. `'unified-balance-kit'`).
|
|
10639
|
+
* @param sdkVersion - SDK version string (e.g. `'1.0.0'`).
|
|
10640
|
+
* @param actionEventMap - Map of action names to subscribe to.
|
|
10641
|
+
* @param mapEventToPayload - Function that maps an action name and payload
|
|
10642
|
+
* to a {@link ClientLogPayload}, or `null` to skip logging.
|
|
10643
|
+
*
|
|
10644
|
+
* @example
|
|
10645
|
+
* ```typescript
|
|
10646
|
+
* import { registerTelemetryHandler } from '@core/utils'
|
|
10647
|
+
*
|
|
10648
|
+
* registerTelemetryHandler(
|
|
10649
|
+
* dispatcher,
|
|
10650
|
+
* 'unified-balance-kit',
|
|
10651
|
+
* '1.0.0',
|
|
10652
|
+
* VERB_EVENT_MAP,
|
|
10653
|
+
* mapSucceededEventToLog,
|
|
10654
|
+
* )
|
|
10655
|
+
* ```
|
|
10656
|
+
*/
|
|
10657
|
+
function registerTelemetryHandler$1(dispatcher, sdkName, sdkVersion, actionEventMap, mapEventToPayload) {
|
|
10658
|
+
for (const actionName of Object.keys(actionEventMap)) {
|
|
10659
|
+
dispatcher.on(actionName, (payload) => {
|
|
10660
|
+
try {
|
|
10661
|
+
const log = mapEventToPayload(actionName, payload, sdkName, sdkVersion);
|
|
10662
|
+
if (log) {
|
|
10663
|
+
// Fire-and-forget — intentionally not awaited.
|
|
10664
|
+
void emitAnalyticsLog(log);
|
|
10665
|
+
}
|
|
10666
|
+
}
|
|
10667
|
+
catch {
|
|
10668
|
+
// Silently swallow — telemetry must never break user operations.
|
|
10669
|
+
}
|
|
10670
|
+
});
|
|
10671
|
+
}
|
|
10672
|
+
}
|
|
10673
|
+
|
|
10674
|
+
/**
|
|
10675
|
+
* Strip the `@circle-fin/` scope from a kit package name to produce the
|
|
10676
|
+
* short SDK name used in telemetry payloads.
|
|
10677
|
+
*
|
|
10678
|
+
* @param pkgName - The full npm package name (e.g. `@circle-fin/bridge-kit`).
|
|
10679
|
+
* @returns The unscoped kit name (e.g. `bridge-kit`).
|
|
10680
|
+
*
|
|
10681
|
+
* @example
|
|
10682
|
+
* ```typescript
|
|
10683
|
+
* import pkg from '../../package.json'
|
|
10684
|
+
* import { resolveKitSdkName } from '@core/utils'
|
|
10685
|
+
*
|
|
10686
|
+
* const SDK_NAME = resolveKitSdkName(pkg.name) // 'bridge-kit'
|
|
10687
|
+
* ```
|
|
10688
|
+
*/
|
|
10689
|
+
function resolveKitSdkName(pkgName) {
|
|
10690
|
+
return pkgName.replace('@circle-fin/', '');
|
|
10691
|
+
}
|
|
10692
|
+
|
|
10693
|
+
/**
|
|
10694
|
+
* Build a telemetry payload from common fields.
|
|
10695
|
+
*
|
|
10696
|
+
* @internal
|
|
10697
|
+
*/
|
|
10698
|
+
function buildPayload$1(config, eventType, errorDetails, context) {
|
|
10699
|
+
return {
|
|
10700
|
+
sdkName: config.sdkName,
|
|
10701
|
+
sdkVersion: config.sdkVersion,
|
|
10702
|
+
eventType,
|
|
10703
|
+
timestamp: new Date().toISOString(),
|
|
10704
|
+
errorDetails,
|
|
10705
|
+
clientContext: buildClientContext(),
|
|
10706
|
+
...(context?.sourceChain != null && {
|
|
10707
|
+
sourceChain: context.sourceChain,
|
|
10708
|
+
}),
|
|
10709
|
+
...(context?.destinationChain != null && {
|
|
10710
|
+
destinationChain: context.destinationChain,
|
|
10711
|
+
}),
|
|
10712
|
+
...(context?.tokenIn != null && { tokenIn: context.tokenIn }),
|
|
10713
|
+
...(context?.tokenOut != null && { tokenOut: context.tokenOut }),
|
|
10714
|
+
};
|
|
10715
|
+
}
|
|
10716
|
+
/**
|
|
10717
|
+
* Wrap an async operation with error telemetry.
|
|
10718
|
+
*
|
|
10719
|
+
* Execute `fn` and, if it throws, emit an error telemetry payload
|
|
10720
|
+
* before re-throwing. No-ops when `config.disabled` is `true`.
|
|
10721
|
+
*
|
|
10722
|
+
* @param fn - The async operation to execute.
|
|
10723
|
+
* @param eventType - The telemetry event type for this operation.
|
|
10724
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
10725
|
+
* @param context - Optional chain/token context.
|
|
10726
|
+
* @returns The result of the operation.
|
|
10727
|
+
* @throws Re-throws any error after emitting telemetry.
|
|
10728
|
+
*
|
|
10729
|
+
* @example
|
|
10730
|
+
* ```typescript
|
|
10731
|
+
* import { withErrorTelemetry } from '@core/utils'
|
|
10732
|
+
*
|
|
10733
|
+
* const result = await withErrorTelemetry(
|
|
10734
|
+
* () => provider.bridge(params),
|
|
10735
|
+
* 'bridge_bridge',
|
|
10736
|
+
* { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
|
|
10737
|
+
* { sourceChain: 'Ethereum', destinationChain: 'Base', tokenIn: 'USDC' },
|
|
10738
|
+
* )
|
|
10739
|
+
* ```
|
|
10740
|
+
*/
|
|
10741
|
+
async function withErrorTelemetry(fn, eventType, config, context) {
|
|
10742
|
+
try {
|
|
10743
|
+
return await fn();
|
|
10744
|
+
}
|
|
10745
|
+
catch (error) {
|
|
10746
|
+
if (!config.disabled) {
|
|
10747
|
+
void emitAnalyticsLog(buildPayload$1(config, eventType, extractErrorDetails(error), context));
|
|
10748
|
+
}
|
|
10749
|
+
throw error;
|
|
10750
|
+
}
|
|
10751
|
+
}
|
|
10752
|
+
/**
|
|
10753
|
+
* Emit error telemetry for a result-reported step error.
|
|
10754
|
+
*
|
|
10755
|
+
* Handle the case where a provider reports a step failure inside a
|
|
10756
|
+
* result object (e.g. `BridgeResult.state === 'error'`) rather than
|
|
10757
|
+
* throwing. The caller extracts the failed step as a simple
|
|
10758
|
+
* {@link FailedStepInfo} — this function handles sanitization,
|
|
10759
|
+
* step-to-event mapping, and emission.
|
|
10760
|
+
*
|
|
10761
|
+
* No-ops when `config.disabled` is `true`.
|
|
10762
|
+
*
|
|
10763
|
+
* @param failedStep - The failed step info, or undefined if none found.
|
|
10764
|
+
* @param stepEventMap - Ordered mapping from step names to event types.
|
|
10765
|
+
* @param fallbackEventType - Event type when step is not in the map.
|
|
10766
|
+
* @param config - Per-kit SDK identity and disabled flag.
|
|
10767
|
+
* @param context - Optional chain/token context.
|
|
10768
|
+
*
|
|
10769
|
+
* @example
|
|
10770
|
+
* ```typescript
|
|
10771
|
+
* import { emitResultStepErrorTelemetry } from '@core/utils'
|
|
10772
|
+
*
|
|
10773
|
+
* const failedStep = result.steps.find((s) => s.state === 'error')
|
|
10774
|
+
* emitResultStepErrorTelemetry(
|
|
10775
|
+
* failedStep,
|
|
10776
|
+
* BRIDGE_STEP_EVENT_MAP,
|
|
10777
|
+
* 'bridge_bridge',
|
|
10778
|
+
* { sdkName: 'bridge-kit', sdkVersion: '1.0.0', disabled: false },
|
|
10779
|
+
* { sourceChain: 'Ethereum', tokenIn: 'USDC' },
|
|
10780
|
+
* )
|
|
10781
|
+
* ```
|
|
10782
|
+
*/
|
|
10783
|
+
function emitResultStepErrorTelemetry(failedStep, stepEventMap, fallbackEventType, config, context) {
|
|
10784
|
+
if (config.disabled) {
|
|
10785
|
+
return;
|
|
10786
|
+
}
|
|
10787
|
+
const stepEntry = stepEventMap.find(([name]) => name === failedStep?.name);
|
|
10788
|
+
const errorDetails = {
|
|
10789
|
+
...(failedStep?.name != null && { errorType: failedStep.name }),
|
|
10790
|
+
};
|
|
10791
|
+
void emitAnalyticsLog(buildPayload$1(config, stepEntry?.[1] ?? fallbackEventType, errorDetails, context));
|
|
10792
|
+
}
|
|
10793
|
+
|
|
10339
10794
|
var name$2 = "@circle-fin/bridge-kit";
|
|
10340
|
-
var version$3 = "1.
|
|
10795
|
+
var version$3 = "1.10.0";
|
|
10341
10796
|
var pkg$3 = {
|
|
10342
10797
|
name: name$2,
|
|
10343
10798
|
version: version$3};
|
|
@@ -13302,18 +13757,16 @@ const buildIrisUrl = (sourceDomainId, transactionHash, isTestnet) => {
|
|
|
13302
13757
|
};
|
|
13303
13758
|
/**
|
|
13304
13759
|
* Fetches attestation data from the IRIS API with retry and timeout handling.
|
|
13305
|
-
* Since fetching starts after a confirmed burn transaction, we attempt up to 10 retries.
|
|
13306
|
-
* Implements a conservative delay between requests to respect the API rate
|
|
13307
|
-
* limit of 35 requests per second. To avoid rate limiting when multiple processes are
|
|
13308
|
-
* running concurrently, we enforce a 200ms delay between retries.
|
|
13309
13760
|
*
|
|
13310
|
-
*
|
|
13311
|
-
*
|
|
13761
|
+
* Polls the IRIS API until a complete attestation is available. The default
|
|
13762
|
+
* window is sized for slow source chains where finality may take many
|
|
13763
|
+
* confirmations.
|
|
13312
13764
|
*
|
|
13313
|
-
*
|
|
13314
|
-
* - Per
|
|
13315
|
-
* - Retry
|
|
13316
|
-
* -
|
|
13765
|
+
* Defaults (see `DEFAULT_CONFIG`):
|
|
13766
|
+
* - Per-attempt timeout: 2 000 ms (each HTTP request aborts after 2 s)
|
|
13767
|
+
* - Retry delay: 2 000 ms between attempts
|
|
13768
|
+
* - Max retries: 600 (30 × 20)
|
|
13769
|
+
* - Total worst-case polling window: 600 × (2 000 ms + 2 000 ms) ≈ 40 minutes
|
|
13317
13770
|
*
|
|
13318
13771
|
* @param sourceDomainId - The CCTP domain ID.
|
|
13319
13772
|
* @param transactionHash - The transaction hash to fetch attestation for.
|
|
@@ -15290,7 +15743,7 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain, statusCo
|
|
|
15290
15743
|
return step;
|
|
15291
15744
|
}
|
|
15292
15745
|
|
|
15293
|
-
var version$2 = "1.
|
|
15746
|
+
var version$2 = "1.8.1";
|
|
15294
15747
|
var pkg$2 = {
|
|
15295
15748
|
version: version$2};
|
|
15296
15749
|
|
|
@@ -16956,6 +17409,35 @@ const formatBridgeResult = (result, formatDirection) => {
|
|
|
16956
17409
|
};
|
|
16957
17410
|
};
|
|
16958
17411
|
|
|
17412
|
+
/**
|
|
17413
|
+
* Telemetry event type identifiers for bridge-kit operations.
|
|
17414
|
+
*
|
|
17415
|
+
* @internal
|
|
17416
|
+
*/
|
|
17417
|
+
const BRIDGE_EVENT_TYPES = {
|
|
17418
|
+
BRIDGE: 'bridge_bridge',
|
|
17419
|
+
RETRY: 'bridge_retry',
|
|
17420
|
+
ESTIMATE: 'bridge_estimate',
|
|
17421
|
+
};
|
|
17422
|
+
/**
|
|
17423
|
+
* Ordered mapping from provider step event names to telemetry event types.
|
|
17424
|
+
*
|
|
17425
|
+
* @remarks
|
|
17426
|
+
* The order matches the CCTP v2 bridge execution sequence. During
|
|
17427
|
+
* `bridge()`, completed step events are counted so the failing step
|
|
17428
|
+
* can be identified by its index.
|
|
17429
|
+
*
|
|
17430
|
+
* @internal
|
|
17431
|
+
*/
|
|
17432
|
+
const BRIDGE_STEP_EVENT_MAP = [
|
|
17433
|
+
['approve', 'bridge_approve'],
|
|
17434
|
+
['burn', 'bridge_burn'],
|
|
17435
|
+
['fetchAttestation', 'bridge_fetch_attestation'],
|
|
17436
|
+
['mint', 'bridge_mint'],
|
|
17437
|
+
];
|
|
17438
|
+
|
|
17439
|
+
/** SDK name used in telemetry payloads. */
|
|
17440
|
+
const SDK_NAME$2 = resolveKitSdkName(pkg$3.name);
|
|
16959
17441
|
/**
|
|
16960
17442
|
* BridgeKit caller component for retry and estimate operations.
|
|
16961
17443
|
*/
|
|
@@ -17039,6 +17521,10 @@ class BridgeKit {
|
|
|
17039
17521
|
* A custom fee policy for the kit.
|
|
17040
17522
|
*/
|
|
17041
17523
|
customFeePolicy;
|
|
17524
|
+
/** Whether error telemetry is disabled. */
|
|
17525
|
+
disableErrorReporting;
|
|
17526
|
+
/** Per-kit telemetry identity for shared helpers. */
|
|
17527
|
+
telemetryConfig;
|
|
17042
17528
|
/**
|
|
17043
17529
|
* Create a new BridgeKit instance.
|
|
17044
17530
|
*
|
|
@@ -17056,6 +17542,12 @@ class BridgeKit {
|
|
|
17056
17542
|
const defaultProviders = getDefaultProviders$2();
|
|
17057
17543
|
this.providers = [...defaultProviders, ...(config.providers ?? [])];
|
|
17058
17544
|
this.actionDispatcher = new Actionable();
|
|
17545
|
+
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
17546
|
+
this.telemetryConfig = {
|
|
17547
|
+
sdkName: SDK_NAME$2,
|
|
17548
|
+
sdkVersion: pkg$3.version,
|
|
17549
|
+
disabled: this.disableErrorReporting,
|
|
17550
|
+
};
|
|
17059
17551
|
for (const provider of this.providers) {
|
|
17060
17552
|
provider.registerDispatcher(this.actionDispatcher);
|
|
17061
17553
|
}
|
|
@@ -17129,19 +17621,36 @@ class BridgeKit {
|
|
|
17129
17621
|
* ```
|
|
17130
17622
|
*/
|
|
17131
17623
|
async bridge(params) {
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17624
|
+
return withErrorTelemetry(async () => {
|
|
17625
|
+
// First validate the parameters
|
|
17626
|
+
assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
|
|
17627
|
+
// Then resolve chain definitions (includes adapter chain support validation)
|
|
17628
|
+
const resolvedParams = await resolveBridgeParams(params);
|
|
17629
|
+
// Validate network compatibility
|
|
17630
|
+
this.validateNetworkCompatibility(resolvedParams);
|
|
17631
|
+
// Merge the custom fee config into the resolved params
|
|
17632
|
+
const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
|
|
17633
|
+
// Find a provider that supports this route
|
|
17634
|
+
const provider = this.findProviderForRoute(finalResolvedParams);
|
|
17635
|
+
// Execute the transfer using the provider
|
|
17636
|
+
// Format the bridge result into human-readable string values for the user
|
|
17637
|
+
const result = formatBridgeResult(await provider.bridge(finalResolvedParams), 'to-human-readable');
|
|
17638
|
+
// Emit error telemetry when the provider returns an error state
|
|
17639
|
+
// (provider records step failures in the result instead of throwing).
|
|
17640
|
+
if (result.state === 'error') {
|
|
17641
|
+
const failedStep = result.steps.find((s) => s.state === 'error');
|
|
17642
|
+
emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
|
|
17643
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
17644
|
+
destinationChain: resolveChainName(params.to.chain),
|
|
17645
|
+
tokenIn: params.token,
|
|
17646
|
+
});
|
|
17647
|
+
}
|
|
17648
|
+
return result;
|
|
17649
|
+
}, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
|
|
17650
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
17651
|
+
destinationChain: resolveChainName(params.to.chain),
|
|
17652
|
+
tokenIn: params.token,
|
|
17653
|
+
});
|
|
17145
17654
|
}
|
|
17146
17655
|
/**
|
|
17147
17656
|
* Retry a failed or incomplete cross-chain USDC bridge operation.
|
|
@@ -17213,17 +17722,33 @@ class BridgeKit {
|
|
|
17213
17722
|
* ```
|
|
17214
17723
|
*/
|
|
17215
17724
|
async retry(result, context, invocationMeta) {
|
|
17216
|
-
|
|
17217
|
-
|
|
17218
|
-
|
|
17219
|
-
|
|
17220
|
-
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
|
|
17224
|
-
|
|
17225
|
-
|
|
17226
|
-
|
|
17725
|
+
return withErrorTelemetry(async () => {
|
|
17726
|
+
const provider = this.providers.find((p) => p.name === result.provider);
|
|
17727
|
+
if (!provider) {
|
|
17728
|
+
throw new Error(`Provider ${result.provider} not found`);
|
|
17729
|
+
}
|
|
17730
|
+
// Merge BridgeKit caller into invocation metadata for retry operation
|
|
17731
|
+
const mergedMeta = mergeRetryInvocationMeta(invocationMeta);
|
|
17732
|
+
// Format the bridge result into bigint string values for internal use
|
|
17733
|
+
const formattedBridgeResultInternal = formatBridgeResult(result, 'to-internal');
|
|
17734
|
+
// Execute the retry using the provider
|
|
17735
|
+
// Format the bridge result into human-readable string values for the user
|
|
17736
|
+
const retryResult = formatBridgeResult(await provider.retry(formattedBridgeResultInternal, context, mergedMeta), 'to-human-readable');
|
|
17737
|
+
// Emit error telemetry when the provider returns an error state.
|
|
17738
|
+
if (retryResult.state === 'error') {
|
|
17739
|
+
const failedStep = retryResult.steps.find((s) => s.state === 'error');
|
|
17740
|
+
emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
|
|
17741
|
+
sourceChain: result.source.chain.chain,
|
|
17742
|
+
destinationChain: result.destination.chain.chain,
|
|
17743
|
+
tokenIn: result.token,
|
|
17744
|
+
});
|
|
17745
|
+
}
|
|
17746
|
+
return retryResult;
|
|
17747
|
+
}, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
|
|
17748
|
+
sourceChain: result.source.chain.chain,
|
|
17749
|
+
destinationChain: result.destination.chain.chain,
|
|
17750
|
+
tokenIn: result.token,
|
|
17751
|
+
});
|
|
17227
17752
|
}
|
|
17228
17753
|
/**
|
|
17229
17754
|
* Estimate the cost and fees for a cross-chain USDC bridge operation.
|
|
@@ -17262,18 +17787,24 @@ class BridgeKit {
|
|
|
17262
17787
|
* ```
|
|
17263
17788
|
*/
|
|
17264
17789
|
async estimate(params) {
|
|
17265
|
-
|
|
17266
|
-
|
|
17267
|
-
|
|
17268
|
-
|
|
17269
|
-
|
|
17270
|
-
|
|
17271
|
-
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17790
|
+
return withErrorTelemetry(async () => {
|
|
17791
|
+
// First validate the parameters
|
|
17792
|
+
assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
|
|
17793
|
+
// Then resolve chain definitions (includes adapter chain support validation)
|
|
17794
|
+
const resolvedParams = await resolveBridgeParams(params);
|
|
17795
|
+
// Validate network compatibility
|
|
17796
|
+
this.validateNetworkCompatibility(resolvedParams);
|
|
17797
|
+
// Merge the custom fee config into the resolved params
|
|
17798
|
+
const finalResolvedParams = await this.mergeCustomFeeConfig(resolvedParams);
|
|
17799
|
+
// Find a provider that supports this route
|
|
17800
|
+
const provider = this.findProviderForRoute(finalResolvedParams);
|
|
17801
|
+
// Estimate the transfer using the provider and format amounts to human-readable strings
|
|
17802
|
+
return formatBridgeResult(await provider.estimate(finalResolvedParams), 'to-human-readable');
|
|
17803
|
+
}, BRIDGE_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
|
|
17804
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
17805
|
+
destinationChain: resolveChainName(params.to.chain),
|
|
17806
|
+
tokenIn: params.token,
|
|
17807
|
+
});
|
|
17277
17808
|
}
|
|
17278
17809
|
/**
|
|
17279
17810
|
* Get all chains supported by any provider in the kit, with optional filtering.
|
|
@@ -17590,7 +18121,11 @@ const createBridgeKit = (context) => {
|
|
|
17590
18121
|
const getFee = context.getFee?.bind(context);
|
|
17591
18122
|
const getFeeRecipient = context.getFeeRecipient?.bind(context);
|
|
17592
18123
|
const hasBoth = typeof getFee === 'function' && typeof getFeeRecipient === 'function';
|
|
17593
|
-
const kit = new BridgeKit(
|
|
18124
|
+
const kit = new BridgeKit({
|
|
18125
|
+
...(context.disableErrorReporting != null && {
|
|
18126
|
+
disableErrorReporting: context.disableErrorReporting,
|
|
18127
|
+
}),
|
|
18128
|
+
});
|
|
17594
18129
|
if (hasBoth) {
|
|
17595
18130
|
kit.setCustomFeePolicy({
|
|
17596
18131
|
calculateFee: async (params) => {
|
|
@@ -17607,7 +18142,7 @@ const createBridgeKit = (context) => {
|
|
|
17607
18142
|
};
|
|
17608
18143
|
|
|
17609
18144
|
var name$1 = "@circle-fin/swap-kit";
|
|
17610
|
-
var version$1 = "1.
|
|
18145
|
+
var version$1 = "1.2.1";
|
|
17611
18146
|
var pkg$1 = {
|
|
17612
18147
|
name: name$1,
|
|
17613
18148
|
version: version$1};
|
|
@@ -21487,6 +22022,119 @@ function evmSigningData(burnIntent) {
|
|
|
21487
22022
|
};
|
|
21488
22023
|
}
|
|
21489
22024
|
|
|
22025
|
+
/**
|
|
22026
|
+
* EIP-7702 delegation indicator. A 7702-delegated EOA's bytecode is
|
|
22027
|
+
* `0xef0100` followed by the 20-byte delegate address (23 bytes total).
|
|
22028
|
+
* The underlying secp256k1 key still produces `ecrecover`-verifiable
|
|
22029
|
+
* signatures, so for Gateway's purposes a 7702-delegated address is
|
|
22030
|
+
* an EOA, not an SCA.
|
|
22031
|
+
*
|
|
22032
|
+
* Spec: https://eips.ethereum.org/EIPS/eip-7702
|
|
22033
|
+
*/
|
|
22034
|
+
const EIP_7702_DELEGATION_PREFIX = '0xef0100';
|
|
22035
|
+
/**
|
|
22036
|
+
* Assert that `address` on `chain` can sign Gateway burn intents.
|
|
22037
|
+
*
|
|
22038
|
+
* Gateway verifies burn-intent signatures with plain `ecrecover` (see
|
|
22039
|
+
* `evm-gateway-contracts/src/lib/EIP712Domain.sol`). Smart-contract
|
|
22040
|
+
* accounts (SCAs) produce signatures over wrapped hashes (ERC-1271 /
|
|
22041
|
+
* ERC-6492 / ERC-6900 replay-safe hashes) that Gateway cannot verify.
|
|
22042
|
+
* Additionally, the Circle Wallets backend rejects SCA typed-data signing
|
|
22043
|
+
* against Gateway's chainId-less domain with an opaque
|
|
22044
|
+
* `invalid integer value <nil>/<nil> for type uint256` error.
|
|
22045
|
+
*
|
|
22046
|
+
* EIP-7702-delegated EOAs are exempt: they expose non-empty bytecode
|
|
22047
|
+
* (`0xef0100<delegate>`) but the underlying secp256k1 key still produces
|
|
22048
|
+
* `ecrecover`-verifiable signatures, so Gateway accepts them.
|
|
22049
|
+
*
|
|
22050
|
+
* When the signer is a true SCA, raises an `INPUT_UNSUPPORTED_ACTION`
|
|
22051
|
+
* error directing the caller to register an EOA delegate against the
|
|
22052
|
+
* SCA and then submit the spend with the delegate EOA as the signer
|
|
22053
|
+
* and the SCA as the source account. See the unified-balance / Gateway
|
|
22054
|
+
* docs for the exact API.
|
|
22055
|
+
*
|
|
22056
|
+
* If bytecode cannot be read (RPC failure, etc.) the pre-check is
|
|
22057
|
+
* skipped and downstream signing surfaces its own error — a warning is
|
|
22058
|
+
* logged so the skip is diagnosable.
|
|
22059
|
+
*
|
|
22060
|
+
* @param adapter - Anything exposing {@link EvmAdapterLike.readBytecode}.
|
|
22061
|
+
* @param address - Signer address to validate.
|
|
22062
|
+
* @param chain - EVM chain where the signer lives.
|
|
22063
|
+
* @throws {KitError} INPUT_UNSUPPORTED_ACTION when `address` is an SCA.
|
|
22064
|
+
*
|
|
22065
|
+
* @example
|
|
22066
|
+
* ```typescript
|
|
22067
|
+
* import { assertSignerIsEoa } from '@core/adapter-evm'
|
|
22068
|
+
* import { Ethereum } from '@core/chains'
|
|
22069
|
+
*
|
|
22070
|
+
* await assertSignerIsEoa(adapter, '0xabc...', Ethereum)
|
|
22071
|
+
* ```
|
|
22072
|
+
*/
|
|
22073
|
+
async function assertSignerIsEoa(adapter, address, chain) {
|
|
22074
|
+
let code;
|
|
22075
|
+
try {
|
|
22076
|
+
code = await adapter.readBytecode(address, chain);
|
|
22077
|
+
}
|
|
22078
|
+
catch (err) {
|
|
22079
|
+
console.warn(`[gateway] assertSignerIsEoa skipped (readBytecode failed for ` +
|
|
22080
|
+
`${address} on ${chain.name}): ` +
|
|
22081
|
+
(err instanceof Error ? err.message : String(err)));
|
|
22082
|
+
return;
|
|
22083
|
+
}
|
|
22084
|
+
if (code === undefined ||
|
|
22085
|
+
code === '0x' ||
|
|
22086
|
+
code.toLowerCase().startsWith(EIP_7702_DELEGATION_PREFIX)) {
|
|
22087
|
+
return;
|
|
22088
|
+
}
|
|
22089
|
+
throw new KitError({
|
|
22090
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
22091
|
+
recoverability: 'FATAL',
|
|
22092
|
+
message: `Gateway burn-intent signing requires an EOA signer (Gateway ` +
|
|
22093
|
+
`verifies signatures with ecrecover and does not support ERC-1271). ` +
|
|
22094
|
+
`The signer ${address} on ${chain.name} has on-chain bytecode, ` +
|
|
22095
|
+
`indicating it is a smart-contract account (SCA). Register an EOA ` +
|
|
22096
|
+
`delegate against the SCA, then submit the spend with the delegate ` +
|
|
22097
|
+
`EOA as the signer and the SCA as the source account. See DEVX-2774.`,
|
|
22098
|
+
cause: {
|
|
22099
|
+
trace: {
|
|
22100
|
+
operation: 'signEvmIntentGroup.assertSignerIsEoa',
|
|
22101
|
+
address,
|
|
22102
|
+
chain: chain.name,
|
|
22103
|
+
bytecodeBytes: (code.length - 2) / 2,
|
|
22104
|
+
bytecodePrefix: code.slice(0, 12),
|
|
22105
|
+
},
|
|
22106
|
+
},
|
|
22107
|
+
});
|
|
22108
|
+
}
|
|
22109
|
+
|
|
22110
|
+
/**
|
|
22111
|
+
* Duck-type test for an EVM adapter that exposes `readBytecode`.
|
|
22112
|
+
*
|
|
22113
|
+
* Used as a structural guard at package boundaries (e.g. the Circle Wallets
|
|
22114
|
+
* hybrid adapter calling into a chain adapter, or the Gateway sign path
|
|
22115
|
+
* receiving an arbitrary adapter implementation) where `instanceof EvmAdapter`
|
|
22116
|
+
* is unreliable because each consumer bundles its own copy of the base class.
|
|
22117
|
+
*
|
|
22118
|
+
* @param value - The value to test.
|
|
22119
|
+
* @returns `true` when `value` is an object exposing a callable
|
|
22120
|
+
* `readBytecode` method, narrowed to {@link EvmAdapterLike}.
|
|
22121
|
+
*
|
|
22122
|
+
* @example
|
|
22123
|
+
* ```typescript
|
|
22124
|
+
* import { isEvmAdapterLike } from '@core/adapter-evm'
|
|
22125
|
+
*
|
|
22126
|
+
* if (isEvmAdapterLike(adapter)) {
|
|
22127
|
+
* const code = await adapter.readBytecode('0xabc...', chain)
|
|
22128
|
+
* }
|
|
22129
|
+
* ```
|
|
22130
|
+
*/
|
|
22131
|
+
function isEvmAdapterLike(value) {
|
|
22132
|
+
return (typeof value === 'object' &&
|
|
22133
|
+
value !== null &&
|
|
22134
|
+
'readBytecode' in value &&
|
|
22135
|
+
typeof value.readBytecode === 'function');
|
|
22136
|
+
}
|
|
22137
|
+
|
|
21490
22138
|
/**
|
|
21491
22139
|
* Sign an EVM adapter group: batches all intents and produces a single
|
|
21492
22140
|
* EIP-712 ECDSA signature.
|
|
@@ -21494,6 +22142,12 @@ function evmSigningData(burnIntent) {
|
|
|
21494
22142
|
* For a single-intent group, `primaryType` is `'BurnIntent'`.
|
|
21495
22143
|
* For multi-intent groups, `primaryType` is `'BurnIntentSet'`.
|
|
21496
22144
|
*
|
|
22145
|
+
* Before signing, asserts that the signer address is an EOA. Gateway
|
|
22146
|
+
* verifies burn-intent signatures with plain `ecrecover` (no ERC-1271
|
|
22147
|
+
* fallback), so signatures produced by smart-contract accounts (SCAs)
|
|
22148
|
+
* cannot be verified. When an SCA is detected, a clear error is raised
|
|
22149
|
+
* directing the caller to the delegate workflow (DEVX-2774).
|
|
22150
|
+
*
|
|
21497
22151
|
* @param group - The adapter group containing the adapter, chain, and
|
|
21498
22152
|
* burn intents to sign.
|
|
21499
22153
|
* @returns A signed set with the intents and the ECDSA signature.
|
|
@@ -21514,6 +22168,22 @@ function evmSigningData(burnIntent) {
|
|
|
21514
22168
|
async function signEvmIntentGroup(group) {
|
|
21515
22169
|
const { adapter, intents: groupIntents, chain, address } = group;
|
|
21516
22170
|
const operationContext = address === undefined ? { chain } : { chain, address };
|
|
22171
|
+
// Gateway verifies burn-intent signatures with plain ecrecover. An SCA
|
|
22172
|
+
// signer silently produces a signature over a wrapped hash that Gateway
|
|
22173
|
+
// cannot verify, and Circle Wallets' KMS rejects the typed data up front
|
|
22174
|
+
// with an opaque `<nil>/<nil>` error. Short-circuit with a clear message
|
|
22175
|
+
// when we can detect bytecode at the signer address. See DEVX-2774.
|
|
22176
|
+
//
|
|
22177
|
+
// Duck-typed on readBytecode rather than `instanceof EvmAdapter` because
|
|
22178
|
+
// each consumer package bundles its own copy of the base class and the
|
|
22179
|
+
// `instanceof` identity check fails across package boundaries.
|
|
22180
|
+
//
|
|
22181
|
+
// Empty string is defended against because assertSignerIsEoa would
|
|
22182
|
+
// otherwise call eth_getCode('') on the RPC.
|
|
22183
|
+
const hasResolvedSigner = typeof address === 'string' && address.length > 0;
|
|
22184
|
+
if (hasResolvedSigner && chain.type === 'evm' && isEvmAdapterLike(adapter)) {
|
|
22185
|
+
await assertSignerIsEoa(adapter, address, chain);
|
|
22186
|
+
}
|
|
21517
22187
|
const firstIntent = groupIntents[0];
|
|
21518
22188
|
const typedData = groupIntents.length === 1 && firstIntent
|
|
21519
22189
|
? evmSigningData(firstIntent)
|
|
@@ -21783,9 +22453,10 @@ function getSolanaFeeRecipient() {
|
|
|
21783
22453
|
return CIRCLE_FEE_RECIPIENT_SOLANA;
|
|
21784
22454
|
}
|
|
21785
22455
|
|
|
21786
|
-
|
|
21787
|
-
|
|
21788
|
-
|
|
22456
|
+
const enc = new TextEncoder();
|
|
22457
|
+
enc.encode('gateway_minter');
|
|
22458
|
+
enc.encode('gateway_minter_custody');
|
|
22459
|
+
enc.encode('used_transfer_spec_hash');
|
|
21789
22460
|
|
|
21790
22461
|
async function executeAndWait$1(adapter, request, chain) {
|
|
21791
22462
|
if (request.type === 'noop') {
|
|
@@ -28068,6 +28739,18 @@ function createSwapKitContext(config = {}) {
|
|
|
28068
28739
|
return context;
|
|
28069
28740
|
}
|
|
28070
28741
|
|
|
28742
|
+
/**
|
|
28743
|
+
* Telemetry event type identifiers for swap-kit operations.
|
|
28744
|
+
*
|
|
28745
|
+
* @internal
|
|
28746
|
+
*/
|
|
28747
|
+
const SWAP_EVENT_TYPES = {
|
|
28748
|
+
SWAP: 'swap_swap',
|
|
28749
|
+
ESTIMATE: 'swap_estimate',
|
|
28750
|
+
};
|
|
28751
|
+
|
|
28752
|
+
/** SDK name used in telemetry payloads. */
|
|
28753
|
+
const SDK_NAME$1 = resolveKitSdkName(pkg$1.name);
|
|
28071
28754
|
/**
|
|
28072
28755
|
* A high-level class-based interface for single-chain token swap operations.
|
|
28073
28756
|
*
|
|
@@ -28139,6 +28822,10 @@ function createSwapKitContext(config = {}) {
|
|
|
28139
28822
|
*/
|
|
28140
28823
|
class SwapKit {
|
|
28141
28824
|
context;
|
|
28825
|
+
/** Whether error telemetry is disabled. */
|
|
28826
|
+
disableErrorReporting;
|
|
28827
|
+
/** Per-kit telemetry identity for shared helpers. */
|
|
28828
|
+
telemetryConfig;
|
|
28142
28829
|
/**
|
|
28143
28830
|
* Create a new SwapKit instance.
|
|
28144
28831
|
*
|
|
@@ -28187,6 +28874,12 @@ class SwapKit {
|
|
|
28187
28874
|
*/
|
|
28188
28875
|
constructor(config = {}) {
|
|
28189
28876
|
this.context = createSwapKitContext(config);
|
|
28877
|
+
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
28878
|
+
this.telemetryConfig = {
|
|
28879
|
+
sdkName: SDK_NAME$1,
|
|
28880
|
+
sdkVersion: pkg$1.version,
|
|
28881
|
+
disabled: this.disableErrorReporting,
|
|
28882
|
+
};
|
|
28190
28883
|
}
|
|
28191
28884
|
/**
|
|
28192
28885
|
* Estimate the output amount and fees for a swap operation.
|
|
@@ -28228,7 +28921,11 @@ class SwapKit {
|
|
|
28228
28921
|
* ```
|
|
28229
28922
|
*/
|
|
28230
28923
|
async estimate(params) {
|
|
28231
|
-
return estimate(this.context, params)
|
|
28924
|
+
return withErrorTelemetry(async () => estimate(this.context, params), SWAP_EVENT_TYPES.ESTIMATE, this.telemetryConfig, {
|
|
28925
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
28926
|
+
tokenIn: params.tokenIn,
|
|
28927
|
+
tokenOut: params.tokenOut,
|
|
28928
|
+
});
|
|
28232
28929
|
}
|
|
28233
28930
|
/**
|
|
28234
28931
|
* Execute a token swap operation on a single chain.
|
|
@@ -28284,7 +28981,11 @@ class SwapKit {
|
|
|
28284
28981
|
* ```
|
|
28285
28982
|
*/
|
|
28286
28983
|
async swap(params) {
|
|
28287
|
-
return swap$1(this.context, params)
|
|
28984
|
+
return withErrorTelemetry(async () => swap$1(this.context, params), SWAP_EVENT_TYPES.SWAP, this.telemetryConfig, {
|
|
28985
|
+
sourceChain: resolveChainName(params.from.chain),
|
|
28986
|
+
tokenIn: params.tokenIn,
|
|
28987
|
+
tokenOut: params.tokenOut,
|
|
28988
|
+
});
|
|
28288
28989
|
}
|
|
28289
28990
|
/**
|
|
28290
28991
|
* Get all chains supported by the configured swap providers.
|
|
@@ -28477,7 +29178,11 @@ const createSwapKit = (context) => {
|
|
|
28477
29178
|
const getFee = context.getFee?.bind(context);
|
|
28478
29179
|
const getFeeRecipient = context.getFeeRecipient?.bind(context);
|
|
28479
29180
|
const hasBoth = typeof getFee === 'function' && typeof getFeeRecipient === 'function';
|
|
28480
|
-
const kit = new SwapKit(
|
|
29181
|
+
const kit = new SwapKit({
|
|
29182
|
+
...(context.disableErrorReporting != null && {
|
|
29183
|
+
disableErrorReporting: context.disableErrorReporting,
|
|
29184
|
+
}),
|
|
29185
|
+
});
|
|
28481
29186
|
if (hasBoth) {
|
|
28482
29187
|
kit.setCustomFeePolicy({
|
|
28483
29188
|
computeFee: async (params) => {
|
|
@@ -29426,121 +30131,11 @@ const getSupportedChains$2 = (context, operationType, unifiedBalance) => {
|
|
|
29426
30131
|
};
|
|
29427
30132
|
|
|
29428
30133
|
var name = "@circle-fin/unified-balance-kit";
|
|
29429
|
-
var version = "1.
|
|
30134
|
+
var version = "1.1.1";
|
|
29430
30135
|
var pkg = {
|
|
29431
30136
|
name: name,
|
|
29432
30137
|
version: version};
|
|
29433
30138
|
|
|
29434
|
-
/**
|
|
29435
|
-
* Default telemetry endpoint.
|
|
29436
|
-
*
|
|
29437
|
-
* Override via the `STABLECOIN_KITS_TELEMETRY_URL` environment variable
|
|
29438
|
-
* (e.g. for staging or local development).
|
|
29439
|
-
*
|
|
29440
|
-
* @internal
|
|
29441
|
-
*/
|
|
29442
|
-
const DEFAULT_LOGS_URL = 'https://api.circle.com/v1/stablecoinKits/logs';
|
|
29443
|
-
/**
|
|
29444
|
-
* Resolve the telemetry endpoint URL.
|
|
29445
|
-
*
|
|
29446
|
-
* @internal
|
|
29447
|
-
*/
|
|
29448
|
-
function getLogsUrl() {
|
|
29449
|
-
if (isNodeEnvironment() &&
|
|
29450
|
-
typeof process.env['STABLECOIN_KITS_TELEMETRY_URL'] === 'string' &&
|
|
29451
|
-
process.env['STABLECOIN_KITS_TELEMETRY_URL'].length > 0) {
|
|
29452
|
-
return process.env['STABLECOIN_KITS_TELEMETRY_URL'];
|
|
29453
|
-
}
|
|
29454
|
-
return DEFAULT_LOGS_URL;
|
|
29455
|
-
}
|
|
29456
|
-
/**
|
|
29457
|
-
* Send a telemetry event to the proxy service.
|
|
29458
|
-
*
|
|
29459
|
-
* @remarks
|
|
29460
|
-
* Fire-and-forget: the returned promise is intentionally not awaited
|
|
29461
|
-
* by the caller. A fetch failure (network error, non-2xx, timeout)
|
|
29462
|
-
* is silently swallowed so telemetry never blocks or fails user
|
|
29463
|
-
* operations.
|
|
29464
|
-
*
|
|
29465
|
-
* @param payload - The structured log payload matching the server schema.
|
|
29466
|
-
*
|
|
29467
|
-
* @example
|
|
29468
|
-
* ```typescript
|
|
29469
|
-
* import { emitAnalyticsLog } from './emitLog'
|
|
29470
|
-
*
|
|
29471
|
-
* // Fire-and-forget — do not await
|
|
29472
|
-
* emitAnalyticsLog(payload).catch(() => {})
|
|
29473
|
-
* ```
|
|
29474
|
-
*
|
|
29475
|
-
* @internal
|
|
29476
|
-
*/
|
|
29477
|
-
async function emitAnalyticsLog(payload) {
|
|
29478
|
-
try {
|
|
29479
|
-
const isNode = isNodeEnvironment();
|
|
29480
|
-
const userAgent = getUserAgent();
|
|
29481
|
-
await fetch(getLogsUrl(), {
|
|
29482
|
-
method: 'POST',
|
|
29483
|
-
headers: {
|
|
29484
|
-
'Content-Type': 'application/json',
|
|
29485
|
-
// Browser restricts setting User-Agent; use X-User-Agent instead.
|
|
29486
|
-
...(isNode
|
|
29487
|
-
? { 'User-Agent': userAgent }
|
|
29488
|
-
: { 'X-User-Agent': userAgent }),
|
|
29489
|
-
},
|
|
29490
|
-
body: JSON.stringify(payload),
|
|
29491
|
-
signal: AbortSignal.timeout(5_000),
|
|
29492
|
-
});
|
|
29493
|
-
}
|
|
29494
|
-
catch {
|
|
29495
|
-
// Silently swallow — telemetry must never break user operations.
|
|
29496
|
-
}
|
|
29497
|
-
}
|
|
29498
|
-
|
|
29499
|
-
/**
|
|
29500
|
-
* Build the `clientContext` object for telemetry payloads.
|
|
29501
|
-
*
|
|
29502
|
-
* @remarks
|
|
29503
|
-
* Uses the exported `getRuntime()` and `isNodeEnvironment()` from
|
|
29504
|
-
* `@core/utils` to detect the runtime environment (per Dominik's
|
|
29505
|
-
* feedback to reuse existing infrastructure). The returned string
|
|
29506
|
-
* is parsed into the structured `ClientContext` fields expected by
|
|
29507
|
-
* the server schema.
|
|
29508
|
-
*
|
|
29509
|
-
* @returns A {@link ClientContext} with platform, OS, and runtime name
|
|
29510
|
-
* populated from the current environment.
|
|
29511
|
-
*
|
|
29512
|
-
* @example
|
|
29513
|
-
* ```typescript
|
|
29514
|
-
* import { buildClientContext } from './clientContext'
|
|
29515
|
-
*
|
|
29516
|
-
* const ctx = buildClientContext()
|
|
29517
|
-
* // Node: { platform: 'node', os: 'darwin', runtimeName: null }
|
|
29518
|
-
* // Browser: { platform: 'browser', os: null, runtimeName: 'chrome' }
|
|
29519
|
-
* ```
|
|
29520
|
-
*/
|
|
29521
|
-
function buildClientContext() {
|
|
29522
|
-
const runtime = getRuntime();
|
|
29523
|
-
if (runtime.startsWith('browser/')) {
|
|
29524
|
-
return {
|
|
29525
|
-
platform: 'browser',
|
|
29526
|
-
os: null,
|
|
29527
|
-
runtimeName: runtime.slice('browser/'.length).toLowerCase(),
|
|
29528
|
-
};
|
|
29529
|
-
}
|
|
29530
|
-
if (runtime.startsWith('node/')) {
|
|
29531
|
-
return {
|
|
29532
|
-
platform: 'node',
|
|
29533
|
-
os: isNodeEnvironment() ? process.platform : null,
|
|
29534
|
-
runtimeName: null,
|
|
29535
|
-
};
|
|
29536
|
-
}
|
|
29537
|
-
return {
|
|
29538
|
-
platform: 'node',
|
|
29539
|
-
os: null,
|
|
29540
|
-
runtimeName: null,
|
|
29541
|
-
};
|
|
29542
|
-
}
|
|
29543
|
-
|
|
29544
30139
|
/**
|
|
29545
30140
|
* Event type identifiers accepted by the server-side logs endpoint.
|
|
29546
30141
|
*
|
|
@@ -29553,6 +30148,11 @@ const EVENT_TYPES = {
|
|
|
29553
30148
|
DEPOSIT_FOR: 'unified_balance_deposit_for',
|
|
29554
30149
|
SPEND: 'unified_balance_spend',
|
|
29555
30150
|
SPEND_FORWARDER: 'unified_balance_spend_forwarder',
|
|
30151
|
+
ESTIMATE_SPEND: 'unified_balance_estimate_spend',
|
|
30152
|
+
GET_BALANCES: 'unified_balance_get_balances',
|
|
30153
|
+
ADD_DELEGATE: 'unified_balance_add_delegate',
|
|
30154
|
+
REMOVE_DELEGATE: 'unified_balance_remove_delegate',
|
|
30155
|
+
GET_DELEGATE_STATUS: 'unified_balance_get_delegate_status',
|
|
29556
30156
|
INITIATE_REMOVE_FUND: 'unified_balance_initiate_remove_fund',
|
|
29557
30157
|
REMOVE_FUND: 'unified_balance_remove_fund',
|
|
29558
30158
|
};
|
|
@@ -29590,33 +30190,29 @@ function extractSingleChainResult(data) {
|
|
|
29590
30190
|
txHash: data.txHash,
|
|
29591
30191
|
};
|
|
29592
30192
|
}
|
|
29593
|
-
/**
|
|
29594
|
-
* Resolve a chain identifier that may be a string or a
|
|
29595
|
-
* `ChainDefinition` object to a plain string.
|
|
29596
|
-
*
|
|
29597
|
-
* @internal
|
|
29598
|
-
*/
|
|
29599
|
-
function resolveChainString(chain) {
|
|
29600
|
-
if (typeof chain === 'string')
|
|
29601
|
-
return chain;
|
|
29602
|
-
return chain.chain;
|
|
29603
|
-
}
|
|
29604
30193
|
/**
|
|
29605
30194
|
* Extract log-relevant fields from a spend result.
|
|
29606
30195
|
*
|
|
30196
|
+
* @remarks
|
|
30197
|
+
* Collects all source chains from allocations and joins them with
|
|
30198
|
+
* commas so multi-chain spends are fully represented.
|
|
30199
|
+
*
|
|
29607
30200
|
* @internal
|
|
29608
30201
|
*/
|
|
29609
30202
|
function extractSpend(data) {
|
|
29610
|
-
const
|
|
29611
|
-
|
|
29612
|
-
|
|
29613
|
-
|
|
30203
|
+
const allocs = data.allocations ?? [];
|
|
30204
|
+
const chains = [];
|
|
30205
|
+
for (const alloc of allocs) {
|
|
30206
|
+
const name = resolveChainName(alloc.chain);
|
|
30207
|
+
if (name != null) {
|
|
30208
|
+
chains.push(name);
|
|
30209
|
+
}
|
|
29614
30210
|
}
|
|
29615
|
-
const
|
|
30211
|
+
const sourceChain = chains.length > 0 ? chains.join(',') : undefined;
|
|
29616
30212
|
return {
|
|
29617
|
-
...(
|
|
30213
|
+
...(sourceChain != null && { sourceChain }),
|
|
29618
30214
|
destinationChain: data.destinationChain,
|
|
29619
|
-
...(
|
|
30215
|
+
...(allocs.length > 0 && { tokenIn: 'USDC' }),
|
|
29620
30216
|
txHash: data.txHash,
|
|
29621
30217
|
};
|
|
29622
30218
|
}
|
|
@@ -29715,10 +30311,9 @@ function mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion) {
|
|
|
29715
30311
|
* telemetry for successful verb operations.
|
|
29716
30312
|
*
|
|
29717
30313
|
* @remarks
|
|
29718
|
-
*
|
|
29719
|
-
*
|
|
29720
|
-
*
|
|
29721
|
-
* subscribed to.
|
|
30314
|
+
* Registers a handler for each verb's `.succeeded` event using the
|
|
30315
|
+
* shared `registerTelemetryHandler` from `@core/utils`. Non-verb and
|
|
30316
|
+
* non-succeeded events are not subscribed to.
|
|
29722
30317
|
*
|
|
29723
30318
|
* The HTTP POST is fire-and-forget — telemetry never blocks or fails
|
|
29724
30319
|
* user operations.
|
|
@@ -29738,20 +30333,7 @@ function mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion) {
|
|
|
29738
30333
|
* @internal
|
|
29739
30334
|
*/
|
|
29740
30335
|
function registerTelemetryHandler(dispatcher, sdkName, sdkVersion) {
|
|
29741
|
-
|
|
29742
|
-
dispatcher.on(actionName, (payload) => {
|
|
29743
|
-
try {
|
|
29744
|
-
const log = mapSucceededEventToLog(actionName, payload, sdkName, sdkVersion);
|
|
29745
|
-
if (log) {
|
|
29746
|
-
// Fire-and-forget — intentionally not awaited.
|
|
29747
|
-
void emitAnalyticsLog(log);
|
|
29748
|
-
}
|
|
29749
|
-
}
|
|
29750
|
-
catch {
|
|
29751
|
-
// Silently swallow — telemetry must never break user operations.
|
|
29752
|
-
}
|
|
29753
|
-
});
|
|
29754
|
-
}
|
|
30336
|
+
registerTelemetryHandler$1(dispatcher, sdkName, sdkVersion, VERB_EVENT_MAP, mapSucceededEventToLog);
|
|
29755
30337
|
}
|
|
29756
30338
|
|
|
29757
30339
|
/**
|
|
@@ -32854,13 +33436,20 @@ async function resolveAllocationsAndIntents(params, destChain, recipientAddress,
|
|
|
32854
33436
|
const sourcesArray = rawSources.filter((s) => s != null);
|
|
32855
33437
|
const networkType = destChain.isTestnet ? 'testnet' : 'mainnet';
|
|
32856
33438
|
const balanceResults = await Promise.all(sourcesArray.map(async (source) => {
|
|
32857
|
-
|
|
32858
|
-
|
|
32859
|
-
|
|
32860
|
-
|
|
32861
|
-
|
|
32862
|
-
|
|
32863
|
-
|
|
33439
|
+
// When sourceAccount is set (delegate flow), scope the balance
|
|
33440
|
+
// query to the Gateway depositor — not the signer. Using the
|
|
33441
|
+
// address-only path bypasses adapter address resolution, which
|
|
33442
|
+
// would otherwise return the signer's balance (developer-
|
|
33443
|
+
// controlled) or reject an explicit address (user-controlled).
|
|
33444
|
+
let querySource;
|
|
33445
|
+
if (source.sourceAccount) {
|
|
33446
|
+
querySource = { address: source.sourceAccount };
|
|
33447
|
+
}
|
|
33448
|
+
else {
|
|
33449
|
+
querySource = { adapter: source.adapter };
|
|
33450
|
+
if ('address' in source && source.address) {
|
|
33451
|
+
querySource['address'] = source.address;
|
|
33452
|
+
}
|
|
32864
33453
|
}
|
|
32865
33454
|
return getBalances$1({
|
|
32866
33455
|
token: params.token,
|
|
@@ -35781,6 +36370,8 @@ function getSupportedChains(context, token, options) {
|
|
|
35781
36370
|
return Object.values(Object.fromEntries(filtered.map((chain) => [chain.chain, chain])));
|
|
35782
36371
|
}
|
|
35783
36372
|
|
|
36373
|
+
/** SDK name used in telemetry payloads. */
|
|
36374
|
+
const SDK_NAME = resolveKitSdkName(pkg.name);
|
|
35784
36375
|
/**
|
|
35785
36376
|
* A high-level class-based interface for cross-chain USDC deposits,
|
|
35786
36377
|
* spending, balance queries, delegation management, and withdrawals.
|
|
@@ -35828,6 +36419,10 @@ class UnifiedBalanceKit {
|
|
|
35828
36419
|
* The action dispatcher for the kit.
|
|
35829
36420
|
*/
|
|
35830
36421
|
actionDispatcher;
|
|
36422
|
+
/** Whether error telemetry is disabled. */
|
|
36423
|
+
disableErrorReporting;
|
|
36424
|
+
/** Per-kit telemetry identity for shared helpers. */
|
|
36425
|
+
telemetryConfig;
|
|
35831
36426
|
/**
|
|
35832
36427
|
* Create a new UnifiedBalanceKit instance.
|
|
35833
36428
|
*
|
|
@@ -35840,14 +36435,49 @@ class UnifiedBalanceKit {
|
|
|
35840
36435
|
constructor(config = {}) {
|
|
35841
36436
|
this.context = createUnifiedBalanceKitContext(config);
|
|
35842
36437
|
this.actionDispatcher = new Actionable();
|
|
36438
|
+
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
36439
|
+
this.telemetryConfig = {
|
|
36440
|
+
sdkName: SDK_NAME,
|
|
36441
|
+
sdkVersion: pkg.version,
|
|
36442
|
+
disabled: this.disableErrorReporting,
|
|
36443
|
+
};
|
|
35843
36444
|
for (const provider of this.context.providers) {
|
|
35844
36445
|
provider.registerDispatcher(this.actionDispatcher);
|
|
35845
36446
|
}
|
|
35846
36447
|
if (!config.disableAnalytics) {
|
|
35847
|
-
|
|
35848
|
-
registerTelemetryHandler(this.actionDispatcher, sdkName, pkg.version);
|
|
36448
|
+
registerTelemetryHandler(this.actionDispatcher, SDK_NAME, pkg.version);
|
|
35849
36449
|
}
|
|
35850
36450
|
}
|
|
36451
|
+
/**
|
|
36452
|
+
* Extract comma-separated source chain names from spend params.
|
|
36453
|
+
*
|
|
36454
|
+
* @internal
|
|
36455
|
+
*/
|
|
36456
|
+
static extractSpendSourceChains(params) {
|
|
36457
|
+
if (params == null || typeof params !== 'object' || !('from' in params)) {
|
|
36458
|
+
return undefined;
|
|
36459
|
+
}
|
|
36460
|
+
const fromVal = params.from;
|
|
36461
|
+
const sources = Array.isArray(fromVal) ? fromVal : [fromVal];
|
|
36462
|
+
const chains = [];
|
|
36463
|
+
for (const src of sources) {
|
|
36464
|
+
const allocs = src?.allocations;
|
|
36465
|
+
let allocArr;
|
|
36466
|
+
if (allocs == null) {
|
|
36467
|
+
allocArr = [];
|
|
36468
|
+
}
|
|
36469
|
+
else {
|
|
36470
|
+
allocArr = Array.isArray(allocs) ? allocs : [allocs];
|
|
36471
|
+
}
|
|
36472
|
+
for (const alloc of allocArr) {
|
|
36473
|
+
const name = resolveChainName(alloc.chain);
|
|
36474
|
+
if (name != null) {
|
|
36475
|
+
chains.push(name);
|
|
36476
|
+
}
|
|
36477
|
+
}
|
|
36478
|
+
}
|
|
36479
|
+
return chains.length > 0 ? chains.join(',') : undefined;
|
|
36480
|
+
}
|
|
35851
36481
|
// implementation just forwards to the bus
|
|
35852
36482
|
on(actionOrWildcard, handler) {
|
|
35853
36483
|
this.actionDispatcher.on(actionOrWildcard, handler);
|
|
@@ -35870,7 +36500,10 @@ class UnifiedBalanceKit {
|
|
|
35870
36500
|
* @see UnifiedBalanceKit.depositFor to deposit into another account.
|
|
35871
36501
|
*/
|
|
35872
36502
|
async deposit(params) {
|
|
35873
|
-
return deposit(this.context, params)
|
|
36503
|
+
return withErrorTelemetry(async () => deposit(this.context, params), EVENT_TYPES.DEPOSIT, this.telemetryConfig, {
|
|
36504
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36505
|
+
tokenIn: params.token ?? 'USDC',
|
|
36506
|
+
});
|
|
35874
36507
|
}
|
|
35875
36508
|
/**
|
|
35876
36509
|
* Deposit USDC into another account (not the caller's).
|
|
@@ -35882,7 +36515,10 @@ class UnifiedBalanceKit {
|
|
|
35882
36515
|
* @see UnifiedBalanceKit.deposit to deposit into your own account.
|
|
35883
36516
|
*/
|
|
35884
36517
|
async depositFor(params) {
|
|
35885
|
-
return depositFor(this.context, params)
|
|
36518
|
+
return withErrorTelemetry(async () => depositFor(this.context, params), EVENT_TYPES.DEPOSIT_FOR, this.telemetryConfig, {
|
|
36519
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36520
|
+
tokenIn: params.token ?? 'USDC',
|
|
36521
|
+
});
|
|
35886
36522
|
}
|
|
35887
36523
|
/**
|
|
35888
36524
|
* Spend (mint) USDC on a destination chain by pulling funds from one
|
|
@@ -35895,7 +36531,17 @@ class UnifiedBalanceKit {
|
|
|
35895
36531
|
* @see UnifiedBalanceKit.estimateSpend to preview fees before spending.
|
|
35896
36532
|
*/
|
|
35897
36533
|
async spend(params) {
|
|
35898
|
-
|
|
36534
|
+
const destChain = 'to' in params
|
|
36535
|
+
? resolveChainName(params.to.chain)
|
|
36536
|
+
: undefined;
|
|
36537
|
+
const tokenIn = 'token' in params
|
|
36538
|
+
? (params.token ?? 'USDC')
|
|
36539
|
+
: 'USDC';
|
|
36540
|
+
return withErrorTelemetry(async () => spend(this.context, params), EVENT_TYPES.SPEND, this.telemetryConfig, {
|
|
36541
|
+
sourceChain: UnifiedBalanceKit.extractSpendSourceChains(params),
|
|
36542
|
+
...(destChain != null && { destinationChain: destChain }),
|
|
36543
|
+
tokenIn,
|
|
36544
|
+
});
|
|
35899
36545
|
}
|
|
35900
36546
|
/**
|
|
35901
36547
|
* Estimate the fees for a spend operation without executing it.
|
|
@@ -35905,7 +36551,17 @@ class UnifiedBalanceKit {
|
|
|
35905
36551
|
* @returns Promise resolving to the fee estimate.
|
|
35906
36552
|
*/
|
|
35907
36553
|
async estimateSpend(params) {
|
|
35908
|
-
|
|
36554
|
+
const destChain = 'to' in params
|
|
36555
|
+
? resolveChainName(params.to.chain)
|
|
36556
|
+
: undefined;
|
|
36557
|
+
const sourceChain = UnifiedBalanceKit.extractSpendSourceChains(params);
|
|
36558
|
+
return withErrorTelemetry(async () => estimateSpend(this.context, params), EVENT_TYPES.ESTIMATE_SPEND, this.telemetryConfig, {
|
|
36559
|
+
...(sourceChain != null && { sourceChain }),
|
|
36560
|
+
...(destChain != null && { destinationChain: destChain }),
|
|
36561
|
+
tokenIn: 'token' in params
|
|
36562
|
+
? (params.token ?? 'USDC')
|
|
36563
|
+
: 'USDC',
|
|
36564
|
+
});
|
|
35909
36565
|
}
|
|
35910
36566
|
/**
|
|
35911
36567
|
* Fetch aggregated and per-chain balances for one or more accounts.
|
|
@@ -35914,7 +36570,7 @@ class UnifiedBalanceKit {
|
|
|
35914
36570
|
* @returns Promise resolving to the aggregated balance result.
|
|
35915
36571
|
*/
|
|
35916
36572
|
async getBalances(params) {
|
|
35917
|
-
return getBalances(this.context, params);
|
|
36573
|
+
return withErrorTelemetry(async () => getBalances(this.context, params), EVENT_TYPES.GET_BALANCES, this.telemetryConfig);
|
|
35918
36574
|
}
|
|
35919
36575
|
/**
|
|
35920
36576
|
* Grant spending rights to another address on the owner's account.
|
|
@@ -35929,7 +36585,7 @@ class UnifiedBalanceKit {
|
|
|
35929
36585
|
* @see UnifiedBalanceKit.getDelegateStatus to check delegate status.
|
|
35930
36586
|
*/
|
|
35931
36587
|
async addDelegate(params) {
|
|
35932
|
-
return addDelegate(this.context, params);
|
|
36588
|
+
return withErrorTelemetry(async () => addDelegate(this.context, params), EVENT_TYPES.ADD_DELEGATE, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
|
|
35933
36589
|
}
|
|
35934
36590
|
/**
|
|
35935
36591
|
* Revoke spending rights from a delegate on the owner's account.
|
|
@@ -35944,7 +36600,7 @@ class UnifiedBalanceKit {
|
|
|
35944
36600
|
* @see UnifiedBalanceKit.getDelegateStatus to check delegate status.
|
|
35945
36601
|
*/
|
|
35946
36602
|
async removeDelegate(params) {
|
|
35947
|
-
return removeDelegate(this.context, params);
|
|
36603
|
+
return withErrorTelemetry(async () => removeDelegate(this.context, params), EVENT_TYPES.REMOVE_DELEGATE, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
|
|
35948
36604
|
}
|
|
35949
36605
|
/**
|
|
35950
36606
|
* Kick off a delayed fund removal from an account.
|
|
@@ -35956,7 +36612,10 @@ class UnifiedBalanceKit {
|
|
|
35956
36612
|
* @see UnifiedBalanceKit.removeFund to complete the fund removal.
|
|
35957
36613
|
*/
|
|
35958
36614
|
async initiateRemoveFund(params) {
|
|
35959
|
-
return initiateRemoveFund(this.context, params)
|
|
36615
|
+
return withErrorTelemetry(async () => initiateRemoveFund(this.context, params), EVENT_TYPES.INITIATE_REMOVE_FUND, this.telemetryConfig, {
|
|
36616
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36617
|
+
tokenIn: params.token ?? 'USDC',
|
|
36618
|
+
});
|
|
35960
36619
|
}
|
|
35961
36620
|
/**
|
|
35962
36621
|
* Complete a fund removal once the activation period has passed.
|
|
@@ -35968,7 +36627,10 @@ class UnifiedBalanceKit {
|
|
|
35968
36627
|
* @see UnifiedBalanceKit.initiateRemoveFund to start the process.
|
|
35969
36628
|
*/
|
|
35970
36629
|
async removeFund(params) {
|
|
35971
|
-
return removeFund(this.context, params)
|
|
36630
|
+
return withErrorTelemetry(async () => removeFund(this.context, params), EVENT_TYPES.REMOVE_FUND, this.telemetryConfig, {
|
|
36631
|
+
sourceChain: resolveChainName(params.from?.chain),
|
|
36632
|
+
tokenIn: params.token ?? 'USDC',
|
|
36633
|
+
});
|
|
35972
36634
|
}
|
|
35973
36635
|
/**
|
|
35974
36636
|
* Check the finality-aware delegate status of an address.
|
|
@@ -35996,7 +36658,7 @@ class UnifiedBalanceKit {
|
|
|
35996
36658
|
* ```
|
|
35997
36659
|
*/
|
|
35998
36660
|
async getDelegateStatus(params) {
|
|
35999
|
-
return getDelegateStatus(this.context, params);
|
|
36661
|
+
return withErrorTelemetry(async () => getDelegateStatus(this.context, params), EVENT_TYPES.GET_DELEGATE_STATUS, this.telemetryConfig, { sourceChain: resolveChainName(params.from?.chain) });
|
|
36000
36662
|
}
|
|
36001
36663
|
/**
|
|
36002
36664
|
* Get all chains supported by the kit.
|
|
@@ -36486,8 +37148,18 @@ class AppKit {
|
|
|
36486
37148
|
* ```
|
|
36487
37149
|
*/
|
|
36488
37150
|
constructor(config = {}) {
|
|
36489
|
-
this.context = createContext(
|
|
36490
|
-
|
|
37151
|
+
this.context = createContext({
|
|
37152
|
+
...config,
|
|
37153
|
+
...(config.disableErrorReporting != null && {
|
|
37154
|
+
disableErrorReporting: config.disableErrorReporting,
|
|
37155
|
+
}),
|
|
37156
|
+
});
|
|
37157
|
+
this.unifiedBalance = new AppKitUnifiedBalance({
|
|
37158
|
+
...config.unifiedBalance,
|
|
37159
|
+
...(config.disableErrorReporting != null && {
|
|
37160
|
+
disableErrorReporting: config.disableErrorReporting,
|
|
37161
|
+
}),
|
|
37162
|
+
});
|
|
36491
37163
|
}
|
|
36492
37164
|
/**
|
|
36493
37165
|
* Execute a cross-chain USDC bridge transfer.
|