@buildonspark/spark-sdk 0.3.9 → 0.4.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 +11 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/uniffi/uniffi/spark_frost/spark_frost.kt +1361 -1367
- package/android/src/main/jniLibs/arm64-v8a/libuniffi_spark_frost.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libuniffi_spark_frost.so +0 -0
- package/android/src/main/jniLibs/x86/libuniffi_spark_frost.so +0 -0
- package/android/src/main/jniLibs/x86_64/libuniffi_spark_frost.so +0 -0
- package/dist/bare/index.cjs +322 -142
- package/dist/bare/index.d.cts +13 -3
- package/dist/bare/index.d.ts +13 -3
- package/dist/bare/index.js +321 -142
- package/dist/{chunk-S55NZT4P.js → chunk-27ILUWDJ.js} +1 -1
- package/dist/{chunk-O4C4HGQL.js → chunk-G3LHXHF3.js} +313 -133
- package/dist/{chunk-WRE2T22S.js → chunk-LOXWCMZL.js} +1 -1
- package/dist/{chunk-MFCM6GUD.js → chunk-WICAF6BS.js} +1 -1
- package/dist/debug.cjs +322 -143
- package/dist/debug.d.cts +5 -4
- package/dist/debug.d.ts +5 -4
- package/dist/debug.js +2 -2
- package/dist/index.cjs +323 -143
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -3
- package/dist/index.node.cjs +323 -143
- package/dist/index.node.d.cts +4 -4
- package/dist/index.node.d.ts +4 -4
- package/dist/index.node.js +4 -2
- package/dist/{logging-DDeMLsVN.d.ts → logging-BNGm6dBp.d.ts} +3 -2
- package/dist/{logging-CXhvuqJJ.d.cts → logging-D3IfXfHG.d.cts} +3 -2
- package/dist/native/index.react-native.cjs +466 -145
- package/dist/native/index.react-native.d.cts +21 -3
- package/dist/native/index.react-native.d.ts +21 -3
- package/dist/native/index.react-native.js +462 -144
- package/dist/{spark-wallet.browser-Cz8c4kOW.d.ts → spark-wallet.browser-B2rGwjuM.d.ts} +1 -1
- package/dist/{spark-wallet.browser-CbYo8A_U.d.cts → spark-wallet.browser-Ck9No4Ks.d.cts} +1 -1
- package/dist/{spark-wallet.node-CmIvxtcC.d.ts → spark-wallet.node-BqmKsGPs.d.ts} +1 -1
- package/dist/{spark-wallet.node-4WQgWwB2.d.cts → spark-wallet.node-C2TIkyt4.d.cts} +1 -1
- package/dist/tests/test-utils.cjs +321 -143
- package/dist/tests/test-utils.d.cts +16 -2
- package/dist/tests/test-utils.d.ts +16 -2
- package/dist/tests/test-utils.js +4 -4
- package/dist/{token-transactions-CV8QD3I7.d.cts → token-transactions-Db8mkjnU.d.cts} +1 -1
- package/dist/{token-transactions-Bu023ztN.d.ts → token-transactions-DoMcrxXQ.d.ts} +1 -1
- package/dist/{wallet-config-Bmk2eAn8.d.ts → wallet-config-Bg3kWltL.d.ts} +11 -2
- package/dist/{wallet-config-DQw5llqA.d.cts → wallet-config-CuZKNo9S.d.cts} +11 -2
- package/ios/spark_frostFFI.xcframework/ios-arm64/SparkFrost +0 -0
- package/ios/spark_frostFFI.xcframework/ios-arm64/spark_frostFFI.framework/spark_frostFFI +0 -0
- package/ios/spark_frostFFI.xcframework/ios-arm64_x86_64-simulator/SparkFrost +0 -0
- package/ios/spark_frostFFI.xcframework/ios-arm64_x86_64-simulator/spark_frostFFI.framework/spark_frostFFI +0 -0
- package/ios/spark_frostFFI.xcframework/macos-arm64_x86_64/spark_frostFFI.framework/spark_frostFFI +0 -0
- package/package.json +1 -1
- package/src/index.react-native.ts +8 -2
- package/src/services/config.ts +5 -0
- package/src/services/wallet-config.ts +10 -0
- package/src/services/xhr-transport.ts +13 -3
- package/src/signer/signer.react-native.ts +73 -1
- package/src/spark-wallet/spark-wallet.ts +98 -76
- package/src/tests/integration/lightning.test.ts +0 -28
- package/src/tests/integration/static_deposit.test.ts +4 -8
- package/src/tests/integration/unilateral-exit.test.ts +117 -0
- package/src/tests/optimize.test.ts +31 -1
- package/src/tests/utils/signing.ts +33 -0
- package/src/tests/utils/test-faucet.ts +61 -0
- package/src/utils/optimize.ts +42 -0
- package/src/utils/unilateral-exit.ts +1 -40
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Q as QueryTransfersResponse, T as Transfer, c as TreeNode } from '../spark-DOpheE8_.js';
|
|
2
|
-
import { b as ConfigOptions } from '../wallet-config-
|
|
2
|
+
import { b as ConfigOptions } from '../wallet-config-Bg3kWltL.js';
|
|
3
3
|
import { S as SparkSigner, D as DefaultSparkSigner } from '../client-BaQf-5gD.js';
|
|
4
|
-
import { S as SparkWalletNodeJS } from '../spark-wallet.node-
|
|
4
|
+
import { S as SparkWalletNodeJS } from '../spark-wallet.node-BqmKsGPs.js';
|
|
5
5
|
import { Transaction } from '@scure/btc-signer';
|
|
6
6
|
import { TransactionInput, TransactionOutput } from '@scure/btc-signer/psbt';
|
|
7
7
|
import '@bufbuild/protobuf/wire';
|
|
@@ -38,12 +38,26 @@ declare class BitcoinFaucet {
|
|
|
38
38
|
sendFaucetCoinToP2WPKHAddress(pubKey: Uint8Array): Promise<void>;
|
|
39
39
|
signFaucetCoin(unsignedTx: Transaction, fundingTxOut: TransactionOutput, key: Uint8Array): Promise<Transaction>;
|
|
40
40
|
mineBlocks(numBlocks: number): Promise<any>;
|
|
41
|
+
mineBlocksAndWaitForMiningToComplete(numBlocks: number): Promise<void>;
|
|
41
42
|
private call;
|
|
42
43
|
generateToAddress(numBlocks: number, address: string): Promise<any>;
|
|
43
44
|
sendToAddressInternal(address: string, amountSats: number): Promise<any>;
|
|
44
45
|
getBlock(blockHash: string): Promise<any>;
|
|
46
|
+
getBlockCount(): Promise<number>;
|
|
47
|
+
waitForBlocksMined({ startBlock, expectedIncrease, timeoutMs, intervalMs, }: {
|
|
48
|
+
startBlock: number;
|
|
49
|
+
expectedIncrease: number;
|
|
50
|
+
timeoutMs?: number;
|
|
51
|
+
intervalMs?: number;
|
|
52
|
+
}): Promise<number>;
|
|
45
53
|
broadcastTx(txHex: string): Promise<any>;
|
|
54
|
+
submitPackage(txHexs: string[]): Promise<any>;
|
|
46
55
|
getNewAddress(): Promise<string>;
|
|
56
|
+
getNewExternalWallet(): Promise<{
|
|
57
|
+
address: string;
|
|
58
|
+
key: Uint8Array;
|
|
59
|
+
pubKey: Uint8Array;
|
|
60
|
+
}>;
|
|
47
61
|
sendToAddress(address: string, amount: bigint, blocksToGenerate?: number): Promise<Transaction>;
|
|
48
62
|
getRawTransaction(txid: string): Promise<any>;
|
|
49
63
|
}
|
package/dist/tests/test-utils.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ConnectionManagerNodeJS,
|
|
3
3
|
SparkWalletNodeJS
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-WICAF6BS.js";
|
|
5
|
+
import "../chunk-LOXWCMZL.js";
|
|
6
|
+
import "../chunk-27ILUWDJ.js";
|
|
7
7
|
import {
|
|
8
8
|
BitcoinFaucet,
|
|
9
9
|
DefaultSparkSigner,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
WalletConfigService,
|
|
15
15
|
getNetwork,
|
|
16
16
|
getP2TRAddressFromPublicKey
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-G3LHXHF3.js";
|
|
18
18
|
import "../chunk-NX5KPN5F.js";
|
|
19
19
|
import "../chunk-JLF6WJ7K.js";
|
|
20
20
|
import "../chunk-4YFT7DAE.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { O as OutputWithPreviousTransactionData } from './spark-DOpheE8_.cjs';
|
|
2
2
|
import { TokenTransaction, QueryTokenTransactionsResponse } from './proto/spark_token.cjs';
|
|
3
|
-
import { W as WalletConfigService, C as ConnectionManager, O as TokenOutputsMap, B as Bech32mTokenIdentifier, S as SparkAddressFormat } from './wallet-config-
|
|
3
|
+
import { W as WalletConfigService, C as ConnectionManager, O as TokenOutputsMap, B as Bech32mTokenIdentifier, S as SparkAddressFormat } from './wallet-config-CuZKNo9S.cjs';
|
|
4
4
|
|
|
5
5
|
declare class SparkSDKError extends Error {
|
|
6
6
|
readonly context: Record<string, unknown>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { O as OutputWithPreviousTransactionData } from './spark-DOpheE8_.js';
|
|
2
2
|
import { TokenTransaction, QueryTokenTransactionsResponse } from './proto/spark_token.js';
|
|
3
|
-
import { W as WalletConfigService, C as ConnectionManager, O as TokenOutputsMap, B as Bech32mTokenIdentifier, S as SparkAddressFormat } from './wallet-config-
|
|
3
|
+
import { W as WalletConfigService, C as ConnectionManager, O as TokenOutputsMap, B as Bech32mTokenIdentifier, S as SparkAddressFormat } from './wallet-config-Bg3kWltL.js';
|
|
4
4
|
|
|
5
5
|
declare class SparkSDKError extends Error {
|
|
6
6
|
readonly context: Record<string, unknown>;
|
|
@@ -118,6 +118,7 @@ declare class WalletConfigService implements HasSspClientOptions {
|
|
|
118
118
|
getSspIdentityPublicKey(): string;
|
|
119
119
|
getConsoleOptions(): ConsoleOptions;
|
|
120
120
|
getEvents(): Partial<SparkWalletEvents>;
|
|
121
|
+
getOptimizationOptions(): OptimizationOptions;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
/** Challenge represents the core challenge data */
|
|
@@ -419,8 +420,11 @@ declare abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
419
420
|
private popOrThrow;
|
|
420
421
|
private selectLeaves;
|
|
421
422
|
private selectLeavesForSwap;
|
|
422
|
-
|
|
423
|
-
|
|
423
|
+
optimizeLeaves(multiplicity?: number | undefined): AsyncGenerator<{
|
|
424
|
+
step: number;
|
|
425
|
+
total: number;
|
|
426
|
+
controller: AbortController;
|
|
427
|
+
}, void, void>;
|
|
424
428
|
private syncWallet;
|
|
425
429
|
private withLeaves;
|
|
426
430
|
/**
|
|
@@ -1141,6 +1145,10 @@ type SigningOperator = {
|
|
|
1141
1145
|
type ConsoleOptions = {
|
|
1142
1146
|
otel?: boolean;
|
|
1143
1147
|
};
|
|
1148
|
+
type OptimizationOptions = {
|
|
1149
|
+
readonly auto?: boolean;
|
|
1150
|
+
readonly multiplicity?: number;
|
|
1151
|
+
};
|
|
1144
1152
|
type ConfigOptions = MayHaveSspClientOptions & {
|
|
1145
1153
|
readonly network?: NetworkType;
|
|
1146
1154
|
readonly signingOperators?: Readonly<Record<string, SigningOperator>>;
|
|
@@ -1156,6 +1164,7 @@ type ConfigOptions = MayHaveSspClientOptions & {
|
|
|
1156
1164
|
readonly signerWithPreExistingKeys?: boolean;
|
|
1157
1165
|
readonly console?: ConsoleOptions;
|
|
1158
1166
|
readonly events?: Partial<SparkWalletEvents>;
|
|
1167
|
+
readonly optimizationOptions?: OptimizationOptions;
|
|
1159
1168
|
};
|
|
1160
1169
|
declare const WalletConfig: {
|
|
1161
1170
|
LOCAL: Required<ConfigOptions>;
|
|
@@ -118,6 +118,7 @@ declare class WalletConfigService implements HasSspClientOptions {
|
|
|
118
118
|
getSspIdentityPublicKey(): string;
|
|
119
119
|
getConsoleOptions(): ConsoleOptions;
|
|
120
120
|
getEvents(): Partial<SparkWalletEvents>;
|
|
121
|
+
getOptimizationOptions(): OptimizationOptions;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
/** Challenge represents the core challenge data */
|
|
@@ -419,8 +420,11 @@ declare abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
419
420
|
private popOrThrow;
|
|
420
421
|
private selectLeaves;
|
|
421
422
|
private selectLeavesForSwap;
|
|
422
|
-
|
|
423
|
-
|
|
423
|
+
optimizeLeaves(multiplicity?: number | undefined): AsyncGenerator<{
|
|
424
|
+
step: number;
|
|
425
|
+
total: number;
|
|
426
|
+
controller: AbortController;
|
|
427
|
+
}, void, void>;
|
|
424
428
|
private syncWallet;
|
|
425
429
|
private withLeaves;
|
|
426
430
|
/**
|
|
@@ -1141,6 +1145,10 @@ type SigningOperator = {
|
|
|
1141
1145
|
type ConsoleOptions = {
|
|
1142
1146
|
otel?: boolean;
|
|
1143
1147
|
};
|
|
1148
|
+
type OptimizationOptions = {
|
|
1149
|
+
readonly auto?: boolean;
|
|
1150
|
+
readonly multiplicity?: number;
|
|
1151
|
+
};
|
|
1144
1152
|
type ConfigOptions = MayHaveSspClientOptions & {
|
|
1145
1153
|
readonly network?: NetworkType;
|
|
1146
1154
|
readonly signingOperators?: Readonly<Record<string, SigningOperator>>;
|
|
@@ -1156,6 +1164,7 @@ type ConfigOptions = MayHaveSspClientOptions & {
|
|
|
1156
1164
|
readonly signerWithPreExistingKeys?: boolean;
|
|
1157
1165
|
readonly console?: ConsoleOptions;
|
|
1158
1166
|
readonly events?: Partial<SparkWalletEvents>;
|
|
1167
|
+
readonly optimizationOptions?: OptimizationOptions;
|
|
1159
1168
|
};
|
|
1160
1169
|
declare const WalletConfig: {
|
|
1161
1170
|
LOCAL: Required<ConfigOptions>;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/ios/spark_frostFFI.xcframework/macos-arm64_x86_64/spark_frostFFI.framework/spark_frostFFI
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -7,9 +7,15 @@ setCrypto(globalThis.crypto);
|
|
|
7
7
|
export * from "./errors/index.js";
|
|
8
8
|
export * from "./utils/index.js";
|
|
9
9
|
|
|
10
|
-
export {
|
|
10
|
+
export {
|
|
11
|
+
ReactNativeSparkSigner,
|
|
12
|
+
ReactNativeTaprootSparkSigner,
|
|
13
|
+
} from "./signer/signer.react-native.js";
|
|
11
14
|
/* Enable some consumers to use named import DefaultSparkSigner regardless of module, see LIG-7662 */
|
|
12
|
-
export {
|
|
15
|
+
export {
|
|
16
|
+
ReactNativeSparkSigner as DefaultSparkSigner,
|
|
17
|
+
ReactNativeTaprootSparkSigner as TaprootSparkSigner,
|
|
18
|
+
} from "./signer/signer.react-native.js";
|
|
13
19
|
|
|
14
20
|
export { SparkWallet } from "./spark-wallet/spark-wallet.react-native.js";
|
|
15
21
|
export * from "./spark-wallet/types.js";
|
package/src/services/config.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
WalletConfig,
|
|
8
8
|
SigningOperator,
|
|
9
9
|
ConsoleOptions,
|
|
10
|
+
OptimizationOptions,
|
|
10
11
|
} from "./wallet-config.js";
|
|
11
12
|
import { ConfigurationError } from "../errors/types.js";
|
|
12
13
|
import { SparkWalletEvents } from "../spark-wallet/types.js";
|
|
@@ -127,4 +128,8 @@ export class WalletConfigService implements HasSspClientOptions {
|
|
|
127
128
|
public getEvents(): Partial<SparkWalletEvents> {
|
|
128
129
|
return this.config.events;
|
|
129
130
|
}
|
|
131
|
+
|
|
132
|
+
public getOptimizationOptions(): OptimizationOptions {
|
|
133
|
+
return this.config.optimizationOptions;
|
|
134
|
+
}
|
|
130
135
|
}
|
|
@@ -104,6 +104,11 @@ export type ConsoleOptions = {
|
|
|
104
104
|
otel?: boolean;
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
+
export type OptimizationOptions = {
|
|
108
|
+
readonly auto?: boolean;
|
|
109
|
+
readonly multiplicity?: number;
|
|
110
|
+
};
|
|
111
|
+
|
|
107
112
|
export type ConfigOptions = MayHaveSspClientOptions & {
|
|
108
113
|
readonly network?: NetworkType;
|
|
109
114
|
readonly signingOperators?: Readonly<Record<string, SigningOperator>>;
|
|
@@ -119,6 +124,7 @@ export type ConfigOptions = MayHaveSspClientOptions & {
|
|
|
119
124
|
readonly signerWithPreExistingKeys?: boolean;
|
|
120
125
|
readonly console?: ConsoleOptions;
|
|
121
126
|
readonly events?: Partial<SparkWalletEvents>;
|
|
127
|
+
readonly optimizationOptions?: OptimizationOptions;
|
|
122
128
|
};
|
|
123
129
|
|
|
124
130
|
const PROD_PUBKEYS = [
|
|
@@ -153,6 +159,10 @@ const BASE_CONFIG: Required<ConfigOptions> = {
|
|
|
153
159
|
otel: false,
|
|
154
160
|
},
|
|
155
161
|
events: {},
|
|
162
|
+
optimizationOptions: {
|
|
163
|
+
auto: true,
|
|
164
|
+
multiplicity: 0,
|
|
165
|
+
},
|
|
156
166
|
};
|
|
157
167
|
|
|
158
168
|
const LOCAL_WALLET_CONFIG: Required<ConfigOptions> = {
|
|
@@ -169,7 +169,17 @@ function headersToMetadata(headers: string): Metadata {
|
|
|
169
169
|
const parts = line.split(": ");
|
|
170
170
|
const header = parts.shift() ?? "";
|
|
171
171
|
const value = parts.join(": ");
|
|
172
|
-
|
|
172
|
+
|
|
173
|
+
if (header.endsWith("-bin")) {
|
|
174
|
+
try {
|
|
175
|
+
metadata.set(header, Base64.toUint8Array(value));
|
|
176
|
+
} catch (e) {
|
|
177
|
+
console.warn(`Failed to decode binary metadata ${header}:`, e);
|
|
178
|
+
metadata.set(header, value);
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
metadata.set(header, value);
|
|
182
|
+
}
|
|
173
183
|
});
|
|
174
184
|
return metadata;
|
|
175
185
|
}
|
|
@@ -202,8 +212,8 @@ function getErrorDetailsFromHttpResponse(
|
|
|
202
212
|
): string {
|
|
203
213
|
return (
|
|
204
214
|
`Received HTTP ${statusCode} response: ` +
|
|
205
|
-
(responseText
|
|
206
|
-
? responseText
|
|
215
|
+
(responseText?.length > 1000
|
|
216
|
+
? responseText?.slice(0, 1000) + "... (truncated)"
|
|
207
217
|
: responseText)
|
|
208
218
|
);
|
|
209
219
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ValidationError } from "../errors/index.js";
|
|
2
2
|
import { NativeSparkFrost } from "../spark_bindings/native/index.js";
|
|
3
3
|
import { IKeyPackage } from "../spark_bindings/types.js";
|
|
4
|
-
import { DefaultSparkSigner } from "./signer.js";
|
|
4
|
+
import { DefaultSparkSigner, TaprootSparkSigner } from "./signer.js";
|
|
5
5
|
import type { AggregateFrostParams, SignFrostParams } from "./types.js";
|
|
6
6
|
|
|
7
7
|
export class ReactNativeSparkSigner extends DefaultSparkSigner {
|
|
@@ -71,3 +71,75 @@ export class ReactNativeSparkSigner extends DefaultSparkSigner {
|
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
export class ReactNativeTaprootSparkSigner extends TaprootSparkSigner {
|
|
76
|
+
constructor(useAddressIndex = false) {
|
|
77
|
+
super(useAddressIndex);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async signFrost({
|
|
81
|
+
message,
|
|
82
|
+
keyDerivation,
|
|
83
|
+
publicKey,
|
|
84
|
+
verifyingKey,
|
|
85
|
+
selfCommitment,
|
|
86
|
+
statechainCommitments,
|
|
87
|
+
adaptorPubKey,
|
|
88
|
+
}: SignFrostParams): Promise<Uint8Array> {
|
|
89
|
+
const signingPrivateKey =
|
|
90
|
+
await this.getSigningPrivateKeyFromDerivation(keyDerivation);
|
|
91
|
+
|
|
92
|
+
if (!signingPrivateKey) {
|
|
93
|
+
throw new ValidationError("Private key not found for public key", {
|
|
94
|
+
field: "privateKey",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const commitment = selfCommitment.commitment;
|
|
99
|
+
const nonce = this.commitmentToNonceMap.get(commitment);
|
|
100
|
+
if (!nonce) {
|
|
101
|
+
throw new ValidationError("Nonce not found for commitment", {
|
|
102
|
+
field: "nonce",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const keyPackage: IKeyPackage = {
|
|
107
|
+
secretKey: signingPrivateKey,
|
|
108
|
+
publicKey: publicKey,
|
|
109
|
+
verifyingKey: verifyingKey,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return NativeSparkFrost.signFrost({
|
|
113
|
+
message,
|
|
114
|
+
keyPackage,
|
|
115
|
+
nonce,
|
|
116
|
+
selfCommitment: commitment,
|
|
117
|
+
statechainCommitments,
|
|
118
|
+
adaptorPubKey,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async aggregateFrost({
|
|
123
|
+
message,
|
|
124
|
+
publicKey,
|
|
125
|
+
verifyingKey,
|
|
126
|
+
selfCommitment,
|
|
127
|
+
statechainCommitments,
|
|
128
|
+
adaptorPubKey,
|
|
129
|
+
selfSignature,
|
|
130
|
+
statechainSignatures,
|
|
131
|
+
statechainPublicKeys,
|
|
132
|
+
}: AggregateFrostParams): Promise<Uint8Array> {
|
|
133
|
+
return NativeSparkFrost.aggregateFrost({
|
|
134
|
+
message,
|
|
135
|
+
statechainSignatures,
|
|
136
|
+
statechainPublicKeys,
|
|
137
|
+
verifyingKey,
|
|
138
|
+
statechainCommitments,
|
|
139
|
+
selfCommitment: selfCommitment.commitment,
|
|
140
|
+
selfPublicKey: publicKey,
|
|
141
|
+
selfSignature,
|
|
142
|
+
adaptorPubKey,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -124,7 +124,6 @@ import {
|
|
|
124
124
|
import { chunkArray } from "../utils/chunkArray.js";
|
|
125
125
|
import { getFetch } from "../utils/fetch.js";
|
|
126
126
|
import { addPublicKeys } from "../utils/keys.js";
|
|
127
|
-
import { maximizeUnilateralExit } from "../utils/optimize.js";
|
|
128
127
|
import { RetryContext, withRetry } from "../utils/retry.js";
|
|
129
128
|
import {
|
|
130
129
|
Bech32mTokenIdentifier,
|
|
@@ -152,6 +151,7 @@ import type {
|
|
|
152
151
|
UserTokenMetadata,
|
|
153
152
|
} from "./types.js";
|
|
154
153
|
import { SparkWalletEvent } from "./types.js";
|
|
154
|
+
import { optimize, shouldOptimize } from "../utils/optimize.js";
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
157
|
* The SparkWallet class is the primary interface for interacting with the Spark network.
|
|
@@ -299,7 +299,6 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
299
299
|
await this.claimTransfer({
|
|
300
300
|
transfer: event.transfer.transfer,
|
|
301
301
|
emit: true,
|
|
302
|
-
optimize: true,
|
|
303
302
|
});
|
|
304
303
|
}
|
|
305
304
|
} else if (isDepositStreamEvent(event)) {
|
|
@@ -669,76 +668,101 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
669
668
|
return nodes;
|
|
670
669
|
}
|
|
671
670
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
671
|
+
public async *optimizeLeaves(
|
|
672
|
+
multiplicity: number | undefined = undefined,
|
|
673
|
+
): AsyncGenerator<
|
|
674
|
+
{
|
|
675
|
+
step: number;
|
|
676
|
+
total: number;
|
|
677
|
+
controller: AbortController;
|
|
678
|
+
},
|
|
679
|
+
void,
|
|
680
|
+
void
|
|
681
|
+
> {
|
|
682
|
+
const multiplicityValue =
|
|
683
|
+
multiplicity ?? this.config.getOptimizationOptions().multiplicity ?? 0;
|
|
684
|
+
if (multiplicityValue < 0) {
|
|
685
|
+
throw new ValidationError("Multiplicity cannot be negative");
|
|
686
|
+
} else if (multiplicityValue > 5) {
|
|
687
|
+
throw new ValidationError("Multiplicity cannot be greater than 5");
|
|
677
688
|
}
|
|
678
689
|
|
|
679
|
-
|
|
690
|
+
if (
|
|
691
|
+
this.optimizationInProgress ||
|
|
692
|
+
!shouldOptimize(
|
|
693
|
+
this.leaves.map((leaf) => leaf.value),
|
|
694
|
+
multiplicityValue,
|
|
695
|
+
)
|
|
696
|
+
) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
680
699
|
|
|
681
|
-
|
|
682
|
-
|
|
700
|
+
const controller = new AbortController();
|
|
701
|
+
const release = await this.leavesMutex.acquire();
|
|
702
|
+
try {
|
|
703
|
+
this.optimizationInProgress = true;
|
|
683
704
|
|
|
684
|
-
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
705
|
+
this.leaves = await this.getLeaves();
|
|
706
|
+
const swaps = optimize(
|
|
707
|
+
this.leaves.map((leaf) => leaf.value),
|
|
708
|
+
multiplicityValue,
|
|
709
|
+
);
|
|
710
|
+
if (swaps.length === 0) {
|
|
711
|
+
return;
|
|
689
712
|
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
return this.leaves.length > optimalLeavesLength * 5;
|
|
693
|
-
}
|
|
694
713
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
714
|
+
yield {
|
|
715
|
+
step: 0,
|
|
716
|
+
total: swaps.length,
|
|
717
|
+
controller,
|
|
718
|
+
};
|
|
699
719
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
);
|
|
720
|
+
// Build a map from the denomination to the indices
|
|
721
|
+
const valueToNodes = new Map<number, TreeNode[]>();
|
|
722
|
+
this.leaves.forEach((leaf) => {
|
|
723
|
+
if (!valueToNodes.has(leaf.value)) {
|
|
724
|
+
valueToNodes.set(leaf.value, []);
|
|
725
|
+
}
|
|
726
|
+
valueToNodes.get(leaf.value)!.push(leaf);
|
|
727
|
+
});
|
|
707
728
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
714
|
-
valueToNodes.get(leaf.value)!.push(leaf);
|
|
715
|
-
});
|
|
729
|
+
// Select the leaves to send for each swap.
|
|
730
|
+
for (const swap of swaps) {
|
|
731
|
+
if (controller.signal.aborted) {
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
716
734
|
|
|
717
|
-
|
|
718
|
-
for (const
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
`No unused leaf with value ${leafValue} found in leaves`,
|
|
728
|
-
);
|
|
729
|
-
}
|
|
735
|
+
const leavesToSend: TreeNode[] = [];
|
|
736
|
+
for (const leafValue of swap.inLeaves) {
|
|
737
|
+
const nodes = valueToNodes.get(leafValue);
|
|
738
|
+
if (nodes && nodes.length > 0) {
|
|
739
|
+
const node = nodes.shift()!;
|
|
740
|
+
leavesToSend.push(node);
|
|
741
|
+
} else {
|
|
742
|
+
throw new InternalValidationError(
|
|
743
|
+
`No unused leaf with value ${leafValue} found in leaves`,
|
|
744
|
+
);
|
|
730
745
|
}
|
|
731
|
-
await this.requestLeavesSwap({
|
|
732
|
-
leaves: leavesToSend,
|
|
733
|
-
targetAmounts: swap.outLeaves,
|
|
734
|
-
});
|
|
735
746
|
}
|
|
736
747
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
748
|
+
// TODO: Parallelize this.
|
|
749
|
+
await this.requestLeavesSwap({
|
|
750
|
+
leaves: leavesToSend,
|
|
751
|
+
targetAmounts: swap.outLeaves,
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
yield {
|
|
755
|
+
step: swaps.indexOf(swap) + 1,
|
|
756
|
+
total: swaps.length,
|
|
757
|
+
controller,
|
|
758
|
+
};
|
|
740
759
|
}
|
|
741
|
-
|
|
760
|
+
|
|
761
|
+
this.leaves = await this.getLeaves();
|
|
762
|
+
} finally {
|
|
763
|
+
this.optimizationInProgress = false;
|
|
764
|
+
release();
|
|
765
|
+
}
|
|
742
766
|
}
|
|
743
767
|
|
|
744
768
|
private async syncWallet() {
|
|
@@ -750,9 +774,11 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
750
774
|
|
|
751
775
|
this.leaves = leaves;
|
|
752
776
|
|
|
753
|
-
this.
|
|
754
|
-
|
|
755
|
-
|
|
777
|
+
if (this.config.getOptimizationOptions().auto) {
|
|
778
|
+
for await (const _ of this.optimizeLeaves()) {
|
|
779
|
+
// run all optimizer steps, do nothing with them
|
|
780
|
+
}
|
|
781
|
+
}
|
|
756
782
|
}
|
|
757
783
|
|
|
758
784
|
private async withLeaves<T>(operation: () => Promise<T>): Promise<T> {
|
|
@@ -1453,7 +1479,6 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
1453
1479
|
return await this.claimTransfer({
|
|
1454
1480
|
transfer: incomingTransfer,
|
|
1455
1481
|
emit: false,
|
|
1456
|
-
optimize: false,
|
|
1457
1482
|
});
|
|
1458
1483
|
} catch (e) {
|
|
1459
1484
|
console.error("[processSwapBatch] Error details:", {
|
|
@@ -2749,7 +2774,7 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
2749
2774
|
transfer.id,
|
|
2750
2775
|
);
|
|
2751
2776
|
if (pending) {
|
|
2752
|
-
await this.claimTransfer({ transfer: pending
|
|
2777
|
+
await this.claimTransfer({ transfer: pending });
|
|
2753
2778
|
}
|
|
2754
2779
|
}
|
|
2755
2780
|
return {
|
|
@@ -2959,7 +2984,6 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
2959
2984
|
result: TreeNode[],
|
|
2960
2985
|
transfer: Transfer,
|
|
2961
2986
|
emit?: boolean,
|
|
2962
|
-
optimize?: boolean,
|
|
2963
2987
|
): Promise<TreeNode[]> {
|
|
2964
2988
|
result = await this.checkRenewLeaves(result);
|
|
2965
2989
|
|
|
@@ -2967,8 +2991,13 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
2967
2991
|
const uniqueResults = result.filter((node) => !existingIds.has(node.id));
|
|
2968
2992
|
this.leaves.push(...uniqueResults);
|
|
2969
2993
|
|
|
2970
|
-
if (
|
|
2971
|
-
|
|
2994
|
+
if (
|
|
2995
|
+
this.config.getOptimizationOptions().auto &&
|
|
2996
|
+
transfer.type !== TransferType.COUNTER_SWAP
|
|
2997
|
+
) {
|
|
2998
|
+
for await (const _ of this.optimizeLeaves()) {
|
|
2999
|
+
// run all optimizer steps, do nothing with them
|
|
3000
|
+
}
|
|
2972
3001
|
}
|
|
2973
3002
|
|
|
2974
3003
|
if (emit) {
|
|
@@ -2991,11 +3020,9 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
2991
3020
|
private async claimTransfer({
|
|
2992
3021
|
transfer,
|
|
2993
3022
|
emit,
|
|
2994
|
-
optimize,
|
|
2995
3023
|
}: {
|
|
2996
3024
|
transfer: Transfer;
|
|
2997
3025
|
emit?: boolean;
|
|
2998
|
-
optimize?: boolean;
|
|
2999
3026
|
}) {
|
|
3000
3027
|
const onError = async (
|
|
3001
3028
|
context: RetryContext<TreeNode[], Transfer>,
|
|
@@ -3053,12 +3080,7 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
3053
3080
|
return [];
|
|
3054
3081
|
}
|
|
3055
3082
|
|
|
3056
|
-
return await this.processClaimedTransferResults(
|
|
3057
|
-
result,
|
|
3058
|
-
transfer,
|
|
3059
|
-
emit,
|
|
3060
|
-
optimize,
|
|
3061
|
-
);
|
|
3083
|
+
return await this.processClaimedTransferResults(result, transfer, emit);
|
|
3062
3084
|
} catch (error) {
|
|
3063
3085
|
console.warn(
|
|
3064
3086
|
`Failed to claim transfer after all retries. Please try reinitializing your wallet in a few minutes. Transfer ID: ${transfer.id}`,
|
|
@@ -3107,7 +3129,7 @@ export abstract class SparkWallet extends EventEmitter<SparkWalletEvents> {
|
|
|
3107
3129
|
continue;
|
|
3108
3130
|
}
|
|
3109
3131
|
promises.push(
|
|
3110
|
-
this.claimTransfer({ transfer, emit
|
|
3132
|
+
this.claimTransfer({ transfer, emit })
|
|
3111
3133
|
.then(() => transfer.id)
|
|
3112
3134
|
.catch((error) => {
|
|
3113
3135
|
console.warn(`Failed to claim transfer ${transfer.id}:`, error);
|