@circle-fin/app-kit 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/README.md +56 -25
- package/bridge.cjs +297 -48
- package/bridge.d.cts +891 -2
- package/bridge.d.mts +891 -2
- package/bridge.d.ts +891 -2
- package/bridge.mjs +297 -48
- package/chains.cjs +117 -1
- package/chains.d.cts +96 -2
- package/chains.d.mts +96 -2
- package/chains.d.ts +96 -2
- package/chains.mjs +116 -2
- package/context.cjs +11 -0
- package/context.d.cts +891 -2
- package/context.d.mts +891 -2
- package/context.d.ts +891 -2
- package/context.mjs +11 -0
- package/earn.cjs +2343 -175
- package/earn.d.cts +891 -2
- package/earn.d.mts +891 -2
- package/earn.d.ts +891 -2
- package/earn.mjs +2343 -175
- package/estimateBridge.cjs +297 -48
- package/estimateBridge.d.cts +891 -2
- package/estimateBridge.d.mts +891 -2
- package/estimateBridge.d.ts +891 -2
- package/estimateBridge.mjs +297 -48
- package/estimateSwap.cjs +391 -39
- package/estimateSwap.d.cts +890 -2
- package/estimateSwap.d.mts +890 -2
- package/estimateSwap.d.ts +890 -2
- package/estimateSwap.mjs +391 -39
- package/index.cjs +2591 -315
- package/index.d.cts +2382 -1632
- package/index.d.mts +2382 -1632
- package/index.d.ts +2382 -1632
- package/index.mjs +2590 -316
- package/package.json +7 -6
- package/swap.cjs +391 -39
- package/swap.d.cts +890 -2
- package/swap.d.mts +890 -2
- package/swap.d.ts +890 -2
- package/swap.mjs +391 -39
- package/unifiedBalance.cjs +411 -132
- package/unifiedBalance.d.cts +30 -5
- package/unifiedBalance.d.mts +30 -5
- package/unifiedBalance.d.ts +30 -5
- package/unifiedBalance.mjs +411 -132
package/unifiedBalance.cjs
CHANGED
|
@@ -18,6 +18,17 @@
|
|
|
18
18
|
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
|
+
// Buffer polyfill setup - executes before any other code
|
|
22
|
+
// Ensures globalThis.Buffer is available for Solana libraries
|
|
23
|
+
const { Buffer } = require('buffer');
|
|
24
|
+
if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
|
|
25
|
+
globalThis.Buffer = Buffer;
|
|
26
|
+
}
|
|
27
|
+
if (typeof window !== 'undefined' && typeof window.Buffer === 'undefined') {
|
|
28
|
+
window.Buffer = Buffer;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
21
32
|
var zod = require('zod');
|
|
22
33
|
var web3_js = require('@solana/web3.js');
|
|
23
34
|
require('bn.js');
|
|
@@ -47,6 +58,27 @@ var bs58__default = /*#__PURE__*/_interopDefault(bs58);
|
|
|
47
58
|
* }
|
|
48
59
|
* ```
|
|
49
60
|
*/ const isNodeEnvironment = ()=>typeof process !== 'undefined' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
|
|
61
|
+
/**
|
|
62
|
+
* Return the SDK User-Agent request header only when running in Node.js.
|
|
63
|
+
*
|
|
64
|
+
* Browsers forbid manually setting `User-Agent`, and a custom fallback header
|
|
65
|
+
* can trigger CORS preflight. Non-Node server runtimes also omit this optional
|
|
66
|
+
* attribution header because they cannot set it reliably.
|
|
67
|
+
*
|
|
68
|
+
* @returns A User-Agent header in Node.js, or an empty object otherwise.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { getNodeUserAgentHeader } from '@core/utils'
|
|
73
|
+
*
|
|
74
|
+
* const headers = {
|
|
75
|
+
* 'Content-Type': 'application/json',
|
|
76
|
+
* ...getNodeUserAgentHeader(),
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*/ const getNodeUserAgentHeader = ()=>isNodeEnvironment() ? {
|
|
80
|
+
'User-Agent': getUserAgent()
|
|
81
|
+
} : {};
|
|
50
82
|
/**
|
|
51
83
|
* Detect the runtime environment and return a shortened identifier.
|
|
52
84
|
*
|
|
@@ -632,11 +664,6 @@ class KitError extends Error {
|
|
|
632
664
|
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
633
665
|
type: 'INPUT'
|
|
634
666
|
},
|
|
635
|
-
/** Action not supported by this adapter / ecosystem */ UNSUPPORTED_ACTION: {
|
|
636
|
-
code: 1008,
|
|
637
|
-
name: 'INPUT_UNSUPPORTED_ACTION',
|
|
638
|
-
type: 'INPUT'
|
|
639
|
-
},
|
|
640
667
|
/** No route satisfies the slippage or minimum-output constraint */ SLIPPAGE_CONSTRAINT_NOT_MET: {
|
|
641
668
|
code: 1009,
|
|
642
669
|
name: 'INPUT_SLIPPAGE_CONSTRAINT_NOT_MET',
|
|
@@ -2293,6 +2320,8 @@ class KitError extends Error {
|
|
|
2293
2320
|
Blockchain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
|
|
2294
2321
|
Blockchain["XDC"] = "XDC";
|
|
2295
2322
|
Blockchain["XDC_Apothem"] = "XDC_Apothem";
|
|
2323
|
+
Blockchain["X_Layer"] = "X_Layer";
|
|
2324
|
+
Blockchain["X_Layer_Testnet"] = "X_Layer_Testnet";
|
|
2296
2325
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
2297
2326
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
2298
2327
|
})(Blockchain || (Blockchain = {}));
|
|
@@ -2346,6 +2375,7 @@ var BridgeChain;
|
|
|
2346
2375
|
BridgeChain["Unichain"] = "Unichain";
|
|
2347
2376
|
BridgeChain["World_Chain"] = "World_Chain";
|
|
2348
2377
|
BridgeChain["XDC"] = "XDC";
|
|
2378
|
+
BridgeChain["X_Layer"] = "X_Layer";
|
|
2349
2379
|
// Testnet chains with CCTPv2 support
|
|
2350
2380
|
BridgeChain["Arc_Testnet"] = "Arc_Testnet";
|
|
2351
2381
|
BridgeChain["Arbitrum_Sepolia"] = "Arbitrum_Sepolia";
|
|
@@ -2371,6 +2401,7 @@ var BridgeChain;
|
|
|
2371
2401
|
BridgeChain["Unichain_Sepolia"] = "Unichain_Sepolia";
|
|
2372
2402
|
BridgeChain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
|
|
2373
2403
|
BridgeChain["XDC_Apothem"] = "XDC_Apothem";
|
|
2404
|
+
BridgeChain["X_Layer_Testnet"] = "X_Layer_Testnet";
|
|
2374
2405
|
})(BridgeChain || (BridgeChain = {}));
|
|
2375
2406
|
var UnifiedBalanceChain;
|
|
2376
2407
|
(function(UnifiedBalanceChain) {
|
|
@@ -4918,7 +4949,8 @@ var EarnChain;
|
|
|
4918
4949
|
isTestnet: true,
|
|
4919
4950
|
explorerUrl: 'https://amoy.polygonscan.com/tx/{hash}',
|
|
4920
4951
|
rpcEndpoints: [
|
|
4921
|
-
'https://
|
|
4952
|
+
'https://polygon-amoy-bor-rpc.publicnode.com',
|
|
4953
|
+
'https://polygon-amoy.drpc.org'
|
|
4922
4954
|
],
|
|
4923
4955
|
eurcAddress: null,
|
|
4924
4956
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
@@ -5783,6 +5815,104 @@ var EarnChain;
|
|
|
5783
5815
|
}
|
|
5784
5816
|
});
|
|
5785
5817
|
|
|
5818
|
+
/**
|
|
5819
|
+
* X Layer Mainnet chain definition
|
|
5820
|
+
* @remarks
|
|
5821
|
+
* This represents the official production network for the X Layer blockchain.
|
|
5822
|
+
* X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
|
|
5823
|
+
* using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
|
|
5824
|
+
* OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
|
|
5825
|
+
*/ const XLayer = defineChain({
|
|
5826
|
+
type: 'evm',
|
|
5827
|
+
chain: Blockchain.X_Layer,
|
|
5828
|
+
name: 'X Layer',
|
|
5829
|
+
title: 'X Layer Mainnet',
|
|
5830
|
+
nativeCurrency: {
|
|
5831
|
+
name: 'OKB',
|
|
5832
|
+
symbol: 'OKB',
|
|
5833
|
+
decimals: 18
|
|
5834
|
+
},
|
|
5835
|
+
chainId: 196,
|
|
5836
|
+
isTestnet: false,
|
|
5837
|
+
explorerUrl: 'https://www.oklink.com/xlayer/tx/{hash}',
|
|
5838
|
+
rpcEndpoints: [
|
|
5839
|
+
'https://xlayerrpc.okx.com'
|
|
5840
|
+
],
|
|
5841
|
+
eurcAddress: null,
|
|
5842
|
+
usdcAddress: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
|
|
5843
|
+
usdtAddress: null,
|
|
5844
|
+
cctp: {
|
|
5845
|
+
domain: 37,
|
|
5846
|
+
contracts: {
|
|
5847
|
+
v2: {
|
|
5848
|
+
type: 'split',
|
|
5849
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
5850
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
5851
|
+
confirmations: 65,
|
|
5852
|
+
fastConfirmations: 1
|
|
5853
|
+
}
|
|
5854
|
+
},
|
|
5855
|
+
forwarderSupported: {
|
|
5856
|
+
source: false,
|
|
5857
|
+
destination: false
|
|
5858
|
+
}
|
|
5859
|
+
},
|
|
5860
|
+
kitContracts: {
|
|
5861
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
5862
|
+
}
|
|
5863
|
+
});
|
|
5864
|
+
|
|
5865
|
+
/**
|
|
5866
|
+
* X Layer Testnet chain definition
|
|
5867
|
+
* @remarks
|
|
5868
|
+
* This represents the official test network for the X Layer blockchain.
|
|
5869
|
+
* X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
|
|
5870
|
+
* using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
|
|
5871
|
+
* OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
|
|
5872
|
+
*/ const XLayerTestnet = defineChain({
|
|
5873
|
+
type: 'evm',
|
|
5874
|
+
chain: Blockchain.X_Layer_Testnet,
|
|
5875
|
+
name: 'X Layer Testnet',
|
|
5876
|
+
title: 'X Layer Testnet',
|
|
5877
|
+
nativeCurrency: {
|
|
5878
|
+
name: 'OKB',
|
|
5879
|
+
symbol: 'OKB',
|
|
5880
|
+
decimals: 18
|
|
5881
|
+
},
|
|
5882
|
+
chainId: 1952,
|
|
5883
|
+
isTestnet: true,
|
|
5884
|
+
// Deliberately not oklink.com (used for mainnet): viem's bundled OKLink
|
|
5885
|
+
// testnet URL targets the deprecated pre-rebrand chain ID 195, not this
|
|
5886
|
+
// chain's ID (1952). Verified against the internal chain-expansion-scripts
|
|
5887
|
+
// config (`v2config.sandbox.yml`) — do not "normalize" this to match mainnet.
|
|
5888
|
+
explorerUrl: 'https://web3.okx.com/explorer/x-layer-testnet/tx/{hash}',
|
|
5889
|
+
rpcEndpoints: [
|
|
5890
|
+
'https://testrpc.xlayer.tech'
|
|
5891
|
+
],
|
|
5892
|
+
eurcAddress: null,
|
|
5893
|
+
usdcAddress: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
|
|
5894
|
+
usdtAddress: null,
|
|
5895
|
+
cctp: {
|
|
5896
|
+
domain: 37,
|
|
5897
|
+
contracts: {
|
|
5898
|
+
v2: {
|
|
5899
|
+
type: 'split',
|
|
5900
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5901
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5902
|
+
confirmations: 65,
|
|
5903
|
+
fastConfirmations: 1
|
|
5904
|
+
}
|
|
5905
|
+
},
|
|
5906
|
+
forwarderSupported: {
|
|
5907
|
+
source: false,
|
|
5908
|
+
destination: false
|
|
5909
|
+
}
|
|
5910
|
+
},
|
|
5911
|
+
kitContracts: {
|
|
5912
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
5913
|
+
}
|
|
5914
|
+
});
|
|
5915
|
+
|
|
5786
5916
|
/**
|
|
5787
5917
|
* ZKSync Era Mainnet chain definition
|
|
5788
5918
|
* @remarks
|
|
@@ -5902,6 +6032,8 @@ var Chains = {
|
|
|
5902
6032
|
WorldChainSepolia: WorldChainSepolia,
|
|
5903
6033
|
XDC: XDC,
|
|
5904
6034
|
XDCApothem: XDCApothem,
|
|
6035
|
+
XLayer: XLayer,
|
|
6036
|
+
XLayerTestnet: XLayerTestnet,
|
|
5905
6037
|
ZKSyncEra: ZKSyncEra,
|
|
5906
6038
|
ZKSyncEraSepolia: ZKSyncEraSepolia
|
|
5907
6039
|
};
|
|
@@ -7086,13 +7218,12 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7086
7218
|
headers: {
|
|
7087
7219
|
...DEFAULT_CONFIG.headers,
|
|
7088
7220
|
...config.headers ?? {},
|
|
7089
|
-
//
|
|
7090
|
-
//
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
}
|
|
7221
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
7222
|
+
// fallback header the SDK used instead trips CORS preflight against the
|
|
7223
|
+
// Circle APIs (it isn't in their `Access-Control-Allow-Headers`),
|
|
7224
|
+
// blocking the request. So send the SDK user agent only in Node;
|
|
7225
|
+
// browsers omit it entirely.
|
|
7226
|
+
...getNodeUserAgentHeader()
|
|
7096
7227
|
}
|
|
7097
7228
|
};
|
|
7098
7229
|
let lastError;
|
|
@@ -7855,6 +7986,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
7855
7986
|
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
7856
7987
|
[Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
7857
7988
|
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
7989
|
+
[Blockchain.X_Layer]: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
|
|
7858
7990
|
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
7859
7991
|
// =========================================================================
|
|
7860
7992
|
// Testnets (alphabetically sorted)
|
|
@@ -7889,6 +8021,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
7889
8021
|
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
7890
8022
|
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
7891
8023
|
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
8024
|
+
[Blockchain.X_Layer_Testnet]: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
|
|
7892
8025
|
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853'
|
|
7893
8026
|
}
|
|
7894
8027
|
};
|
|
@@ -8364,6 +8497,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
8364
8497
|
if (payload.tokenIn !== undefined) safe['tokenIn'] = payload.tokenIn;
|
|
8365
8498
|
if (payload.tokenOut !== undefined) safe['tokenOut'] = payload.tokenOut;
|
|
8366
8499
|
if (payload.txHash !== undefined) safe['txHash'] = payload.txHash;
|
|
8500
|
+
if (payload.correlationId !== undefined) safe['correlationId'] = payload.correlationId;
|
|
8367
8501
|
if (payload.errorDetails !== undefined) {
|
|
8368
8502
|
const errorDetails = {
|
|
8369
8503
|
...payload.errorDetails.errorCode !== undefined && {
|
|
@@ -8434,18 +8568,15 @@ function parseOrThrow(value, schema, context) {
|
|
|
8434
8568
|
timeoutHandle.unref();
|
|
8435
8569
|
}
|
|
8436
8570
|
try {
|
|
8437
|
-
const isNode = isNodeEnvironment();
|
|
8438
|
-
const userAgent = getUserAgent();
|
|
8439
8571
|
await fetch(getLogsUrl(), {
|
|
8440
8572
|
method: 'POST',
|
|
8441
8573
|
headers: {
|
|
8442
8574
|
'Content-Type': 'application/json',
|
|
8443
|
-
//
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
}
|
|
8575
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
8576
|
+
// fallback header the SDK used instead trips CORS preflight (it isn't
|
|
8577
|
+
// in the telemetry endpoint's `Access-Control-Allow-Headers`), so send
|
|
8578
|
+
// it only in Node; browsers omit it entirely.
|
|
8579
|
+
...getNodeUserAgentHeader()
|
|
8449
8580
|
},
|
|
8450
8581
|
body: JSON.stringify(toSafePayload(payload)),
|
|
8451
8582
|
signal: controller.signal
|
|
@@ -8658,7 +8789,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
8658
8789
|
// discards the stack trace, nested `cause`, and any custom Error
|
|
8659
8790
|
// properties — exactly the context an on-call needs when a
|
|
8660
8791
|
// resolver-closure regression triggers this path.
|
|
8661
|
-
console.warn(`[stablecoin-kits telemetry] dropped
|
|
8792
|
+
console.warn(`[stablecoin-kits telemetry] dropped event '${eventType}':`, cause);
|
|
8662
8793
|
} catch {
|
|
8663
8794
|
// console.warn itself throwing is the user's environment; nothing more we
|
|
8664
8795
|
// can do without risking the original operation error.
|
|
@@ -8674,7 +8805,9 @@ function parseOrThrow(value, schema, context) {
|
|
|
8674
8805
|
sdkVersion: config.sdkVersion,
|
|
8675
8806
|
eventType,
|
|
8676
8807
|
timestamp: new Date().toISOString(),
|
|
8677
|
-
errorDetails
|
|
8808
|
+
...errorDetails !== undefined && {
|
|
8809
|
+
errorDetails
|
|
8810
|
+
},
|
|
8678
8811
|
clientContext: buildClientContext(),
|
|
8679
8812
|
...context?.sourceChain != null && {
|
|
8680
8813
|
sourceChain: context.sourceChain
|
|
@@ -8690,6 +8823,9 @@ function parseOrThrow(value, schema, context) {
|
|
|
8690
8823
|
},
|
|
8691
8824
|
...context?.txHash != null && {
|
|
8692
8825
|
txHash: context.txHash
|
|
8826
|
+
},
|
|
8827
|
+
...context?.correlationId != null && {
|
|
8828
|
+
correlationId: context.correlationId
|
|
8693
8829
|
}
|
|
8694
8830
|
};
|
|
8695
8831
|
}
|
|
@@ -8751,7 +8887,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
8751
8887
|
}
|
|
8752
8888
|
|
|
8753
8889
|
var name = "@circle-fin/unified-balance-kit";
|
|
8754
|
-
var version = "1.
|
|
8890
|
+
var version = "1.4.0";
|
|
8755
8891
|
var pkg = {
|
|
8756
8892
|
name: name,
|
|
8757
8893
|
version: version};
|
|
@@ -12032,72 +12168,55 @@ function evmSigningData(burnIntent) {
|
|
|
12032
12168
|
* `0xef0100` followed by the 20-byte delegate address (23 bytes total).
|
|
12033
12169
|
* The underlying secp256k1 key still produces `ecrecover`-verifiable
|
|
12034
12170
|
* signatures, so for Gateway's purposes a 7702-delegated address is
|
|
12035
|
-
* an EOA, not
|
|
12171
|
+
* an EOA, not a contract signer.
|
|
12036
12172
|
*
|
|
12037
12173
|
* Spec: https://eips.ethereum.org/EIPS/eip-7702
|
|
12038
12174
|
*/ const EIP_7702_DELEGATION_PREFIX = '0xef0100';
|
|
12039
12175
|
/**
|
|
12040
|
-
*
|
|
12176
|
+
* Determine whether `address` on `chain` signs as a contract (ERC-1271)
|
|
12177
|
+
* rather than as an EOA.
|
|
12041
12178
|
*
|
|
12042
|
-
* Gateway
|
|
12043
|
-
* `
|
|
12044
|
-
*
|
|
12045
|
-
* ERC-
|
|
12046
|
-
*
|
|
12047
|
-
* against Gateway's chainId-less domain with an opaque
|
|
12048
|
-
* `invalid integer value <nil>/<nil> for type uint256` error.
|
|
12179
|
+
* Gateway validates burn-intent signatures two ways: a static `ecrecover`
|
|
12180
|
+
* check for EOAs, and — for requests that carry `contractSigner: true` —
|
|
12181
|
+
* an offchain `isValidSignature` simulation against the signing contract
|
|
12182
|
+
* (ERC-1271). Gateway does not infer which one to use, so the caller must
|
|
12183
|
+
* declare it. This detects the contract case from on-chain bytecode.
|
|
12049
12184
|
*
|
|
12050
|
-
* EIP-7702-delegated EOAs are
|
|
12051
|
-
* (`0xef0100<delegate>`) but the underlying secp256k1 key still
|
|
12052
|
-
* `ecrecover`-verifiable signatures, so
|
|
12185
|
+
* EIP-7702-delegated EOAs are treated as EOAs: they expose non-empty
|
|
12186
|
+
* bytecode (`0xef0100<delegate>`) but the underlying secp256k1 key still
|
|
12187
|
+
* produces `ecrecover`-verifiable signatures, so the cheaper EOA path
|
|
12188
|
+
* stays correct for them.
|
|
12053
12189
|
*
|
|
12054
|
-
*
|
|
12055
|
-
*
|
|
12056
|
-
*
|
|
12057
|
-
*
|
|
12058
|
-
* docs for the exact API.
|
|
12059
|
-
*
|
|
12060
|
-
* If bytecode cannot be read (RPC failure, etc.) the pre-check is
|
|
12061
|
-
* skipped and downstream signing surfaces its own error — a warning is
|
|
12062
|
-
* logged so the skip is diagnosable.
|
|
12190
|
+
* If bytecode cannot be read (RPC failure, etc.) the address is reported
|
|
12191
|
+
* as an EOA and a warning is logged so the fallback is diagnosable. A
|
|
12192
|
+
* genuine contract signer misreported this way is rejected by Gateway with
|
|
12193
|
+
* an invalid-signature error rather than silently mis-attested.
|
|
12063
12194
|
*
|
|
12064
12195
|
* @param adapter - Anything exposing {@link EvmAdapterLike.readBytecode}.
|
|
12065
|
-
* @param address - Signer address to
|
|
12196
|
+
* @param address - Signer address to classify.
|
|
12066
12197
|
* @param chain - EVM chain where the signer lives.
|
|
12067
|
-
* @
|
|
12198
|
+
* @returns `true` when the signer is a contract account and the transfer
|
|
12199
|
+
* request must set `contractSigner: true`; `false` otherwise.
|
|
12068
12200
|
*
|
|
12069
12201
|
* @example
|
|
12070
12202
|
* ```typescript
|
|
12071
|
-
* import {
|
|
12203
|
+
* import { isContractSigner } from '@core/adapter-evm'
|
|
12072
12204
|
* import { Ethereum } from '@core/chains'
|
|
12073
12205
|
*
|
|
12074
|
-
* await
|
|
12206
|
+
* const useErc1271 = await isContractSigner(adapter, '0xabc...', Ethereum)
|
|
12075
12207
|
* ```
|
|
12076
|
-
*/ async function
|
|
12208
|
+
*/ async function isContractSigner(adapter, address, chain) {
|
|
12077
12209
|
let code;
|
|
12078
12210
|
try {
|
|
12079
12211
|
code = await adapter.readBytecode(address, chain);
|
|
12080
12212
|
} catch (err) {
|
|
12081
|
-
console.warn(`[gateway]
|
|
12082
|
-
return;
|
|
12213
|
+
console.warn(`[gateway] isContractSigner defaulting to EOA (readBytecode failed ` + `for ${address} on ${chain.name}): ` + (err instanceof Error ? err.message : String(err)));
|
|
12214
|
+
return false;
|
|
12083
12215
|
}
|
|
12084
12216
|
if (code === undefined || code === '0x' || code.toLowerCase().startsWith(EIP_7702_DELEGATION_PREFIX)) {
|
|
12085
|
-
return;
|
|
12217
|
+
return false;
|
|
12086
12218
|
}
|
|
12087
|
-
|
|
12088
|
-
...InputError.UNSUPPORTED_ACTION,
|
|
12089
|
-
recoverability: 'FATAL',
|
|
12090
|
-
message: `Gateway burn-intent signing requires an EOA signer (Gateway ` + `verifies signatures with ecrecover and does not support ERC-1271). ` + `The signer ${address} on ${chain.name} has on-chain bytecode, ` + `indicating it is a smart-contract account (SCA). Register an EOA ` + `delegate against the SCA, then submit the spend with the delegate ` + `EOA as the signer and the SCA as the source account. See DEVX-2774.`,
|
|
12091
|
-
cause: {
|
|
12092
|
-
trace: {
|
|
12093
|
-
operation: 'signEvmIntentGroup.assertSignerIsEoa',
|
|
12094
|
-
address,
|
|
12095
|
-
chain: chain.name,
|
|
12096
|
-
bytecodeBytes: (code.length - 2) / 2,
|
|
12097
|
-
bytecodePrefix: code.slice(0, 12)
|
|
12098
|
-
}
|
|
12099
|
-
}
|
|
12100
|
-
});
|
|
12219
|
+
return true;
|
|
12101
12220
|
}
|
|
12102
12221
|
|
|
12103
12222
|
/**
|
|
@@ -12124,78 +12243,177 @@ function evmSigningData(burnIntent) {
|
|
|
12124
12243
|
return typeof value === 'object' && value !== null && 'readBytecode' in value && typeof value.readBytecode === 'function';
|
|
12125
12244
|
}
|
|
12126
12245
|
|
|
12246
|
+
function resolveIntentChain(group, intent) {
|
|
12247
|
+
const sourceDomain = intent.spec.sourceDomain;
|
|
12248
|
+
const chain = group.chainsByDomain.get(sourceDomain);
|
|
12249
|
+
if (chain !== undefined) return chain;
|
|
12250
|
+
throw createValidationFailedError$1('intent.spec.sourceDomain', sourceDomain, `No source chain found for Gateway domain ${String(sourceDomain)}`);
|
|
12251
|
+
}
|
|
12252
|
+
function normalizeSignatureResult(result) {
|
|
12253
|
+
if (typeof result === 'string') {
|
|
12254
|
+
return {
|
|
12255
|
+
signature: result,
|
|
12256
|
+
contractSigner: false
|
|
12257
|
+
};
|
|
12258
|
+
}
|
|
12259
|
+
if (typeof result === 'object' && result !== null && 'signature' in result && typeof result.signature === 'string') {
|
|
12260
|
+
return {
|
|
12261
|
+
signature: result.signature,
|
|
12262
|
+
contractSigner: 'contractSigner' in result && result.contractSigner === true
|
|
12263
|
+
};
|
|
12264
|
+
}
|
|
12265
|
+
throw createValidationFailedError$1('signature', result, 'must be a signature string or an object containing a signature string');
|
|
12266
|
+
}
|
|
12267
|
+
function validateGroupIntents(intents) {
|
|
12268
|
+
evmSigningData(intents);
|
|
12269
|
+
}
|
|
12270
|
+
function collectChainsByDomain(group) {
|
|
12271
|
+
const chainsByDomain = new Map();
|
|
12272
|
+
for (const intent of group.intents){
|
|
12273
|
+
chainsByDomain.set(intent.spec.sourceDomain, resolveIntentChain(group, intent));
|
|
12274
|
+
}
|
|
12275
|
+
return chainsByDomain;
|
|
12276
|
+
}
|
|
12277
|
+
async function classifySignerTypes(group, chainsByDomain) {
|
|
12278
|
+
const { adapter, address } = group;
|
|
12279
|
+
// Duck-typed on readBytecode rather than `instanceof EvmAdapter` because
|
|
12280
|
+
// each consumer package bundles its own copy of the base class and the
|
|
12281
|
+
// `instanceof` identity check fails across package boundaries.
|
|
12282
|
+
// Empty strings are rejected to avoid calling eth_getCode('') on the RPC.
|
|
12283
|
+
const hasResolvedSigner = typeof address === 'string' && address.length > 0;
|
|
12284
|
+
const signerTypes = await Promise.all([
|
|
12285
|
+
...chainsByDomain
|
|
12286
|
+
].map(async ([sourceDomain, sourceChain])=>{
|
|
12287
|
+
const contractSigner = hasResolvedSigner && sourceChain.type === 'evm' && isEvmAdapterLike(adapter) ? await isContractSigner(adapter, address, sourceChain) : false;
|
|
12288
|
+
return [
|
|
12289
|
+
sourceDomain,
|
|
12290
|
+
contractSigner
|
|
12291
|
+
];
|
|
12292
|
+
}));
|
|
12293
|
+
return new Map(signerTypes);
|
|
12294
|
+
}
|
|
12295
|
+
function createSigningUnits(group, signerTypeByDomain) {
|
|
12296
|
+
const contractUnitsByDomain = new Map();
|
|
12297
|
+
let eoaUnit;
|
|
12298
|
+
for (const [index, intent] of group.intents.entries()){
|
|
12299
|
+
const sourceDomain = intent.spec.sourceDomain;
|
|
12300
|
+
const contractSigner = signerTypeByDomain.get(sourceDomain) ?? false;
|
|
12301
|
+
if (contractSigner) {
|
|
12302
|
+
const existingUnit = contractUnitsByDomain.get(sourceDomain);
|
|
12303
|
+
if (existingUnit === undefined) {
|
|
12304
|
+
contractUnitsByDomain.set(sourceDomain, {
|
|
12305
|
+
intents: [
|
|
12306
|
+
intent
|
|
12307
|
+
],
|
|
12308
|
+
chain: resolveIntentChain(group, intent),
|
|
12309
|
+
contractSigner: true,
|
|
12310
|
+
firstIntentIndex: index
|
|
12311
|
+
});
|
|
12312
|
+
} else {
|
|
12313
|
+
existingUnit.intents.push(intent);
|
|
12314
|
+
}
|
|
12315
|
+
} else {
|
|
12316
|
+
eoaUnit ??= {
|
|
12317
|
+
intents: [],
|
|
12318
|
+
chain: resolveIntentChain(group, intent),
|
|
12319
|
+
contractSigner: false,
|
|
12320
|
+
firstIntentIndex: index
|
|
12321
|
+
};
|
|
12322
|
+
eoaUnit.intents.push(intent);
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
12325
|
+
const signingUnits = [
|
|
12326
|
+
...contractUnitsByDomain.values()
|
|
12327
|
+
];
|
|
12328
|
+
if (eoaUnit !== undefined) signingUnits.push(eoaUnit);
|
|
12329
|
+
signingUnits.sort((a, b)=>a.firstIntentIndex - b.firstIntentIndex);
|
|
12330
|
+
return signingUnits;
|
|
12331
|
+
}
|
|
12332
|
+
async function signUnit(group, unit) {
|
|
12333
|
+
const { adapter, address } = group;
|
|
12334
|
+
const firstIntent = unit.intents[0];
|
|
12335
|
+
const typedData = unit.intents.length === 1 && firstIntent !== undefined ? evmSigningData(firstIntent) : evmSigningData(unit.intents);
|
|
12336
|
+
const operationContext = address === undefined ? {
|
|
12337
|
+
chain: unit.chain
|
|
12338
|
+
} : {
|
|
12339
|
+
chain: unit.chain,
|
|
12340
|
+
address
|
|
12341
|
+
};
|
|
12342
|
+
const signRequest = await adapter.prepareAction('gateway.v1.signBurnIntents', {
|
|
12343
|
+
typedData,
|
|
12344
|
+
chain: unit.chain
|
|
12345
|
+
}, operationContext);
|
|
12346
|
+
const result = normalizeSignatureResult(await signRequest.execute());
|
|
12347
|
+
return {
|
|
12348
|
+
intents: unit.intents,
|
|
12349
|
+
signature: result.signature,
|
|
12350
|
+
contractSigner: result.contractSigner || unit.contractSigner
|
|
12351
|
+
};
|
|
12352
|
+
}
|
|
12353
|
+
async function signUnits(group, signingUnits) {
|
|
12354
|
+
const signedSets = [];
|
|
12355
|
+
// Keep wallet prompts deterministic. Multiple adapter groups can still sign
|
|
12356
|
+
// in parallel, but one signer is asked for its chain-bound signatures in
|
|
12357
|
+
// source-intent order.
|
|
12358
|
+
for (const unit of signingUnits){
|
|
12359
|
+
signedSets.push(await signUnit(group, unit));
|
|
12360
|
+
}
|
|
12361
|
+
return signedSets;
|
|
12362
|
+
}
|
|
12127
12363
|
/**
|
|
12128
|
-
* Sign an EVM adapter group
|
|
12129
|
-
* EIP-712 ECDSA signature.
|
|
12364
|
+
* Sign an EVM adapter group.
|
|
12130
12365
|
*
|
|
12131
|
-
*
|
|
12132
|
-
*
|
|
12366
|
+
* EOA intents remain batched into one EIP-712 `BurnIntentSet`. ERC-1271
|
|
12367
|
+
* intents are grouped and signed per source chain because smart accounts
|
|
12368
|
+
* commonly include `chainId` in their replay-safe signature hash.
|
|
12369
|
+
* All returned entries can still be submitted together in one atomic Gateway
|
|
12370
|
+
* transfer request.
|
|
12133
12371
|
*
|
|
12134
|
-
* Before signing,
|
|
12135
|
-
*
|
|
12136
|
-
*
|
|
12137
|
-
*
|
|
12138
|
-
*
|
|
12372
|
+
* Before signing, classifies the signer as an EOA or a contract account.
|
|
12373
|
+
* Gateway validates EOA signatures with `ecrecover` and contract-account
|
|
12374
|
+
* signatures with ERC-1271, but it does not infer which one applies — the
|
|
12375
|
+
* transfer request has to declare it. The returned `contractSigner` flag
|
|
12376
|
+
* carries that decision through to `buildTransferRequestBody`.
|
|
12139
12377
|
*
|
|
12140
12378
|
* @param group - The adapter group containing the adapter, chain, and
|
|
12141
12379
|
* burn intents to sign.
|
|
12142
|
-
* @returns
|
|
12380
|
+
* @returns Signed entries with their intents, signatures, and Gateway signer
|
|
12381
|
+
* validation mode.
|
|
12382
|
+
* @throws KitError when an intent has no source-chain mapping or a signing
|
|
12383
|
+
* action returns an invalid signature shape.
|
|
12143
12384
|
*
|
|
12144
12385
|
* @example
|
|
12145
12386
|
* ```typescript
|
|
12146
12387
|
* import { signEvmIntentGroup } from '@core/adapter-evm'
|
|
12147
12388
|
*
|
|
12148
|
-
* const
|
|
12389
|
+
* const signedSets = await signEvmIntentGroup({
|
|
12149
12390
|
* adapter: evmAdapter,
|
|
12150
12391
|
* chain: ethereumChain,
|
|
12151
12392
|
* intents: [burnIntent1, burnIntent2],
|
|
12393
|
+
* chainsByDomain: new Map([
|
|
12394
|
+
* [0, ethereumChain],
|
|
12395
|
+
* [6, baseChain],
|
|
12396
|
+
* ]),
|
|
12152
12397
|
* address: '0x...',
|
|
12153
12398
|
* })
|
|
12154
|
-
* console.log(
|
|
12399
|
+
* console.log(signedSets)
|
|
12155
12400
|
* ```
|
|
12156
12401
|
*/ async function signEvmIntentGroup(group) {
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
// Gateway verifies burn-intent signatures with plain ecrecover. An SCA
|
|
12165
|
-
// signer silently produces a signature over a wrapped hash that Gateway
|
|
12166
|
-
// cannot verify, and Circle Wallets' KMS rejects the typed data up front
|
|
12167
|
-
// with an opaque `<nil>/<nil>` error. Short-circuit with a clear message
|
|
12168
|
-
// when we can detect bytecode at the signer address. See DEVX-2774.
|
|
12169
|
-
//
|
|
12170
|
-
// Duck-typed on readBytecode rather than `instanceof EvmAdapter` because
|
|
12171
|
-
// each consumer package bundles its own copy of the base class and the
|
|
12172
|
-
// `instanceof` identity check fails across package boundaries.
|
|
12173
|
-
//
|
|
12174
|
-
// Empty string is defended against because assertSignerIsEoa would
|
|
12175
|
-
// otherwise call eth_getCode('') on the RPC.
|
|
12176
|
-
const hasResolvedSigner = typeof address === 'string' && address.length > 0;
|
|
12177
|
-
if (hasResolvedSigner && chain.type === 'evm' && isEvmAdapterLike(adapter)) {
|
|
12178
|
-
await assertSignerIsEoa(adapter, address, chain);
|
|
12179
|
-
}
|
|
12180
|
-
const firstIntent = groupIntents[0];
|
|
12181
|
-
const typedData = groupIntents.length === 1 && firstIntent ? evmSigningData(firstIntent) : evmSigningData(groupIntents);
|
|
12182
|
-
const signRequest = await adapter.prepareAction('gateway.v1.signBurnIntents', {
|
|
12183
|
-
typedData,
|
|
12184
|
-
chain
|
|
12185
|
-
}, operationContext);
|
|
12186
|
-
const sig = await signRequest.execute();
|
|
12187
|
-
return {
|
|
12188
|
-
intents: groupIntents,
|
|
12189
|
-
signature: sig
|
|
12190
|
-
};
|
|
12402
|
+
// Validate the collection before doing bytecode reads or asking a wallet
|
|
12403
|
+
// to sign. evmSigningData owns the canonical BurnIntent validation.
|
|
12404
|
+
validateGroupIntents(group.intents);
|
|
12405
|
+
const chainsByDomain = collectChainsByDomain(group);
|
|
12406
|
+
const signerTypeByDomain = await classifySignerTypes(group, chainsByDomain);
|
|
12407
|
+
const signingUnits = createSigningUnits(group, signerTypeByDomain);
|
|
12408
|
+
return await signUnits(group, signingUnits);
|
|
12191
12409
|
}
|
|
12192
12410
|
|
|
12193
12411
|
/**
|
|
12194
12412
|
* Add an EVM intent into the batched EVM group map.
|
|
12195
12413
|
*
|
|
12196
12414
|
* On EVM, all intents for the same adapter are batched into a single
|
|
12197
|
-
* group
|
|
12198
|
-
*
|
|
12415
|
+
* group. The signing step uses `chainsByDomain` to preserve EOA batching
|
|
12416
|
+
* while signing ERC-1271 intents separately on their source chains.
|
|
12199
12417
|
*
|
|
12200
12418
|
* @param intent - The burn intent to group.
|
|
12201
12419
|
* @param alloc - The allocation that resolved to this intent.
|
|
@@ -12212,6 +12430,7 @@ function evmSigningData(burnIntent) {
|
|
|
12212
12430
|
const existing = evmGroups.get(alloc.adapter);
|
|
12213
12431
|
if (existing) {
|
|
12214
12432
|
existing.intents.push(intent);
|
|
12433
|
+
existing.chainsByDomain.set(alloc.chain.gateway.domain, alloc.chain);
|
|
12215
12434
|
} else {
|
|
12216
12435
|
evmGroups.set(alloc.adapter, {
|
|
12217
12436
|
adapter: alloc.adapter,
|
|
@@ -12219,6 +12438,12 @@ function evmSigningData(burnIntent) {
|
|
|
12219
12438
|
intents: [
|
|
12220
12439
|
intent
|
|
12221
12440
|
],
|
|
12441
|
+
chainsByDomain: new Map([
|
|
12442
|
+
[
|
|
12443
|
+
alloc.chain.gateway.domain,
|
|
12444
|
+
alloc.chain
|
|
12445
|
+
]
|
|
12446
|
+
]),
|
|
12222
12447
|
address: alloc.sourceSigner
|
|
12223
12448
|
});
|
|
12224
12449
|
}
|
|
@@ -13744,7 +13969,8 @@ function throwNetworkMismatch(expected, actual) {
|
|
|
13744
13969
|
};
|
|
13745
13970
|
}
|
|
13746
13971
|
/**
|
|
13747
|
-
* Group intents
|
|
13972
|
+
* Group intents for signing (Solana one-per-intent, EVM batched by adapter
|
|
13973
|
+
* with every source chain retained by Gateway domain).
|
|
13748
13974
|
*
|
|
13749
13975
|
* @param intents - Burn intents from estimate response.
|
|
13750
13976
|
* @param allocations - Normalized allocations used to map domain → adapter/chain.
|
|
@@ -16637,22 +16863,32 @@ const DEFAULT_GAS_FEE = parseUnits('0.1', USDC_DECIMALS);
|
|
|
16637
16863
|
*
|
|
16638
16864
|
* Single-intent sets become one burnIntent + signature; multi-intent sets become burnIntentSet + signature.
|
|
16639
16865
|
*
|
|
16866
|
+
* Sets flagged `contractSigner` carry `contractSigner: true`, which tells
|
|
16867
|
+
* Gateway to validate the signature with ERC-1271 (an offchain
|
|
16868
|
+
* `isValidSignature` simulation) instead of `ecrecover`. The flag is
|
|
16869
|
+
* omitted for EOA signers so their payloads stay byte-identical.
|
|
16870
|
+
*
|
|
16640
16871
|
* @param signedSets - Signed intent sets (intents + signature per signer).
|
|
16641
16872
|
* @returns Array of transfer payloads for POST /v1/transfer.
|
|
16642
16873
|
*/ function buildTransferRequestBody(signedSets) {
|
|
16643
16874
|
return signedSets.map((set)=>{
|
|
16644
16875
|
const firstIntent = set.intents[0];
|
|
16876
|
+
const contractSigner = set.contractSigner === true ? {
|
|
16877
|
+
contractSigner: true
|
|
16878
|
+
} : {};
|
|
16645
16879
|
if (set.intents.length === 1 && firstIntent) {
|
|
16646
16880
|
return {
|
|
16647
16881
|
burnIntent: serializeBurnIntent(firstIntent),
|
|
16648
|
-
signature: set.signature
|
|
16882
|
+
signature: set.signature,
|
|
16883
|
+
...contractSigner
|
|
16649
16884
|
};
|
|
16650
16885
|
}
|
|
16651
16886
|
return {
|
|
16652
16887
|
burnIntentSet: {
|
|
16653
16888
|
intents: set.intents.map(serializeBurnIntent)
|
|
16654
16889
|
},
|
|
16655
|
-
signature: set.signature
|
|
16890
|
+
signature: set.signature,
|
|
16891
|
+
...contractSigner
|
|
16656
16892
|
};
|
|
16657
16893
|
});
|
|
16658
16894
|
}
|
|
@@ -17015,11 +17251,16 @@ const BPS_DIVISOR = 100_000n;
|
|
|
17015
17251
|
return required;
|
|
17016
17252
|
}
|
|
17017
17253
|
|
|
17254
|
+
function requireEvmChainsByDomain(group) {
|
|
17255
|
+
if (group.chainsByDomain !== undefined) return group.chainsByDomain;
|
|
17256
|
+
throw createValidationFailedError$1('adapterGroup.chainsByDomain', group.chainsByDomain, 'must be provided for an EVM adapter group');
|
|
17257
|
+
}
|
|
17018
17258
|
/**
|
|
17019
|
-
* Sign each adapter group: Solana one intent per signature, EVM
|
|
17259
|
+
* Sign each adapter group: Solana one intent per signature, and EVM either
|
|
17260
|
+
* batched for EOAs or split by source chain for ERC-1271 signers.
|
|
17020
17261
|
*
|
|
17021
17262
|
* @param adapterGroups - Groups from groupIntentsByAdapter.
|
|
17022
|
-
* @returns Promise of signed sets
|
|
17263
|
+
* @returns Promise of signed sets for buildTransferRequestBody.
|
|
17023
17264
|
*
|
|
17024
17265
|
* @example
|
|
17025
17266
|
* ```typescript
|
|
@@ -17032,9 +17273,10 @@ const BPS_DIVISOR = 100_000n;
|
|
|
17032
17273
|
if (group.chain.type === 'solana') {
|
|
17033
17274
|
return signSolanaIntentGroup(group);
|
|
17034
17275
|
}
|
|
17035
|
-
return
|
|
17036
|
-
|
|
17037
|
-
|
|
17276
|
+
return await signEvmIntentGroup({
|
|
17277
|
+
...group,
|
|
17278
|
+
chainsByDomain: requireEvmChainsByDomain(group)
|
|
17279
|
+
});
|
|
17038
17280
|
}));
|
|
17039
17281
|
return nested.flat();
|
|
17040
17282
|
}
|
|
@@ -17684,7 +17926,8 @@ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, s
|
|
|
17684
17926
|
signedSetCount: signedSets.length,
|
|
17685
17927
|
signatures: signedSets.map((s)=>({
|
|
17686
17928
|
intentCount: s.intents.length,
|
|
17687
|
-
signature: s.signature
|
|
17929
|
+
signature: s.signature,
|
|
17930
|
+
contractSigner: s.contractSigner === true
|
|
17688
17931
|
}))
|
|
17689
17932
|
}
|
|
17690
17933
|
});
|
|
@@ -20429,7 +20672,11 @@ const removeFundParamsSchema = zod.z.object({
|
|
|
20429
20672
|
// Remove Fund Operations
|
|
20430
20673
|
// ---------------------------------------------------------------------------
|
|
20431
20674
|
/**
|
|
20432
|
-
* Kick off a delayed fund removal from an account.
|
|
20675
|
+
* Kick off a delayed recovery fund removal from an account.
|
|
20676
|
+
*
|
|
20677
|
+
* Use `initiateRemoveFund` only as a trustless fallback when the normal spend
|
|
20678
|
+
* flow is unavailable. For day-to-day movement out of a Unified Balance, use
|
|
20679
|
+
* `spend`.
|
|
20433
20680
|
*
|
|
20434
20681
|
* Validates `from` and `amount`, resolves the chain and token via
|
|
20435
20682
|
* {@link resolveRemoveFundParams}, selects the matching provider, then calls
|
|
@@ -20466,7 +20713,10 @@ const removeFundParamsSchema = zod.z.object({
|
|
|
20466
20713
|
return provider.initiateRemoveFund(resolved);
|
|
20467
20714
|
}
|
|
20468
20715
|
/**
|
|
20469
|
-
* Complete a fund removal once the 7-day
|
|
20716
|
+
* Complete a recovery fund removal once the 7-day withdrawal delay has passed.
|
|
20717
|
+
*
|
|
20718
|
+
* Use `removeFund` only as a trustless fallback when the normal spend flow is
|
|
20719
|
+
* unavailable. For day-to-day movement out of a Unified Balance, use `spend`.
|
|
20470
20720
|
*
|
|
20471
20721
|
* Validates `from`, resolves the chain and token via
|
|
20472
20722
|
* {@link resolveRemoveFundParams}, selects the matching provider, then calls
|
|
@@ -20555,13 +20805,18 @@ const removeFundParamsSchema = zod.z.object({
|
|
|
20555
20805
|
/** SDK name used in telemetry payloads. */ const SDK_NAME = resolveKitSdkName(pkg.name);
|
|
20556
20806
|
/**
|
|
20557
20807
|
* A high-level class-based interface for cross-chain USDC deposits,
|
|
20558
|
-
* spending, balance queries, delegation management, and
|
|
20808
|
+
* spending, balance queries, delegation management, and recovery fund removals.
|
|
20559
20809
|
*
|
|
20560
20810
|
* UnifiedBalanceKit provides a familiar class-based API for developers who
|
|
20561
20811
|
* prefer traditional object-oriented patterns. The class maintains an
|
|
20562
20812
|
* internal context and provides methods that delegate to the standalone
|
|
20563
20813
|
* operation functions exported by this package.
|
|
20564
20814
|
*
|
|
20815
|
+
* Use `spend` for normal movement out of a Unified Balance. `removeFund` is a
|
|
20816
|
+
* trustless recovery path for situations where the normal spend flow is
|
|
20817
|
+
* unavailable, and it requires a 7-day withdrawal delay before funds can be
|
|
20818
|
+
* removed.
|
|
20819
|
+
*
|
|
20565
20820
|
* @remarks
|
|
20566
20821
|
* For functional usage, import and use the operations directly:
|
|
20567
20822
|
* ```typescript
|
|
@@ -20782,7 +21037,11 @@ const removeFundParamsSchema = zod.z.object({
|
|
|
20782
21037
|
});
|
|
20783
21038
|
}
|
|
20784
21039
|
/**
|
|
20785
|
-
* Kick off a delayed fund removal from an account.
|
|
21040
|
+
* Kick off a delayed recovery fund removal from an account.
|
|
21041
|
+
*
|
|
21042
|
+
* Use this only as a trustless fallback when the normal spend flow is
|
|
21043
|
+
* unavailable. For day-to-day movement out of a Unified Balance, use
|
|
21044
|
+
* `spend`.
|
|
20786
21045
|
*
|
|
20787
21046
|
* @param params - The account owner's adapter context, amount, and
|
|
20788
21047
|
* optional token type.
|
|
@@ -20796,7 +21055,12 @@ const removeFundParamsSchema = zod.z.object({
|
|
|
20796
21055
|
});
|
|
20797
21056
|
}
|
|
20798
21057
|
/**
|
|
20799
|
-
* Complete a fund removal once the
|
|
21058
|
+
* Complete a recovery fund removal once the 7-day withdrawal delay has
|
|
21059
|
+
* passed.
|
|
21060
|
+
*
|
|
21061
|
+
* Use this only as a trustless fallback when the normal spend flow is
|
|
21062
|
+
* unavailable. For day-to-day movement out of a Unified Balance, use
|
|
21063
|
+
* `spend`.
|
|
20800
21064
|
*
|
|
20801
21065
|
* @param params - The account owner context matching the original
|
|
20802
21066
|
* fund removal initiation.
|
|
@@ -20923,6 +21187,11 @@ registerKit(`${pkg.name}/${pkg.version}`);
|
|
|
20923
21187
|
* Internally holds a persistent {@link UnifiedBalanceKit} instance so that
|
|
20924
21188
|
* event dispatchers and custom fee policies are preserved across calls.
|
|
20925
21189
|
*
|
|
21190
|
+
* Use {@link AppKitUnifiedBalance.spend} for normal movement out of a Unified
|
|
21191
|
+
* Balance. {@link AppKitUnifiedBalance.removeFund} is a trustless recovery path
|
|
21192
|
+
* for situations where the normal spend flow is unavailable, and it requires a
|
|
21193
|
+
* 7-day withdrawal delay after {@link AppKitUnifiedBalance.initiateRemoveFund}.
|
|
21194
|
+
*
|
|
20926
21195
|
* @example
|
|
20927
21196
|
* ```typescript
|
|
20928
21197
|
* import { AppKit } from '@circle-fin/app-kit'
|
|
@@ -21134,7 +21403,12 @@ registerKit(`${pkg.name}/${pkg.version}`);
|
|
|
21134
21403
|
return this.kit.removeDelegate(params);
|
|
21135
21404
|
}
|
|
21136
21405
|
/**
|
|
21137
|
-
*
|
|
21406
|
+
* Initiate a trustless recovery removal from an account.
|
|
21407
|
+
*
|
|
21408
|
+
* Use `spend` for normal movement out of a Unified Balance. `removeFund` is a
|
|
21409
|
+
* recovery path for situations where the normal spend flow is unavailable.
|
|
21410
|
+
* Calling this method starts the 7-day withdrawal delay before the removal can
|
|
21411
|
+
* be completed.
|
|
21138
21412
|
*
|
|
21139
21413
|
* @param params - The account owner's adapter context, amount, and token.
|
|
21140
21414
|
* @returns Promise resolving to the initiation details.
|
|
@@ -21153,11 +21427,16 @@ registerKit(`${pkg.name}/${pkg.version}`);
|
|
|
21153
21427
|
return this.kit.initiateRemoveFund(params);
|
|
21154
21428
|
}
|
|
21155
21429
|
/**
|
|
21156
|
-
* Complete a
|
|
21430
|
+
* Complete a trustless recovery removal after the withdrawal delay.
|
|
21431
|
+
*
|
|
21432
|
+
* Use `spend` for normal movement out of a Unified Balance. `removeFund` is a
|
|
21433
|
+
* recovery path for situations where the normal spend flow is unavailable.
|
|
21434
|
+
* Both EVM and Solana removals require a 7-day withdrawal delay after
|
|
21435
|
+
* `initiateRemoveFund` before funds can be removed.
|
|
21157
21436
|
*
|
|
21158
21437
|
* @param params - The account owner context matching the original initiation.
|
|
21159
21438
|
* @returns Promise resolving to the fund removal details.
|
|
21160
|
-
* @throws {KitError} If the
|
|
21439
|
+
* @throws {KitError} If the withdrawal delay has not elapsed or the
|
|
21161
21440
|
* on-chain transaction fails.
|
|
21162
21441
|
*
|
|
21163
21442
|
* @example
|