@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.mjs
CHANGED
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
// Buffer polyfill setup - executes before any other code
|
|
20
|
+
// Ensures globalThis.Buffer is available for Solana libraries
|
|
21
|
+
import { Buffer } from 'buffer';
|
|
22
|
+
if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
|
|
23
|
+
globalThis.Buffer = Buffer;
|
|
24
|
+
}
|
|
25
|
+
if (typeof window !== 'undefined' && typeof window.Buffer === 'undefined') {
|
|
26
|
+
window.Buffer = Buffer;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
19
30
|
import { z } from 'zod';
|
|
20
31
|
import { PublicKey } from '@solana/web3.js';
|
|
21
32
|
import 'bn.js';
|
|
@@ -41,6 +52,27 @@ import { getAddress } from '@ethersproject/address';
|
|
|
41
52
|
* }
|
|
42
53
|
* ```
|
|
43
54
|
*/ const isNodeEnvironment = ()=>typeof process !== 'undefined' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
|
|
55
|
+
/**
|
|
56
|
+
* Return the SDK User-Agent request header only when running in Node.js.
|
|
57
|
+
*
|
|
58
|
+
* Browsers forbid manually setting `User-Agent`, and a custom fallback header
|
|
59
|
+
* can trigger CORS preflight. Non-Node server runtimes also omit this optional
|
|
60
|
+
* attribution header because they cannot set it reliably.
|
|
61
|
+
*
|
|
62
|
+
* @returns A User-Agent header in Node.js, or an empty object otherwise.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* import { getNodeUserAgentHeader } from '@core/utils'
|
|
67
|
+
*
|
|
68
|
+
* const headers = {
|
|
69
|
+
* 'Content-Type': 'application/json',
|
|
70
|
+
* ...getNodeUserAgentHeader(),
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/ const getNodeUserAgentHeader = ()=>isNodeEnvironment() ? {
|
|
74
|
+
'User-Agent': getUserAgent()
|
|
75
|
+
} : {};
|
|
44
76
|
/**
|
|
45
77
|
* Detect the runtime environment and return a shortened identifier.
|
|
46
78
|
*
|
|
@@ -626,11 +658,6 @@ class KitError extends Error {
|
|
|
626
658
|
name: 'INPUT_UNSUPPORTED_TOKEN',
|
|
627
659
|
type: 'INPUT'
|
|
628
660
|
},
|
|
629
|
-
/** Action not supported by this adapter / ecosystem */ UNSUPPORTED_ACTION: {
|
|
630
|
-
code: 1008,
|
|
631
|
-
name: 'INPUT_UNSUPPORTED_ACTION',
|
|
632
|
-
type: 'INPUT'
|
|
633
|
-
},
|
|
634
661
|
/** No route satisfies the slippage or minimum-output constraint */ SLIPPAGE_CONSTRAINT_NOT_MET: {
|
|
635
662
|
code: 1009,
|
|
636
663
|
name: 'INPUT_SLIPPAGE_CONSTRAINT_NOT_MET',
|
|
@@ -2287,6 +2314,8 @@ class KitError extends Error {
|
|
|
2287
2314
|
Blockchain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
|
|
2288
2315
|
Blockchain["XDC"] = "XDC";
|
|
2289
2316
|
Blockchain["XDC_Apothem"] = "XDC_Apothem";
|
|
2317
|
+
Blockchain["X_Layer"] = "X_Layer";
|
|
2318
|
+
Blockchain["X_Layer_Testnet"] = "X_Layer_Testnet";
|
|
2290
2319
|
Blockchain["ZKSync_Era"] = "ZKSync_Era";
|
|
2291
2320
|
Blockchain["ZKSync_Sepolia"] = "ZKSync_Sepolia";
|
|
2292
2321
|
})(Blockchain || (Blockchain = {}));
|
|
@@ -2340,6 +2369,7 @@ var BridgeChain;
|
|
|
2340
2369
|
BridgeChain["Unichain"] = "Unichain";
|
|
2341
2370
|
BridgeChain["World_Chain"] = "World_Chain";
|
|
2342
2371
|
BridgeChain["XDC"] = "XDC";
|
|
2372
|
+
BridgeChain["X_Layer"] = "X_Layer";
|
|
2343
2373
|
// Testnet chains with CCTPv2 support
|
|
2344
2374
|
BridgeChain["Arc_Testnet"] = "Arc_Testnet";
|
|
2345
2375
|
BridgeChain["Arbitrum_Sepolia"] = "Arbitrum_Sepolia";
|
|
@@ -2365,6 +2395,7 @@ var BridgeChain;
|
|
|
2365
2395
|
BridgeChain["Unichain_Sepolia"] = "Unichain_Sepolia";
|
|
2366
2396
|
BridgeChain["World_Chain_Sepolia"] = "World_Chain_Sepolia";
|
|
2367
2397
|
BridgeChain["XDC_Apothem"] = "XDC_Apothem";
|
|
2398
|
+
BridgeChain["X_Layer_Testnet"] = "X_Layer_Testnet";
|
|
2368
2399
|
})(BridgeChain || (BridgeChain = {}));
|
|
2369
2400
|
var UnifiedBalanceChain;
|
|
2370
2401
|
(function(UnifiedBalanceChain) {
|
|
@@ -4912,7 +4943,8 @@ var EarnChain;
|
|
|
4912
4943
|
isTestnet: true,
|
|
4913
4944
|
explorerUrl: 'https://amoy.polygonscan.com/tx/{hash}',
|
|
4914
4945
|
rpcEndpoints: [
|
|
4915
|
-
'https://
|
|
4946
|
+
'https://polygon-amoy-bor-rpc.publicnode.com',
|
|
4947
|
+
'https://polygon-amoy.drpc.org'
|
|
4916
4948
|
],
|
|
4917
4949
|
eurcAddress: null,
|
|
4918
4950
|
usdcAddress: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
|
|
@@ -5777,6 +5809,104 @@ var EarnChain;
|
|
|
5777
5809
|
}
|
|
5778
5810
|
});
|
|
5779
5811
|
|
|
5812
|
+
/**
|
|
5813
|
+
* X Layer Mainnet chain definition
|
|
5814
|
+
* @remarks
|
|
5815
|
+
* This represents the official production network for the X Layer blockchain.
|
|
5816
|
+
* X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
|
|
5817
|
+
* using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
|
|
5818
|
+
* OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
|
|
5819
|
+
*/ const XLayer = defineChain({
|
|
5820
|
+
type: 'evm',
|
|
5821
|
+
chain: Blockchain.X_Layer,
|
|
5822
|
+
name: 'X Layer',
|
|
5823
|
+
title: 'X Layer Mainnet',
|
|
5824
|
+
nativeCurrency: {
|
|
5825
|
+
name: 'OKB',
|
|
5826
|
+
symbol: 'OKB',
|
|
5827
|
+
decimals: 18
|
|
5828
|
+
},
|
|
5829
|
+
chainId: 196,
|
|
5830
|
+
isTestnet: false,
|
|
5831
|
+
explorerUrl: 'https://www.oklink.com/xlayer/tx/{hash}',
|
|
5832
|
+
rpcEndpoints: [
|
|
5833
|
+
'https://xlayerrpc.okx.com'
|
|
5834
|
+
],
|
|
5835
|
+
eurcAddress: null,
|
|
5836
|
+
usdcAddress: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
|
|
5837
|
+
usdtAddress: null,
|
|
5838
|
+
cctp: {
|
|
5839
|
+
domain: 37,
|
|
5840
|
+
contracts: {
|
|
5841
|
+
v2: {
|
|
5842
|
+
type: 'split',
|
|
5843
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
5844
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
5845
|
+
confirmations: 65,
|
|
5846
|
+
fastConfirmations: 1
|
|
5847
|
+
}
|
|
5848
|
+
},
|
|
5849
|
+
forwarderSupported: {
|
|
5850
|
+
source: false,
|
|
5851
|
+
destination: false
|
|
5852
|
+
}
|
|
5853
|
+
},
|
|
5854
|
+
kitContracts: {
|
|
5855
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
5856
|
+
}
|
|
5857
|
+
});
|
|
5858
|
+
|
|
5859
|
+
/**
|
|
5860
|
+
* X Layer Testnet chain definition
|
|
5861
|
+
* @remarks
|
|
5862
|
+
* This represents the official test network for the X Layer blockchain.
|
|
5863
|
+
* X Layer is an EVM-compatible OP Stack Layer-2 blockchain built by OKX,
|
|
5864
|
+
* using OKB as its native gas token. (Migrated from Polygon zkEVM/CDK to the
|
|
5865
|
+
* OP Stack on 2025-10-27; older docs describing it as zkEVM are obsolete.)
|
|
5866
|
+
*/ const XLayerTestnet = defineChain({
|
|
5867
|
+
type: 'evm',
|
|
5868
|
+
chain: Blockchain.X_Layer_Testnet,
|
|
5869
|
+
name: 'X Layer Testnet',
|
|
5870
|
+
title: 'X Layer Testnet',
|
|
5871
|
+
nativeCurrency: {
|
|
5872
|
+
name: 'OKB',
|
|
5873
|
+
symbol: 'OKB',
|
|
5874
|
+
decimals: 18
|
|
5875
|
+
},
|
|
5876
|
+
chainId: 1952,
|
|
5877
|
+
isTestnet: true,
|
|
5878
|
+
// Deliberately not oklink.com (used for mainnet): viem's bundled OKLink
|
|
5879
|
+
// testnet URL targets the deprecated pre-rebrand chain ID 195, not this
|
|
5880
|
+
// chain's ID (1952). Verified against the internal chain-expansion-scripts
|
|
5881
|
+
// config (`v2config.sandbox.yml`) — do not "normalize" this to match mainnet.
|
|
5882
|
+
explorerUrl: 'https://web3.okx.com/explorer/x-layer-testnet/tx/{hash}',
|
|
5883
|
+
rpcEndpoints: [
|
|
5884
|
+
'https://testrpc.xlayer.tech'
|
|
5885
|
+
],
|
|
5886
|
+
eurcAddress: null,
|
|
5887
|
+
usdcAddress: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
|
|
5888
|
+
usdtAddress: null,
|
|
5889
|
+
cctp: {
|
|
5890
|
+
domain: 37,
|
|
5891
|
+
contracts: {
|
|
5892
|
+
v2: {
|
|
5893
|
+
type: 'split',
|
|
5894
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5895
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5896
|
+
confirmations: 65,
|
|
5897
|
+
fastConfirmations: 1
|
|
5898
|
+
}
|
|
5899
|
+
},
|
|
5900
|
+
forwarderSupported: {
|
|
5901
|
+
source: false,
|
|
5902
|
+
destination: false
|
|
5903
|
+
}
|
|
5904
|
+
},
|
|
5905
|
+
kitContracts: {
|
|
5906
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
5907
|
+
}
|
|
5908
|
+
});
|
|
5909
|
+
|
|
5780
5910
|
/**
|
|
5781
5911
|
* ZKSync Era Mainnet chain definition
|
|
5782
5912
|
* @remarks
|
|
@@ -5896,6 +6026,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
5896
6026
|
WorldChainSepolia: WorldChainSepolia,
|
|
5897
6027
|
XDC: XDC,
|
|
5898
6028
|
XDCApothem: XDCApothem,
|
|
6029
|
+
XLayer: XLayer,
|
|
6030
|
+
XLayerTestnet: XLayerTestnet,
|
|
5899
6031
|
ZKSyncEra: ZKSyncEra,
|
|
5900
6032
|
ZKSyncEraSepolia: ZKSyncEraSepolia
|
|
5901
6033
|
});
|
|
@@ -7080,13 +7212,12 @@ const swapTokenEnumSchema = z.enum([
|
|
|
7080
7212
|
headers: {
|
|
7081
7213
|
...DEFAULT_CONFIG.headers,
|
|
7082
7214
|
...config.headers ?? {},
|
|
7083
|
-
//
|
|
7084
|
-
//
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
}
|
|
7215
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
7216
|
+
// fallback header the SDK used instead trips CORS preflight against the
|
|
7217
|
+
// Circle APIs (it isn't in their `Access-Control-Allow-Headers`),
|
|
7218
|
+
// blocking the request. So send the SDK user agent only in Node;
|
|
7219
|
+
// browsers omit it entirely.
|
|
7220
|
+
...getNodeUserAgentHeader()
|
|
7090
7221
|
}
|
|
7091
7222
|
};
|
|
7092
7223
|
let lastError;
|
|
@@ -7849,6 +7980,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
7849
7980
|
[Blockchain.Unichain]: '0x078D782b760474a361dDA0AF3839290b0EF57AD6',
|
|
7850
7981
|
[Blockchain.World_Chain]: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1',
|
|
7851
7982
|
[Blockchain.XDC]: '0xfA2958CB79b0491CC627c1557F441eF849Ca8eb1',
|
|
7983
|
+
[Blockchain.X_Layer]: '0xB6CEceAB302E2E4948951eE7843FC24E92933061',
|
|
7852
7984
|
[Blockchain.ZKSync_Era]: '0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4',
|
|
7853
7985
|
// =========================================================================
|
|
7854
7986
|
// Testnets (alphabetically sorted)
|
|
@@ -7883,6 +8015,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
7883
8015
|
[Blockchain.Unichain_Sepolia]: '0x31d0220469e10c4E71834a79b1f276d740d3768F',
|
|
7884
8016
|
[Blockchain.World_Chain_Sepolia]: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88',
|
|
7885
8017
|
[Blockchain.XDC_Apothem]: '0xb5AB69F7bBada22B28e79C8FFAECe55eF1c771D4',
|
|
8018
|
+
[Blockchain.X_Layer_Testnet]: '0xDec90b78111Ba2fc6FC6d84d8B9ec159A2d4b9B3',
|
|
7886
8019
|
[Blockchain.ZKSync_Sepolia]: '0xAe045DE5638162fa134807Cb558E15A3F5A7F853'
|
|
7887
8020
|
}
|
|
7888
8021
|
};
|
|
@@ -8358,6 +8491,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
8358
8491
|
if (payload.tokenIn !== undefined) safe['tokenIn'] = payload.tokenIn;
|
|
8359
8492
|
if (payload.tokenOut !== undefined) safe['tokenOut'] = payload.tokenOut;
|
|
8360
8493
|
if (payload.txHash !== undefined) safe['txHash'] = payload.txHash;
|
|
8494
|
+
if (payload.correlationId !== undefined) safe['correlationId'] = payload.correlationId;
|
|
8361
8495
|
if (payload.errorDetails !== undefined) {
|
|
8362
8496
|
const errorDetails = {
|
|
8363
8497
|
...payload.errorDetails.errorCode !== undefined && {
|
|
@@ -8428,18 +8562,15 @@ function parseOrThrow(value, schema, context) {
|
|
|
8428
8562
|
timeoutHandle.unref();
|
|
8429
8563
|
}
|
|
8430
8564
|
try {
|
|
8431
|
-
const isNode = isNodeEnvironment();
|
|
8432
|
-
const userAgent = getUserAgent();
|
|
8433
8565
|
await fetch(getLogsUrl(), {
|
|
8434
8566
|
method: 'POST',
|
|
8435
8567
|
headers: {
|
|
8436
8568
|
'Content-Type': 'application/json',
|
|
8437
|
-
//
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
}
|
|
8569
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
8570
|
+
// fallback header the SDK used instead trips CORS preflight (it isn't
|
|
8571
|
+
// in the telemetry endpoint's `Access-Control-Allow-Headers`), so send
|
|
8572
|
+
// it only in Node; browsers omit it entirely.
|
|
8573
|
+
...getNodeUserAgentHeader()
|
|
8443
8574
|
},
|
|
8444
8575
|
body: JSON.stringify(toSafePayload(payload)),
|
|
8445
8576
|
signal: controller.signal
|
|
@@ -8652,7 +8783,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
8652
8783
|
// discards the stack trace, nested `cause`, and any custom Error
|
|
8653
8784
|
// properties — exactly the context an on-call needs when a
|
|
8654
8785
|
// resolver-closure regression triggers this path.
|
|
8655
|
-
console.warn(`[stablecoin-kits telemetry] dropped
|
|
8786
|
+
console.warn(`[stablecoin-kits telemetry] dropped event '${eventType}':`, cause);
|
|
8656
8787
|
} catch {
|
|
8657
8788
|
// console.warn itself throwing is the user's environment; nothing more we
|
|
8658
8789
|
// can do without risking the original operation error.
|
|
@@ -8668,7 +8799,9 @@ function parseOrThrow(value, schema, context) {
|
|
|
8668
8799
|
sdkVersion: config.sdkVersion,
|
|
8669
8800
|
eventType,
|
|
8670
8801
|
timestamp: new Date().toISOString(),
|
|
8671
|
-
errorDetails
|
|
8802
|
+
...errorDetails !== undefined && {
|
|
8803
|
+
errorDetails
|
|
8804
|
+
},
|
|
8672
8805
|
clientContext: buildClientContext(),
|
|
8673
8806
|
...context?.sourceChain != null && {
|
|
8674
8807
|
sourceChain: context.sourceChain
|
|
@@ -8684,6 +8817,9 @@ function parseOrThrow(value, schema, context) {
|
|
|
8684
8817
|
},
|
|
8685
8818
|
...context?.txHash != null && {
|
|
8686
8819
|
txHash: context.txHash
|
|
8820
|
+
},
|
|
8821
|
+
...context?.correlationId != null && {
|
|
8822
|
+
correlationId: context.correlationId
|
|
8687
8823
|
}
|
|
8688
8824
|
};
|
|
8689
8825
|
}
|
|
@@ -8745,7 +8881,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
8745
8881
|
}
|
|
8746
8882
|
|
|
8747
8883
|
var name = "@circle-fin/unified-balance-kit";
|
|
8748
|
-
var version = "1.
|
|
8884
|
+
var version = "1.4.0";
|
|
8749
8885
|
var pkg = {
|
|
8750
8886
|
name: name,
|
|
8751
8887
|
version: version};
|
|
@@ -12026,72 +12162,55 @@ function evmSigningData(burnIntent) {
|
|
|
12026
12162
|
* `0xef0100` followed by the 20-byte delegate address (23 bytes total).
|
|
12027
12163
|
* The underlying secp256k1 key still produces `ecrecover`-verifiable
|
|
12028
12164
|
* signatures, so for Gateway's purposes a 7702-delegated address is
|
|
12029
|
-
* an EOA, not
|
|
12165
|
+
* an EOA, not a contract signer.
|
|
12030
12166
|
*
|
|
12031
12167
|
* Spec: https://eips.ethereum.org/EIPS/eip-7702
|
|
12032
12168
|
*/ const EIP_7702_DELEGATION_PREFIX = '0xef0100';
|
|
12033
12169
|
/**
|
|
12034
|
-
*
|
|
12170
|
+
* Determine whether `address` on `chain` signs as a contract (ERC-1271)
|
|
12171
|
+
* rather than as an EOA.
|
|
12035
12172
|
*
|
|
12036
|
-
* Gateway
|
|
12037
|
-
* `
|
|
12038
|
-
*
|
|
12039
|
-
* ERC-
|
|
12040
|
-
*
|
|
12041
|
-
* against Gateway's chainId-less domain with an opaque
|
|
12042
|
-
* `invalid integer value <nil>/<nil> for type uint256` error.
|
|
12173
|
+
* Gateway validates burn-intent signatures two ways: a static `ecrecover`
|
|
12174
|
+
* check for EOAs, and — for requests that carry `contractSigner: true` —
|
|
12175
|
+
* an offchain `isValidSignature` simulation against the signing contract
|
|
12176
|
+
* (ERC-1271). Gateway does not infer which one to use, so the caller must
|
|
12177
|
+
* declare it. This detects the contract case from on-chain bytecode.
|
|
12043
12178
|
*
|
|
12044
|
-
* EIP-7702-delegated EOAs are
|
|
12045
|
-
* (`0xef0100<delegate>`) but the underlying secp256k1 key still
|
|
12046
|
-
* `ecrecover`-verifiable signatures, so
|
|
12179
|
+
* EIP-7702-delegated EOAs are treated as EOAs: they expose non-empty
|
|
12180
|
+
* bytecode (`0xef0100<delegate>`) but the underlying secp256k1 key still
|
|
12181
|
+
* produces `ecrecover`-verifiable signatures, so the cheaper EOA path
|
|
12182
|
+
* stays correct for them.
|
|
12047
12183
|
*
|
|
12048
|
-
*
|
|
12049
|
-
*
|
|
12050
|
-
*
|
|
12051
|
-
*
|
|
12052
|
-
* docs for the exact API.
|
|
12053
|
-
*
|
|
12054
|
-
* If bytecode cannot be read (RPC failure, etc.) the pre-check is
|
|
12055
|
-
* skipped and downstream signing surfaces its own error — a warning is
|
|
12056
|
-
* logged so the skip is diagnosable.
|
|
12184
|
+
* If bytecode cannot be read (RPC failure, etc.) the address is reported
|
|
12185
|
+
* as an EOA and a warning is logged so the fallback is diagnosable. A
|
|
12186
|
+
* genuine contract signer misreported this way is rejected by Gateway with
|
|
12187
|
+
* an invalid-signature error rather than silently mis-attested.
|
|
12057
12188
|
*
|
|
12058
12189
|
* @param adapter - Anything exposing {@link EvmAdapterLike.readBytecode}.
|
|
12059
|
-
* @param address - Signer address to
|
|
12190
|
+
* @param address - Signer address to classify.
|
|
12060
12191
|
* @param chain - EVM chain where the signer lives.
|
|
12061
|
-
* @
|
|
12192
|
+
* @returns `true` when the signer is a contract account and the transfer
|
|
12193
|
+
* request must set `contractSigner: true`; `false` otherwise.
|
|
12062
12194
|
*
|
|
12063
12195
|
* @example
|
|
12064
12196
|
* ```typescript
|
|
12065
|
-
* import {
|
|
12197
|
+
* import { isContractSigner } from '@core/adapter-evm'
|
|
12066
12198
|
* import { Ethereum } from '@core/chains'
|
|
12067
12199
|
*
|
|
12068
|
-
* await
|
|
12200
|
+
* const useErc1271 = await isContractSigner(adapter, '0xabc...', Ethereum)
|
|
12069
12201
|
* ```
|
|
12070
|
-
*/ async function
|
|
12202
|
+
*/ async function isContractSigner(adapter, address, chain) {
|
|
12071
12203
|
let code;
|
|
12072
12204
|
try {
|
|
12073
12205
|
code = await adapter.readBytecode(address, chain);
|
|
12074
12206
|
} catch (err) {
|
|
12075
|
-
console.warn(`[gateway]
|
|
12076
|
-
return;
|
|
12207
|
+
console.warn(`[gateway] isContractSigner defaulting to EOA (readBytecode failed ` + `for ${address} on ${chain.name}): ` + (err instanceof Error ? err.message : String(err)));
|
|
12208
|
+
return false;
|
|
12077
12209
|
}
|
|
12078
12210
|
if (code === undefined || code === '0x' || code.toLowerCase().startsWith(EIP_7702_DELEGATION_PREFIX)) {
|
|
12079
|
-
return;
|
|
12211
|
+
return false;
|
|
12080
12212
|
}
|
|
12081
|
-
|
|
12082
|
-
...InputError.UNSUPPORTED_ACTION,
|
|
12083
|
-
recoverability: 'FATAL',
|
|
12084
|
-
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.`,
|
|
12085
|
-
cause: {
|
|
12086
|
-
trace: {
|
|
12087
|
-
operation: 'signEvmIntentGroup.assertSignerIsEoa',
|
|
12088
|
-
address,
|
|
12089
|
-
chain: chain.name,
|
|
12090
|
-
bytecodeBytes: (code.length - 2) / 2,
|
|
12091
|
-
bytecodePrefix: code.slice(0, 12)
|
|
12092
|
-
}
|
|
12093
|
-
}
|
|
12094
|
-
});
|
|
12213
|
+
return true;
|
|
12095
12214
|
}
|
|
12096
12215
|
|
|
12097
12216
|
/**
|
|
@@ -12118,78 +12237,177 @@ function evmSigningData(burnIntent) {
|
|
|
12118
12237
|
return typeof value === 'object' && value !== null && 'readBytecode' in value && typeof value.readBytecode === 'function';
|
|
12119
12238
|
}
|
|
12120
12239
|
|
|
12240
|
+
function resolveIntentChain(group, intent) {
|
|
12241
|
+
const sourceDomain = intent.spec.sourceDomain;
|
|
12242
|
+
const chain = group.chainsByDomain.get(sourceDomain);
|
|
12243
|
+
if (chain !== undefined) return chain;
|
|
12244
|
+
throw createValidationFailedError$1('intent.spec.sourceDomain', sourceDomain, `No source chain found for Gateway domain ${String(sourceDomain)}`);
|
|
12245
|
+
}
|
|
12246
|
+
function normalizeSignatureResult(result) {
|
|
12247
|
+
if (typeof result === 'string') {
|
|
12248
|
+
return {
|
|
12249
|
+
signature: result,
|
|
12250
|
+
contractSigner: false
|
|
12251
|
+
};
|
|
12252
|
+
}
|
|
12253
|
+
if (typeof result === 'object' && result !== null && 'signature' in result && typeof result.signature === 'string') {
|
|
12254
|
+
return {
|
|
12255
|
+
signature: result.signature,
|
|
12256
|
+
contractSigner: 'contractSigner' in result && result.contractSigner === true
|
|
12257
|
+
};
|
|
12258
|
+
}
|
|
12259
|
+
throw createValidationFailedError$1('signature', result, 'must be a signature string or an object containing a signature string');
|
|
12260
|
+
}
|
|
12261
|
+
function validateGroupIntents(intents) {
|
|
12262
|
+
evmSigningData(intents);
|
|
12263
|
+
}
|
|
12264
|
+
function collectChainsByDomain(group) {
|
|
12265
|
+
const chainsByDomain = new Map();
|
|
12266
|
+
for (const intent of group.intents){
|
|
12267
|
+
chainsByDomain.set(intent.spec.sourceDomain, resolveIntentChain(group, intent));
|
|
12268
|
+
}
|
|
12269
|
+
return chainsByDomain;
|
|
12270
|
+
}
|
|
12271
|
+
async function classifySignerTypes(group, chainsByDomain) {
|
|
12272
|
+
const { adapter, address } = group;
|
|
12273
|
+
// Duck-typed on readBytecode rather than `instanceof EvmAdapter` because
|
|
12274
|
+
// each consumer package bundles its own copy of the base class and the
|
|
12275
|
+
// `instanceof` identity check fails across package boundaries.
|
|
12276
|
+
// Empty strings are rejected to avoid calling eth_getCode('') on the RPC.
|
|
12277
|
+
const hasResolvedSigner = typeof address === 'string' && address.length > 0;
|
|
12278
|
+
const signerTypes = await Promise.all([
|
|
12279
|
+
...chainsByDomain
|
|
12280
|
+
].map(async ([sourceDomain, sourceChain])=>{
|
|
12281
|
+
const contractSigner = hasResolvedSigner && sourceChain.type === 'evm' && isEvmAdapterLike(adapter) ? await isContractSigner(adapter, address, sourceChain) : false;
|
|
12282
|
+
return [
|
|
12283
|
+
sourceDomain,
|
|
12284
|
+
contractSigner
|
|
12285
|
+
];
|
|
12286
|
+
}));
|
|
12287
|
+
return new Map(signerTypes);
|
|
12288
|
+
}
|
|
12289
|
+
function createSigningUnits(group, signerTypeByDomain) {
|
|
12290
|
+
const contractUnitsByDomain = new Map();
|
|
12291
|
+
let eoaUnit;
|
|
12292
|
+
for (const [index, intent] of group.intents.entries()){
|
|
12293
|
+
const sourceDomain = intent.spec.sourceDomain;
|
|
12294
|
+
const contractSigner = signerTypeByDomain.get(sourceDomain) ?? false;
|
|
12295
|
+
if (contractSigner) {
|
|
12296
|
+
const existingUnit = contractUnitsByDomain.get(sourceDomain);
|
|
12297
|
+
if (existingUnit === undefined) {
|
|
12298
|
+
contractUnitsByDomain.set(sourceDomain, {
|
|
12299
|
+
intents: [
|
|
12300
|
+
intent
|
|
12301
|
+
],
|
|
12302
|
+
chain: resolveIntentChain(group, intent),
|
|
12303
|
+
contractSigner: true,
|
|
12304
|
+
firstIntentIndex: index
|
|
12305
|
+
});
|
|
12306
|
+
} else {
|
|
12307
|
+
existingUnit.intents.push(intent);
|
|
12308
|
+
}
|
|
12309
|
+
} else {
|
|
12310
|
+
eoaUnit ??= {
|
|
12311
|
+
intents: [],
|
|
12312
|
+
chain: resolveIntentChain(group, intent),
|
|
12313
|
+
contractSigner: false,
|
|
12314
|
+
firstIntentIndex: index
|
|
12315
|
+
};
|
|
12316
|
+
eoaUnit.intents.push(intent);
|
|
12317
|
+
}
|
|
12318
|
+
}
|
|
12319
|
+
const signingUnits = [
|
|
12320
|
+
...contractUnitsByDomain.values()
|
|
12321
|
+
];
|
|
12322
|
+
if (eoaUnit !== undefined) signingUnits.push(eoaUnit);
|
|
12323
|
+
signingUnits.sort((a, b)=>a.firstIntentIndex - b.firstIntentIndex);
|
|
12324
|
+
return signingUnits;
|
|
12325
|
+
}
|
|
12326
|
+
async function signUnit(group, unit) {
|
|
12327
|
+
const { adapter, address } = group;
|
|
12328
|
+
const firstIntent = unit.intents[0];
|
|
12329
|
+
const typedData = unit.intents.length === 1 && firstIntent !== undefined ? evmSigningData(firstIntent) : evmSigningData(unit.intents);
|
|
12330
|
+
const operationContext = address === undefined ? {
|
|
12331
|
+
chain: unit.chain
|
|
12332
|
+
} : {
|
|
12333
|
+
chain: unit.chain,
|
|
12334
|
+
address
|
|
12335
|
+
};
|
|
12336
|
+
const signRequest = await adapter.prepareAction('gateway.v1.signBurnIntents', {
|
|
12337
|
+
typedData,
|
|
12338
|
+
chain: unit.chain
|
|
12339
|
+
}, operationContext);
|
|
12340
|
+
const result = normalizeSignatureResult(await signRequest.execute());
|
|
12341
|
+
return {
|
|
12342
|
+
intents: unit.intents,
|
|
12343
|
+
signature: result.signature,
|
|
12344
|
+
contractSigner: result.contractSigner || unit.contractSigner
|
|
12345
|
+
};
|
|
12346
|
+
}
|
|
12347
|
+
async function signUnits(group, signingUnits) {
|
|
12348
|
+
const signedSets = [];
|
|
12349
|
+
// Keep wallet prompts deterministic. Multiple adapter groups can still sign
|
|
12350
|
+
// in parallel, but one signer is asked for its chain-bound signatures in
|
|
12351
|
+
// source-intent order.
|
|
12352
|
+
for (const unit of signingUnits){
|
|
12353
|
+
signedSets.push(await signUnit(group, unit));
|
|
12354
|
+
}
|
|
12355
|
+
return signedSets;
|
|
12356
|
+
}
|
|
12121
12357
|
/**
|
|
12122
|
-
* Sign an EVM adapter group
|
|
12123
|
-
* EIP-712 ECDSA signature.
|
|
12358
|
+
* Sign an EVM adapter group.
|
|
12124
12359
|
*
|
|
12125
|
-
*
|
|
12126
|
-
*
|
|
12360
|
+
* EOA intents remain batched into one EIP-712 `BurnIntentSet`. ERC-1271
|
|
12361
|
+
* intents are grouped and signed per source chain because smart accounts
|
|
12362
|
+
* commonly include `chainId` in their replay-safe signature hash.
|
|
12363
|
+
* All returned entries can still be submitted together in one atomic Gateway
|
|
12364
|
+
* transfer request.
|
|
12127
12365
|
*
|
|
12128
|
-
* Before signing,
|
|
12129
|
-
*
|
|
12130
|
-
*
|
|
12131
|
-
*
|
|
12132
|
-
*
|
|
12366
|
+
* Before signing, classifies the signer as an EOA or a contract account.
|
|
12367
|
+
* Gateway validates EOA signatures with `ecrecover` and contract-account
|
|
12368
|
+
* signatures with ERC-1271, but it does not infer which one applies — the
|
|
12369
|
+
* transfer request has to declare it. The returned `contractSigner` flag
|
|
12370
|
+
* carries that decision through to `buildTransferRequestBody`.
|
|
12133
12371
|
*
|
|
12134
12372
|
* @param group - The adapter group containing the adapter, chain, and
|
|
12135
12373
|
* burn intents to sign.
|
|
12136
|
-
* @returns
|
|
12374
|
+
* @returns Signed entries with their intents, signatures, and Gateway signer
|
|
12375
|
+
* validation mode.
|
|
12376
|
+
* @throws KitError when an intent has no source-chain mapping or a signing
|
|
12377
|
+
* action returns an invalid signature shape.
|
|
12137
12378
|
*
|
|
12138
12379
|
* @example
|
|
12139
12380
|
* ```typescript
|
|
12140
12381
|
* import { signEvmIntentGroup } from '@core/adapter-evm'
|
|
12141
12382
|
*
|
|
12142
|
-
* const
|
|
12383
|
+
* const signedSets = await signEvmIntentGroup({
|
|
12143
12384
|
* adapter: evmAdapter,
|
|
12144
12385
|
* chain: ethereumChain,
|
|
12145
12386
|
* intents: [burnIntent1, burnIntent2],
|
|
12387
|
+
* chainsByDomain: new Map([
|
|
12388
|
+
* [0, ethereumChain],
|
|
12389
|
+
* [6, baseChain],
|
|
12390
|
+
* ]),
|
|
12146
12391
|
* address: '0x...',
|
|
12147
12392
|
* })
|
|
12148
|
-
* console.log(
|
|
12393
|
+
* console.log(signedSets)
|
|
12149
12394
|
* ```
|
|
12150
12395
|
*/ async function signEvmIntentGroup(group) {
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
// Gateway verifies burn-intent signatures with plain ecrecover. An SCA
|
|
12159
|
-
// signer silently produces a signature over a wrapped hash that Gateway
|
|
12160
|
-
// cannot verify, and Circle Wallets' KMS rejects the typed data up front
|
|
12161
|
-
// with an opaque `<nil>/<nil>` error. Short-circuit with a clear message
|
|
12162
|
-
// when we can detect bytecode at the signer address. See DEVX-2774.
|
|
12163
|
-
//
|
|
12164
|
-
// Duck-typed on readBytecode rather than `instanceof EvmAdapter` because
|
|
12165
|
-
// each consumer package bundles its own copy of the base class and the
|
|
12166
|
-
// `instanceof` identity check fails across package boundaries.
|
|
12167
|
-
//
|
|
12168
|
-
// Empty string is defended against because assertSignerIsEoa would
|
|
12169
|
-
// otherwise call eth_getCode('') on the RPC.
|
|
12170
|
-
const hasResolvedSigner = typeof address === 'string' && address.length > 0;
|
|
12171
|
-
if (hasResolvedSigner && chain.type === 'evm' && isEvmAdapterLike(adapter)) {
|
|
12172
|
-
await assertSignerIsEoa(adapter, address, chain);
|
|
12173
|
-
}
|
|
12174
|
-
const firstIntent = groupIntents[0];
|
|
12175
|
-
const typedData = groupIntents.length === 1 && firstIntent ? evmSigningData(firstIntent) : evmSigningData(groupIntents);
|
|
12176
|
-
const signRequest = await adapter.prepareAction('gateway.v1.signBurnIntents', {
|
|
12177
|
-
typedData,
|
|
12178
|
-
chain
|
|
12179
|
-
}, operationContext);
|
|
12180
|
-
const sig = await signRequest.execute();
|
|
12181
|
-
return {
|
|
12182
|
-
intents: groupIntents,
|
|
12183
|
-
signature: sig
|
|
12184
|
-
};
|
|
12396
|
+
// Validate the collection before doing bytecode reads or asking a wallet
|
|
12397
|
+
// to sign. evmSigningData owns the canonical BurnIntent validation.
|
|
12398
|
+
validateGroupIntents(group.intents);
|
|
12399
|
+
const chainsByDomain = collectChainsByDomain(group);
|
|
12400
|
+
const signerTypeByDomain = await classifySignerTypes(group, chainsByDomain);
|
|
12401
|
+
const signingUnits = createSigningUnits(group, signerTypeByDomain);
|
|
12402
|
+
return await signUnits(group, signingUnits);
|
|
12185
12403
|
}
|
|
12186
12404
|
|
|
12187
12405
|
/**
|
|
12188
12406
|
* Add an EVM intent into the batched EVM group map.
|
|
12189
12407
|
*
|
|
12190
12408
|
* On EVM, all intents for the same adapter are batched into a single
|
|
12191
|
-
* group
|
|
12192
|
-
*
|
|
12409
|
+
* group. The signing step uses `chainsByDomain` to preserve EOA batching
|
|
12410
|
+
* while signing ERC-1271 intents separately on their source chains.
|
|
12193
12411
|
*
|
|
12194
12412
|
* @param intent - The burn intent to group.
|
|
12195
12413
|
* @param alloc - The allocation that resolved to this intent.
|
|
@@ -12206,6 +12424,7 @@ function evmSigningData(burnIntent) {
|
|
|
12206
12424
|
const existing = evmGroups.get(alloc.adapter);
|
|
12207
12425
|
if (existing) {
|
|
12208
12426
|
existing.intents.push(intent);
|
|
12427
|
+
existing.chainsByDomain.set(alloc.chain.gateway.domain, alloc.chain);
|
|
12209
12428
|
} else {
|
|
12210
12429
|
evmGroups.set(alloc.adapter, {
|
|
12211
12430
|
adapter: alloc.adapter,
|
|
@@ -12213,6 +12432,12 @@ function evmSigningData(burnIntent) {
|
|
|
12213
12432
|
intents: [
|
|
12214
12433
|
intent
|
|
12215
12434
|
],
|
|
12435
|
+
chainsByDomain: new Map([
|
|
12436
|
+
[
|
|
12437
|
+
alloc.chain.gateway.domain,
|
|
12438
|
+
alloc.chain
|
|
12439
|
+
]
|
|
12440
|
+
]),
|
|
12216
12441
|
address: alloc.sourceSigner
|
|
12217
12442
|
});
|
|
12218
12443
|
}
|
|
@@ -13738,7 +13963,8 @@ function throwNetworkMismatch(expected, actual) {
|
|
|
13738
13963
|
};
|
|
13739
13964
|
}
|
|
13740
13965
|
/**
|
|
13741
|
-
* Group intents
|
|
13966
|
+
* Group intents for signing (Solana one-per-intent, EVM batched by adapter
|
|
13967
|
+
* with every source chain retained by Gateway domain).
|
|
13742
13968
|
*
|
|
13743
13969
|
* @param intents - Burn intents from estimate response.
|
|
13744
13970
|
* @param allocations - Normalized allocations used to map domain → adapter/chain.
|
|
@@ -16631,22 +16857,32 @@ const DEFAULT_GAS_FEE = parseUnits('0.1', USDC_DECIMALS);
|
|
|
16631
16857
|
*
|
|
16632
16858
|
* Single-intent sets become one burnIntent + signature; multi-intent sets become burnIntentSet + signature.
|
|
16633
16859
|
*
|
|
16860
|
+
* Sets flagged `contractSigner` carry `contractSigner: true`, which tells
|
|
16861
|
+
* Gateway to validate the signature with ERC-1271 (an offchain
|
|
16862
|
+
* `isValidSignature` simulation) instead of `ecrecover`. The flag is
|
|
16863
|
+
* omitted for EOA signers so their payloads stay byte-identical.
|
|
16864
|
+
*
|
|
16634
16865
|
* @param signedSets - Signed intent sets (intents + signature per signer).
|
|
16635
16866
|
* @returns Array of transfer payloads for POST /v1/transfer.
|
|
16636
16867
|
*/ function buildTransferRequestBody(signedSets) {
|
|
16637
16868
|
return signedSets.map((set)=>{
|
|
16638
16869
|
const firstIntent = set.intents[0];
|
|
16870
|
+
const contractSigner = set.contractSigner === true ? {
|
|
16871
|
+
contractSigner: true
|
|
16872
|
+
} : {};
|
|
16639
16873
|
if (set.intents.length === 1 && firstIntent) {
|
|
16640
16874
|
return {
|
|
16641
16875
|
burnIntent: serializeBurnIntent(firstIntent),
|
|
16642
|
-
signature: set.signature
|
|
16876
|
+
signature: set.signature,
|
|
16877
|
+
...contractSigner
|
|
16643
16878
|
};
|
|
16644
16879
|
}
|
|
16645
16880
|
return {
|
|
16646
16881
|
burnIntentSet: {
|
|
16647
16882
|
intents: set.intents.map(serializeBurnIntent)
|
|
16648
16883
|
},
|
|
16649
|
-
signature: set.signature
|
|
16884
|
+
signature: set.signature,
|
|
16885
|
+
...contractSigner
|
|
16650
16886
|
};
|
|
16651
16887
|
});
|
|
16652
16888
|
}
|
|
@@ -17009,11 +17245,16 @@ const BPS_DIVISOR = 100_000n;
|
|
|
17009
17245
|
return required;
|
|
17010
17246
|
}
|
|
17011
17247
|
|
|
17248
|
+
function requireEvmChainsByDomain(group) {
|
|
17249
|
+
if (group.chainsByDomain !== undefined) return group.chainsByDomain;
|
|
17250
|
+
throw createValidationFailedError$1('adapterGroup.chainsByDomain', group.chainsByDomain, 'must be provided for an EVM adapter group');
|
|
17251
|
+
}
|
|
17012
17252
|
/**
|
|
17013
|
-
* Sign each adapter group: Solana one intent per signature, EVM
|
|
17253
|
+
* Sign each adapter group: Solana one intent per signature, and EVM either
|
|
17254
|
+
* batched for EOAs or split by source chain for ERC-1271 signers.
|
|
17014
17255
|
*
|
|
17015
17256
|
* @param adapterGroups - Groups from groupIntentsByAdapter.
|
|
17016
|
-
* @returns Promise of signed sets
|
|
17257
|
+
* @returns Promise of signed sets for buildTransferRequestBody.
|
|
17017
17258
|
*
|
|
17018
17259
|
* @example
|
|
17019
17260
|
* ```typescript
|
|
@@ -17026,9 +17267,10 @@ const BPS_DIVISOR = 100_000n;
|
|
|
17026
17267
|
if (group.chain.type === 'solana') {
|
|
17027
17268
|
return signSolanaIntentGroup(group);
|
|
17028
17269
|
}
|
|
17029
|
-
return
|
|
17030
|
-
|
|
17031
|
-
|
|
17270
|
+
return await signEvmIntentGroup({
|
|
17271
|
+
...group,
|
|
17272
|
+
chainsByDomain: requireEvmChainsByDomain(group)
|
|
17273
|
+
});
|
|
17032
17274
|
}));
|
|
17033
17275
|
return nested.flat();
|
|
17034
17276
|
}
|
|
@@ -17678,7 +17920,8 @@ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, s
|
|
|
17678
17920
|
signedSetCount: signedSets.length,
|
|
17679
17921
|
signatures: signedSets.map((s)=>({
|
|
17680
17922
|
intentCount: s.intents.length,
|
|
17681
|
-
signature: s.signature
|
|
17923
|
+
signature: s.signature,
|
|
17924
|
+
contractSigner: s.contractSigner === true
|
|
17682
17925
|
}))
|
|
17683
17926
|
}
|
|
17684
17927
|
});
|
|
@@ -20423,7 +20666,11 @@ const removeFundParamsSchema = z.object({
|
|
|
20423
20666
|
// Remove Fund Operations
|
|
20424
20667
|
// ---------------------------------------------------------------------------
|
|
20425
20668
|
/**
|
|
20426
|
-
* Kick off a delayed fund removal from an account.
|
|
20669
|
+
* Kick off a delayed recovery fund removal from an account.
|
|
20670
|
+
*
|
|
20671
|
+
* Use `initiateRemoveFund` only as a trustless fallback when the normal spend
|
|
20672
|
+
* flow is unavailable. For day-to-day movement out of a Unified Balance, use
|
|
20673
|
+
* `spend`.
|
|
20427
20674
|
*
|
|
20428
20675
|
* Validates `from` and `amount`, resolves the chain and token via
|
|
20429
20676
|
* {@link resolveRemoveFundParams}, selects the matching provider, then calls
|
|
@@ -20460,7 +20707,10 @@ const removeFundParamsSchema = z.object({
|
|
|
20460
20707
|
return provider.initiateRemoveFund(resolved);
|
|
20461
20708
|
}
|
|
20462
20709
|
/**
|
|
20463
|
-
* Complete a fund removal once the 7-day
|
|
20710
|
+
* Complete a recovery fund removal once the 7-day withdrawal delay has passed.
|
|
20711
|
+
*
|
|
20712
|
+
* Use `removeFund` only as a trustless fallback when the normal spend flow is
|
|
20713
|
+
* unavailable. For day-to-day movement out of a Unified Balance, use `spend`.
|
|
20464
20714
|
*
|
|
20465
20715
|
* Validates `from`, resolves the chain and token via
|
|
20466
20716
|
* {@link resolveRemoveFundParams}, selects the matching provider, then calls
|
|
@@ -20549,13 +20799,18 @@ const removeFundParamsSchema = z.object({
|
|
|
20549
20799
|
/** SDK name used in telemetry payloads. */ const SDK_NAME = resolveKitSdkName(pkg.name);
|
|
20550
20800
|
/**
|
|
20551
20801
|
* A high-level class-based interface for cross-chain USDC deposits,
|
|
20552
|
-
* spending, balance queries, delegation management, and
|
|
20802
|
+
* spending, balance queries, delegation management, and recovery fund removals.
|
|
20553
20803
|
*
|
|
20554
20804
|
* UnifiedBalanceKit provides a familiar class-based API for developers who
|
|
20555
20805
|
* prefer traditional object-oriented patterns. The class maintains an
|
|
20556
20806
|
* internal context and provides methods that delegate to the standalone
|
|
20557
20807
|
* operation functions exported by this package.
|
|
20558
20808
|
*
|
|
20809
|
+
* Use `spend` for normal movement out of a Unified Balance. `removeFund` is a
|
|
20810
|
+
* trustless recovery path for situations where the normal spend flow is
|
|
20811
|
+
* unavailable, and it requires a 7-day withdrawal delay before funds can be
|
|
20812
|
+
* removed.
|
|
20813
|
+
*
|
|
20559
20814
|
* @remarks
|
|
20560
20815
|
* For functional usage, import and use the operations directly:
|
|
20561
20816
|
* ```typescript
|
|
@@ -20776,7 +21031,11 @@ const removeFundParamsSchema = z.object({
|
|
|
20776
21031
|
});
|
|
20777
21032
|
}
|
|
20778
21033
|
/**
|
|
20779
|
-
* Kick off a delayed fund removal from an account.
|
|
21034
|
+
* Kick off a delayed recovery fund removal from an account.
|
|
21035
|
+
*
|
|
21036
|
+
* Use this only as a trustless fallback when the normal spend flow is
|
|
21037
|
+
* unavailable. For day-to-day movement out of a Unified Balance, use
|
|
21038
|
+
* `spend`.
|
|
20780
21039
|
*
|
|
20781
21040
|
* @param params - The account owner's adapter context, amount, and
|
|
20782
21041
|
* optional token type.
|
|
@@ -20790,7 +21049,12 @@ const removeFundParamsSchema = z.object({
|
|
|
20790
21049
|
});
|
|
20791
21050
|
}
|
|
20792
21051
|
/**
|
|
20793
|
-
* Complete a fund removal once the
|
|
21052
|
+
* Complete a recovery fund removal once the 7-day withdrawal delay has
|
|
21053
|
+
* passed.
|
|
21054
|
+
*
|
|
21055
|
+
* Use this only as a trustless fallback when the normal spend flow is
|
|
21056
|
+
* unavailable. For day-to-day movement out of a Unified Balance, use
|
|
21057
|
+
* `spend`.
|
|
20794
21058
|
*
|
|
20795
21059
|
* @param params - The account owner context matching the original
|
|
20796
21060
|
* fund removal initiation.
|
|
@@ -20917,6 +21181,11 @@ registerKit(`${pkg.name}/${pkg.version}`);
|
|
|
20917
21181
|
* Internally holds a persistent {@link UnifiedBalanceKit} instance so that
|
|
20918
21182
|
* event dispatchers and custom fee policies are preserved across calls.
|
|
20919
21183
|
*
|
|
21184
|
+
* Use {@link AppKitUnifiedBalance.spend} for normal movement out of a Unified
|
|
21185
|
+
* Balance. {@link AppKitUnifiedBalance.removeFund} is a trustless recovery path
|
|
21186
|
+
* for situations where the normal spend flow is unavailable, and it requires a
|
|
21187
|
+
* 7-day withdrawal delay after {@link AppKitUnifiedBalance.initiateRemoveFund}.
|
|
21188
|
+
*
|
|
20920
21189
|
* @example
|
|
20921
21190
|
* ```typescript
|
|
20922
21191
|
* import { AppKit } from '@circle-fin/app-kit'
|
|
@@ -21128,7 +21397,12 @@ registerKit(`${pkg.name}/${pkg.version}`);
|
|
|
21128
21397
|
return this.kit.removeDelegate(params);
|
|
21129
21398
|
}
|
|
21130
21399
|
/**
|
|
21131
|
-
*
|
|
21400
|
+
* Initiate a trustless recovery removal from an account.
|
|
21401
|
+
*
|
|
21402
|
+
* Use `spend` for normal movement out of a Unified Balance. `removeFund` is a
|
|
21403
|
+
* recovery path for situations where the normal spend flow is unavailable.
|
|
21404
|
+
* Calling this method starts the 7-day withdrawal delay before the removal can
|
|
21405
|
+
* be completed.
|
|
21132
21406
|
*
|
|
21133
21407
|
* @param params - The account owner's adapter context, amount, and token.
|
|
21134
21408
|
* @returns Promise resolving to the initiation details.
|
|
@@ -21147,11 +21421,16 @@ registerKit(`${pkg.name}/${pkg.version}`);
|
|
|
21147
21421
|
return this.kit.initiateRemoveFund(params);
|
|
21148
21422
|
}
|
|
21149
21423
|
/**
|
|
21150
|
-
* Complete a
|
|
21424
|
+
* Complete a trustless recovery removal after the withdrawal delay.
|
|
21425
|
+
*
|
|
21426
|
+
* Use `spend` for normal movement out of a Unified Balance. `removeFund` is a
|
|
21427
|
+
* recovery path for situations where the normal spend flow is unavailable.
|
|
21428
|
+
* Both EVM and Solana removals require a 7-day withdrawal delay after
|
|
21429
|
+
* `initiateRemoveFund` before funds can be removed.
|
|
21151
21430
|
*
|
|
21152
21431
|
* @param params - The account owner context matching the original initiation.
|
|
21153
21432
|
* @returns Promise resolving to the fund removal details.
|
|
21154
|
-
* @throws {KitError} If the
|
|
21433
|
+
* @throws {KitError} If the withdrawal delay has not elapsed or the
|
|
21155
21434
|
* on-chain transaction fails.
|
|
21156
21435
|
*
|
|
21157
21436
|
* @example
|