@hardkas/accounts 0.12.0-rc.2 → 0.12.0-rc.21
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/dist/{authorizers-OVWWAL5J.js → authorizers-CP222OTW.js} +1 -1
- package/dist/{chunk-TRVIQTIO.js → chunk-7KKJXU73.js} +84 -29
- package/dist/{chunk-6DPO5V3N.js → chunk-BNF566PS.js} +11 -20
- package/dist/{chunk-6Q4K4A24.js → chunk-CELVD4YG.js} +136 -135
- package/dist/{chunk-YJL7P33W.js → chunk-E73SSWAX.js} +4 -5
- package/dist/{chunk-R5P3WIWR.js → chunk-GM2BY4VS.js} +37 -15
- package/dist/{dev-accounts-B6ZVTPCW.js → dev-accounts-BSWPKAAE.js} +4 -4
- package/dist/index.d.ts +358 -10
- package/dist/index.js +575 -36
- package/dist/internal/wasm-rpc-serialization.d.ts +5 -1
- package/dist/internal/wasm-rpc-serialization.js +1 -1
- package/dist/{resolve-GHZEED5L.js → resolve-KMMTZWC3.js} +3 -1
- package/dist/{signer-backend-W3LNCQA3.js → signer-backend-LHWY7ULI.js} +5 -3
- package/package.json +6 -7
package/dist/index.js
CHANGED
|
@@ -2,13 +2,27 @@ import {
|
|
|
2
2
|
DEV_ACCOUNTS_PASSWORD,
|
|
3
3
|
KaspaWasmPrivateKeySigner,
|
|
4
4
|
assertSigningNetworkAllowed,
|
|
5
|
+
assertValueConservation,
|
|
6
|
+
createBalancedTransaction,
|
|
5
7
|
createDevSigner,
|
|
8
|
+
createScriptTransaction,
|
|
6
9
|
ensureDevAccounts,
|
|
7
10
|
getOrCreateDevAccount,
|
|
8
|
-
listDevAccountsSync
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
listDevAccountsSync,
|
|
12
|
+
planOutputsWithChange,
|
|
13
|
+
toWasmScriptPublicKey
|
|
14
|
+
} from "./chunk-CELVD4YG.js";
|
|
15
|
+
import {
|
|
16
|
+
parseWasmTxToRpc
|
|
17
|
+
} from "./chunk-GM2BY4VS.js";
|
|
18
|
+
import {
|
|
19
|
+
detectCapabilities,
|
|
20
|
+
getKaspaSigningBackendStatus,
|
|
21
|
+
loadKaspaWasm,
|
|
22
|
+
loadKaspaWasmSync
|
|
23
|
+
} from "./chunk-BNF566PS.js";
|
|
11
24
|
import {
|
|
25
|
+
assertAccountCompatible,
|
|
12
26
|
createEmptyRealAccountStore,
|
|
13
27
|
describeAccount,
|
|
14
28
|
getDefaultRealAccountsPath,
|
|
@@ -27,12 +41,7 @@ import {
|
|
|
27
41
|
validateAccountName,
|
|
28
42
|
validateAddressNetwork,
|
|
29
43
|
validateAddressPrefix
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
import {
|
|
32
|
-
detectCapabilities,
|
|
33
|
-
getKaspaSigningBackendStatus,
|
|
34
|
-
loadKaspaWasm
|
|
35
|
-
} from "./chunk-6DPO5V3N.js";
|
|
44
|
+
} from "./chunk-7KKJXU73.js";
|
|
36
45
|
import {
|
|
37
46
|
KeystoreManager
|
|
38
47
|
} from "./chunk-YLG2NIAU.js";
|
|
@@ -40,7 +49,7 @@ import {
|
|
|
40
49
|
LazyAccountAuthorizer,
|
|
41
50
|
PrivateKeyAuthorizer,
|
|
42
51
|
StaticSignatureScriptAuthorizer
|
|
43
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-E73SSWAX.js";
|
|
44
53
|
|
|
45
54
|
// src/simulated.ts
|
|
46
55
|
var SimulatedSigner = class {
|
|
@@ -236,14 +245,536 @@ async function signTxPlanArtifact(input) {
|
|
|
236
245
|
throw new Error(`Unsupported account kind for signing: ${accountRecord ? accountRecord.kind : "unknown"}`);
|
|
237
246
|
}
|
|
238
247
|
|
|
248
|
+
// src/silver-spend.ts
|
|
249
|
+
import {
|
|
250
|
+
encodeSilverEntryArgs,
|
|
251
|
+
getSilContract,
|
|
252
|
+
loadManagedKaspaWasmSync,
|
|
253
|
+
silContractBytecodeHex,
|
|
254
|
+
silverP2shLock,
|
|
255
|
+
silverSigFromInputSignature,
|
|
256
|
+
silverUnlockScript
|
|
257
|
+
} from "@hardkas/core";
|
|
258
|
+
import { calculateUpstreamStorageMass, measureBuiltTransactionMass } from "@hardkas/tx-builder";
|
|
259
|
+
function spendError(code, message) {
|
|
260
|
+
const err = new Error(`${code}: ${message}`);
|
|
261
|
+
err.code = code;
|
|
262
|
+
return err;
|
|
263
|
+
}
|
|
264
|
+
var PLACEHOLDER_SIG = { kind: "bytes", value: new Uint8Array(65) };
|
|
265
|
+
function buildSilverSweep(request) {
|
|
266
|
+
const k = loadManagedKaspaWasmSync();
|
|
267
|
+
const { name: contractName, contract } = getSilContract(request.artifact, request.contractName);
|
|
268
|
+
const bytecode = silContractBytecodeHex(contract);
|
|
269
|
+
const lock = silverP2shLock(bytecode);
|
|
270
|
+
const utxoSpk = request.utxo.scriptPublicKey;
|
|
271
|
+
if (Number(utxoSpk.version) !== lock.version || String(utxoSpk.script).toLowerCase() !== lock.script) {
|
|
272
|
+
throw spendError(
|
|
273
|
+
"SILVER_SPEND_LOCK_MISMATCH",
|
|
274
|
+
`output ${request.utxo.outpoint.transactionId}:${request.utxo.outpoint.index} is not locked to contract '${contractName}'`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
if (!k.Address.validate(request.to)) throw spendError("SILVER_SPEND_INVALID_RECIPIENT", `'${request.to}' is not a Kaspa address`);
|
|
278
|
+
const sequence = request.sequence ?? 0n;
|
|
279
|
+
const sigOpCount = request.sigOpCount ?? 1;
|
|
280
|
+
const amountIn = request.utxo.amountSompi;
|
|
281
|
+
const { transactionId, index } = request.utxo.outpoint;
|
|
282
|
+
const makeTx = (amountOut2, signatureScript) => {
|
|
283
|
+
const tx = new k.Transaction({
|
|
284
|
+
version: 0,
|
|
285
|
+
inputs: [
|
|
286
|
+
{
|
|
287
|
+
previousOutpoint: { transactionId, index },
|
|
288
|
+
signatureScript,
|
|
289
|
+
sequence,
|
|
290
|
+
sigOpCount,
|
|
291
|
+
utxo: {
|
|
292
|
+
outpoint: { transactionId, index },
|
|
293
|
+
amount: amountIn,
|
|
294
|
+
scriptPublicKey: new k.ScriptPublicKey(lock.version, lock.script),
|
|
295
|
+
blockDaaScore: request.utxo.blockDaaScore,
|
|
296
|
+
isCoinbase: request.utxo.isCoinbase
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
],
|
|
300
|
+
outputs: [{ value: amountOut2, scriptPublicKey: k.payToAddressScript(new k.Address(request.to)) }],
|
|
301
|
+
lockTime: 0n,
|
|
302
|
+
subnetworkId: "0000000000000000000000000000000000000000",
|
|
303
|
+
gas: 0n,
|
|
304
|
+
payload: ""
|
|
305
|
+
});
|
|
306
|
+
tx.storageMass = calculateUpstreamStorageMass([amountIn], [amountOut2], request.networkId);
|
|
307
|
+
return tx;
|
|
308
|
+
};
|
|
309
|
+
const entryArgs = (resolveSig) => encodeSilverEntryArgs({
|
|
310
|
+
artifact: request.artifact,
|
|
311
|
+
contractName,
|
|
312
|
+
entry: request.entry,
|
|
313
|
+
args: request.args.map((a) => a.kind === "signature" ? resolveSig(a) : a)
|
|
314
|
+
});
|
|
315
|
+
const placeholderUnlock = silverUnlockScript(bytecode, entryArgs(() => PLACEHOLDER_SIG));
|
|
316
|
+
let fee = 0n;
|
|
317
|
+
let priced;
|
|
318
|
+
let converged = false;
|
|
319
|
+
for (let round = 0; round < 8 && !converged; round++) {
|
|
320
|
+
const amountOut2 = amountIn - fee;
|
|
321
|
+
if (amountOut2 <= 0n) throw spendError("SILVER_SPEND_INSUFFICIENT_VALUE", `output of ${amountIn} sompi cannot pay a fee of ${fee}`);
|
|
322
|
+
priced = measureBuiltTransactionMass(makeTx(amountOut2, placeholderUnlock), request.networkId);
|
|
323
|
+
if (!priced.standard) {
|
|
324
|
+
throw spendError("TX_MASS_ABOVE_STANDARD_LIMIT", `mass ${priced.mass} exceeds the maximum standard mass ${priced.maximumStandardMass}`);
|
|
325
|
+
}
|
|
326
|
+
const byRate = request.feeRateSompiPerGram !== void 0 ? priced.mass * request.feeRateSompiPerGram : 0n;
|
|
327
|
+
const required = priced.minimumFeeSompi > byRate ? priced.minimumFeeSompi : byRate;
|
|
328
|
+
if (required <= fee) converged = true;
|
|
329
|
+
else fee = required;
|
|
330
|
+
}
|
|
331
|
+
if (!priced || !converged) throw spendError("SILVER_SPEND_FEE_UNRESOLVED", "the fee did not converge");
|
|
332
|
+
const amountOut = amountIn - fee;
|
|
333
|
+
const unsigned = makeTx(amountOut, "");
|
|
334
|
+
const unlock = silverUnlockScript(
|
|
335
|
+
bytecode,
|
|
336
|
+
entryArgs((a) => ({
|
|
337
|
+
kind: "bytes",
|
|
338
|
+
value: silverSigFromInputSignature(String(k.createInputSignature(unsigned, 0, new k.PrivateKey(a.privateKey), k.SighashType.All)))
|
|
339
|
+
}))
|
|
340
|
+
);
|
|
341
|
+
if (unlock.length !== placeholderUnlock.length) {
|
|
342
|
+
throw spendError("SILVER_SPEND_UNLOCK_SIZE_CHANGED", "the signed unlock is not the size the fee was computed for");
|
|
343
|
+
}
|
|
344
|
+
const signed = makeTx(amountOut, unlock);
|
|
345
|
+
return {
|
|
346
|
+
transaction: signed,
|
|
347
|
+
rpcTransaction: parseWasmTxToRpc(signed.serializeToObject()),
|
|
348
|
+
txId: String(signed.id),
|
|
349
|
+
contractName,
|
|
350
|
+
entry: request.entry,
|
|
351
|
+
outputSompi: amountOut,
|
|
352
|
+
feeSompi: fee,
|
|
353
|
+
mass: priced.mass,
|
|
354
|
+
storageMass: BigInt(signed.storageMass),
|
|
355
|
+
signatureScriptHex: unlock,
|
|
356
|
+
assumptions: [...priced.assumptions, `sigOpCount ${sigOpCount}`]
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
var SILVER_SPEND_DRAFT_SCHEMA = "hardkas.silver.spendDraft.v1";
|
|
360
|
+
function draftTx(k, draft, signatureScript, networkId) {
|
|
361
|
+
const i = draft.input;
|
|
362
|
+
const tx = new k.Transaction({
|
|
363
|
+
version: 0,
|
|
364
|
+
inputs: [{
|
|
365
|
+
previousOutpoint: i.outpoint,
|
|
366
|
+
signatureScript,
|
|
367
|
+
sequence: BigInt(i.sequence),
|
|
368
|
+
sigOpCount: i.sigOpCount,
|
|
369
|
+
utxo: {
|
|
370
|
+
outpoint: i.outpoint,
|
|
371
|
+
amount: BigInt(i.amountSompi),
|
|
372
|
+
scriptPublicKey: new k.ScriptPublicKey(i.scriptPublicKey.version, i.scriptPublicKey.script),
|
|
373
|
+
blockDaaScore: BigInt(i.blockDaaScore),
|
|
374
|
+
isCoinbase: i.isCoinbase
|
|
375
|
+
}
|
|
376
|
+
}],
|
|
377
|
+
outputs: draft.outputs.map((o) => ({ value: BigInt(o.valueSompi), scriptPublicKey: new k.ScriptPublicKey(o.scriptPublicKey.version, o.scriptPublicKey.script) })),
|
|
378
|
+
lockTime: 0n,
|
|
379
|
+
subnetworkId: "0000000000000000000000000000000000000000",
|
|
380
|
+
gas: 0n,
|
|
381
|
+
payload: ""
|
|
382
|
+
});
|
|
383
|
+
tx.storageMass = calculateUpstreamStorageMass([BigInt(i.amountSompi)], draft.outputs.map((o) => BigInt(o.valueSompi)), networkId);
|
|
384
|
+
return tx;
|
|
385
|
+
}
|
|
386
|
+
function draftUnlock(artifact, contractName, entry, args, fill) {
|
|
387
|
+
const { contract } = getSilContract(artifact, contractName);
|
|
388
|
+
return silverUnlockScript(
|
|
389
|
+
silContractBytecodeHex(contract),
|
|
390
|
+
encodeSilverEntryArgs({ artifact, contractName, entry, args: args.map((a) => a.kind === "signer" ? fill(a) : a) })
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
function prepareSilverSpend(request) {
|
|
394
|
+
const k = loadManagedKaspaWasmSync();
|
|
395
|
+
const { name: contractName, contract } = getSilContract(request.artifact, request.contractName);
|
|
396
|
+
const lock = silverP2shLock(silContractBytecodeHex(contract));
|
|
397
|
+
const u = request.utxo;
|
|
398
|
+
if (Number(u.scriptPublicKey.version) !== lock.version || String(u.scriptPublicKey.script).toLowerCase() !== lock.script) {
|
|
399
|
+
throw spendError("SILVER_SPEND_LOCK_MISMATCH", `output ${u.outpoint.transactionId}:${u.outpoint.index} is not locked to contract '${contractName}'`);
|
|
400
|
+
}
|
|
401
|
+
const signers = request.args.filter((a) => a.kind === "signer").map((a) => a.signer);
|
|
402
|
+
const outputs = request.outputs.map((o, i) => {
|
|
403
|
+
let spk = o.scriptPublicKey;
|
|
404
|
+
if (!spk && o.address) {
|
|
405
|
+
if (!k.Address.validate(o.address)) throw spendError("SILVER_SPEND_INVALID_RECIPIENT", `output ${i}: '${o.address}' is not a Kaspa address`);
|
|
406
|
+
const s = k.payToAddressScript(new k.Address(o.address));
|
|
407
|
+
spk = { version: Number(s.version), script: String(s.script) };
|
|
408
|
+
}
|
|
409
|
+
if (!spk || !/^(?:[0-9a-f]{2})+$/i.test(spk.script)) throw spendError("SILVER_SPEND_INVALID_RECIPIENT", `output ${i} has no script`);
|
|
410
|
+
if (o.amountSompi <= 0n) throw spendError("SILVER_SPEND_INVALID_OUTPUT", `output ${i} has no value`);
|
|
411
|
+
return { valueSompi: o.amountSompi.toString(), scriptPublicKey: { version: Number(spk.version), script: String(spk.script).toLowerCase() } };
|
|
412
|
+
});
|
|
413
|
+
const totalOut = outputs.reduce((s, o) => s + BigInt(o.valueSompi), 0n);
|
|
414
|
+
if (totalOut > u.amountSompi) throw spendError("SILVER_SPEND_INSUFFICIENT_VALUE", `outputs ${totalOut} exceed the contract output ${u.amountSompi}`);
|
|
415
|
+
const base = {
|
|
416
|
+
networkId: request.networkId,
|
|
417
|
+
contractName,
|
|
418
|
+
entry: request.entry,
|
|
419
|
+
input: {
|
|
420
|
+
outpoint: { transactionId: u.outpoint.transactionId, index: u.outpoint.index },
|
|
421
|
+
amountSompi: u.amountSompi.toString(),
|
|
422
|
+
scriptPublicKey: { version: lock.version, script: lock.script },
|
|
423
|
+
blockDaaScore: u.blockDaaScore.toString(),
|
|
424
|
+
isCoinbase: u.isCoinbase,
|
|
425
|
+
sequence: (request.sequence ?? 0n).toString(),
|
|
426
|
+
sigOpCount: request.sigOpCount ?? Math.max(1, signers.length)
|
|
427
|
+
},
|
|
428
|
+
outputs
|
|
429
|
+
};
|
|
430
|
+
const placeholder = draftUnlock(request.artifact, contractName, request.entry, request.args, () => PLACEHOLDER_SIG);
|
|
431
|
+
const priced = measureBuiltTransactionMass(draftTx(k, base, placeholder, request.networkId), request.networkId);
|
|
432
|
+
if (!priced.standard) throw spendError("TX_MASS_ABOVE_STANDARD_LIMIT", `mass ${priced.mass} exceeds the maximum standard mass ${priced.maximumStandardMass}`);
|
|
433
|
+
const fee = u.amountSompi - totalOut;
|
|
434
|
+
if (fee < priced.minimumFeeSompi) {
|
|
435
|
+
throw spendError("FEE_BELOW_NETWORK_MINIMUM", `the outputs leave ${fee} sompi of fee; the SDK minimum for this spend is ${priced.minimumFeeSompi}`);
|
|
436
|
+
}
|
|
437
|
+
const unsigned = draftTx(k, base, "", request.networkId);
|
|
438
|
+
return {
|
|
439
|
+
schema: SILVER_SPEND_DRAFT_SCHEMA,
|
|
440
|
+
...base,
|
|
441
|
+
signers,
|
|
442
|
+
feeSompi: fee.toString(),
|
|
443
|
+
mass: priced.mass.toString(),
|
|
444
|
+
storageMass: String(unsigned.storageMass),
|
|
445
|
+
unlockHexLength: placeholder.length,
|
|
446
|
+
unsignedTxId: String(unsigned.id)
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
function signSilverSpend(draft, privateKey) {
|
|
450
|
+
if (draft?.schema !== SILVER_SPEND_DRAFT_SCHEMA) throw spendError("SILVER_SPEND_DRAFT_INVALID", "not a SilverScript spend draft");
|
|
451
|
+
const k = loadManagedKaspaWasmSync();
|
|
452
|
+
const unsigned = draftTx(k, draft, "", draft.networkId);
|
|
453
|
+
if (String(unsigned.id) !== draft.unsignedTxId) throw spendError("SILVER_SPEND_DRAFT_INVALID", "the draft does not rebuild to the transaction it describes");
|
|
454
|
+
const inputSignature = String(k.createInputSignature(unsigned, 0, new k.PrivateKey(privateKey), k.SighashType.All));
|
|
455
|
+
return Buffer.from(silverSigFromInputSignature(inputSignature)).toString("hex");
|
|
456
|
+
}
|
|
457
|
+
function finalizeSilverSpend(draft, artifact, args, signatures) {
|
|
458
|
+
if (draft?.schema !== SILVER_SPEND_DRAFT_SCHEMA) throw spendError("SILVER_SPEND_DRAFT_INVALID", "not a SilverScript spend draft");
|
|
459
|
+
const k = loadManagedKaspaWasmSync();
|
|
460
|
+
const lock = silverP2shLock(silContractBytecodeHex(getSilContract(artifact, draft.contractName).contract));
|
|
461
|
+
if (lock.script !== draft.input.scriptPublicKey.script) throw spendError("SILVER_SPEND_LOCK_MISMATCH", "the artifact is not the contract the draft spends");
|
|
462
|
+
const unlock = draftUnlock(artifact, draft.contractName, draft.entry, args, (slot) => {
|
|
463
|
+
const sig = signatures[slot.signer];
|
|
464
|
+
if (!sig) throw spendError("SILVER_SPEND_SIGNATURE_MISSING", `no signature from '${slot.signer}'`);
|
|
465
|
+
return { kind: "bytes", value: Buffer.from(sig, "hex") };
|
|
466
|
+
});
|
|
467
|
+
if (unlock.length !== draft.unlockHexLength) {
|
|
468
|
+
throw spendError("SILVER_SPEND_UNLOCK_SIZE_CHANGED", "the signed unlock is not the size the fee was checked for");
|
|
469
|
+
}
|
|
470
|
+
const tx = draftTx(k, draft, unlock, draft.networkId);
|
|
471
|
+
if (String(tx.id) !== draft.unsignedTxId) throw spendError("SILVER_SPEND_DRAFT_INVALID", "the finalized transaction differs from the draft");
|
|
472
|
+
return { rpcTransaction: parseWasmTxToRpc(tx.serializeToObject()), txId: String(tx.id), signatureScriptHex: unlock };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/silver-covenant.ts
|
|
476
|
+
import {
|
|
477
|
+
encodeSilverEntryArgs as encodeSilverEntryArgs2,
|
|
478
|
+
getSilContract as getSilContract2,
|
|
479
|
+
loadManagedKaspaWasmSync as loadManagedKaspaWasmSync2,
|
|
480
|
+
silContractBytecodeHex as silContractBytecodeHex2,
|
|
481
|
+
silverP2shLock as silverP2shLock2,
|
|
482
|
+
silverUnlockScript as silverUnlockScript2
|
|
483
|
+
} from "@hardkas/core";
|
|
484
|
+
import { calculateUpstreamStorageMass as calculateUpstreamStorageMass2, measureBuiltTransactionMass as measureBuiltTransactionMass2 } from "@hardkas/tx-builder";
|
|
485
|
+
function covenantError(code, message) {
|
|
486
|
+
const err = new Error(`${code}: ${message}`);
|
|
487
|
+
err.code = code;
|
|
488
|
+
return err;
|
|
489
|
+
}
|
|
490
|
+
var ZERO_SUBNET = "0000000000000000000000000000000000000000";
|
|
491
|
+
function checkBudget(budget, where) {
|
|
492
|
+
if (!Number.isInteger(budget) || budget < 0 || budget > 65535) {
|
|
493
|
+
throw covenantError("COVENANT_COMPUTE_BUDGET_INVALID", `${where}: compute budget ${budget} is not a u16`);
|
|
494
|
+
}
|
|
495
|
+
return budget;
|
|
496
|
+
}
|
|
497
|
+
function requireExplicitFeeForBudgets(budgets, feeSompi) {
|
|
498
|
+
if (budgets.some((b) => b > 0) && feeSompi === void 0) {
|
|
499
|
+
throw covenantError(
|
|
500
|
+
"COVENANT_V1_FEE_UNPRICED",
|
|
501
|
+
"the SDK mass calculator does not count v1 compute budgets (upstream TODO); pass feeSompi explicitly for inputs with computeBudget > 0"
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function settleFee(build, networkId, feeRate, explicitFee) {
|
|
506
|
+
if (explicitFee !== void 0) {
|
|
507
|
+
const measured = measureBuiltTransactionMass2(build(explicitFee), networkId);
|
|
508
|
+
if (!measured.standard) {
|
|
509
|
+
throw covenantError("TX_MASS_ABOVE_STANDARD_LIMIT", `mass ${measured.mass} exceeds the maximum standard mass ${measured.maximumStandardMass}`);
|
|
510
|
+
}
|
|
511
|
+
if (explicitFee < measured.minimumFeeSompi) {
|
|
512
|
+
throw covenantError("FEE_BELOW_NETWORK_MINIMUM", `fee ${explicitFee} is below the SDK minimum ${measured.minimumFeeSompi}`);
|
|
513
|
+
}
|
|
514
|
+
return { fee: explicitFee, measured };
|
|
515
|
+
}
|
|
516
|
+
let fee = 0n;
|
|
517
|
+
for (let round = 0; round < 8; round++) {
|
|
518
|
+
const measured = measureBuiltTransactionMass2(build(fee), networkId);
|
|
519
|
+
if (!measured.standard) {
|
|
520
|
+
throw covenantError("TX_MASS_ABOVE_STANDARD_LIMIT", `mass ${measured.mass} exceeds the maximum standard mass ${measured.maximumStandardMass}`);
|
|
521
|
+
}
|
|
522
|
+
const byRate = feeRate !== void 0 ? measured.mass * feeRate : 0n;
|
|
523
|
+
const required = measured.minimumFeeSompi > byRate ? measured.minimumFeeSompi : byRate;
|
|
524
|
+
if (required <= fee) return { fee, measured };
|
|
525
|
+
fee = required;
|
|
526
|
+
}
|
|
527
|
+
throw covenantError("COVENANT_FEE_UNRESOLVED", "the fee did not converge");
|
|
528
|
+
}
|
|
529
|
+
function buildCovenantGenesis(request) {
|
|
530
|
+
const k = loadManagedKaspaWasmSync2();
|
|
531
|
+
const { contract } = getSilContract2(request.artifact, request.contractName);
|
|
532
|
+
const lock = silverP2shLock2(silContractBytecodeHex2(contract));
|
|
533
|
+
if (request.funding.length === 0) throw covenantError("COVENANT_GENESIS_UNFUNDED", "a genesis needs at least one funding input");
|
|
534
|
+
if (!k.Address.validate(request.changeAddress)) throw covenantError("COVENANT_INVALID_ADDRESS", `'${request.changeAddress}' is not a Kaspa address`);
|
|
535
|
+
const inputs = request.funding.map((f, i) => {
|
|
536
|
+
const key = new k.PrivateKey(f.privateKey);
|
|
537
|
+
const expected = k.payToAddressScript(key.toKeypair().toAddress(request.networkId));
|
|
538
|
+
if (Number(f.scriptPublicKey.version) !== Number(expected.version) || String(f.scriptPublicKey.script).toLowerCase() !== String(expected.script)) {
|
|
539
|
+
throw covenantError("COVENANT_FUNDING_KEY_MISMATCH", `funding input ${i} is not a P2PK output of its key`);
|
|
540
|
+
}
|
|
541
|
+
return { ...f, computeBudget: checkBudget(f.computeBudget, `funding input ${i}`), key };
|
|
542
|
+
});
|
|
543
|
+
const totalIn = inputs.reduce((s, f) => s + f.amountSompi, 0n);
|
|
544
|
+
const make = (fee2, signatureScripts) => {
|
|
545
|
+
const change = totalIn - request.valueSompi - fee2;
|
|
546
|
+
if (change < 0n) throw covenantError("COVENANT_GENESIS_INSUFFICIENT_FUNDS", `inputs ${totalIn} cannot cover ${request.valueSompi} + fee ${fee2}`);
|
|
547
|
+
const outputs = [{ value: request.valueSompi, scriptPublicKey: new k.ScriptPublicKey(lock.version, lock.script) }];
|
|
548
|
+
if (change > 0n) outputs.push({ value: change, scriptPublicKey: k.payToAddressScript(new k.Address(request.changeAddress)) });
|
|
549
|
+
const tx = new k.Transaction({
|
|
550
|
+
version: 1,
|
|
551
|
+
inputs: inputs.map((f, i) => ({
|
|
552
|
+
previousOutpoint: f.outpoint,
|
|
553
|
+
signatureScript: signatureScripts?.[i] ?? "",
|
|
554
|
+
sequence: 0n,
|
|
555
|
+
sigOpCount: 0,
|
|
556
|
+
computeBudget: f.computeBudget,
|
|
557
|
+
utxo: {
|
|
558
|
+
outpoint: f.outpoint,
|
|
559
|
+
amount: f.amountSompi,
|
|
560
|
+
scriptPublicKey: new k.ScriptPublicKey(Number(f.scriptPublicKey.version), String(f.scriptPublicKey.script)),
|
|
561
|
+
blockDaaScore: f.blockDaaScore,
|
|
562
|
+
isCoinbase: f.isCoinbase
|
|
563
|
+
}
|
|
564
|
+
})),
|
|
565
|
+
outputs,
|
|
566
|
+
lockTime: 0n,
|
|
567
|
+
subnetworkId: ZERO_SUBNET,
|
|
568
|
+
gas: 0n,
|
|
569
|
+
payload: ""
|
|
570
|
+
});
|
|
571
|
+
tx.populateGenesisCovenants([{ authorizingInput: 0, outputs: [0] }]);
|
|
572
|
+
tx.storageMass = calculateUpstreamStorageMass2(
|
|
573
|
+
inputs.map((f) => f.amountSompi),
|
|
574
|
+
change > 0n ? [request.valueSompi, change] : [request.valueSompi],
|
|
575
|
+
request.networkId
|
|
576
|
+
);
|
|
577
|
+
return tx;
|
|
578
|
+
};
|
|
579
|
+
requireExplicitFeeForBudgets(inputs.map((f) => f.computeBudget), request.feeSompi);
|
|
580
|
+
const { fee, measured } = settleFee((f) => make(f), request.networkId, request.feeRateSompiPerGram, request.feeSompi);
|
|
581
|
+
const unsigned = make(fee);
|
|
582
|
+
const signatures = inputs.map((f, i) => String(k.createInputSignature(unsigned, i, f.key, k.SighashType.All)));
|
|
583
|
+
const signed = make(fee, signatures);
|
|
584
|
+
const binding = signed.outputs[0].covenant;
|
|
585
|
+
if (!binding) throw covenantError("COVENANT_GENESIS_UNBOUND", "the SDK did not bind the covenant output");
|
|
586
|
+
return {
|
|
587
|
+
transaction: signed,
|
|
588
|
+
rpcTransaction: parseWasmTxToRpc(signed.serializeToObject()),
|
|
589
|
+
txId: String(signed.id),
|
|
590
|
+
covenantId: String(binding.covenantId),
|
|
591
|
+
lockingScript: lock,
|
|
592
|
+
feeSompi: fee,
|
|
593
|
+
mass: measured.mass,
|
|
594
|
+
storageMass: BigInt(signed.storageMass),
|
|
595
|
+
changeSompi: totalIn - request.valueSompi - fee,
|
|
596
|
+
computeBudgets: inputs.map((f) => f.computeBudget),
|
|
597
|
+
assumptions: [
|
|
598
|
+
...measured.assumptions,
|
|
599
|
+
"compute budgets supplied by the caller; validated only by the node",
|
|
600
|
+
...request.feeSompi !== void 0 ? ["fee supplied by the caller: the SDK does not price v1 compute budgets"] : []
|
|
601
|
+
]
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
function buildCovenantTransition(request) {
|
|
605
|
+
const k = loadManagedKaspaWasmSync2();
|
|
606
|
+
const { name, contract } = getSilContract2(request.current, request.contractName);
|
|
607
|
+
const next = getSilContract2(request.successor, name).contract;
|
|
608
|
+
if (contract.delegate_entry_abi !== void 0) {
|
|
609
|
+
throw covenantError("COVENANT_BINDING_NOT_IMPLEMENTED", `contract '${name}' is a cov-bound leader contract; only auth-bound singletons are supported`);
|
|
610
|
+
}
|
|
611
|
+
const entry = contract.cov_decl_to_abi?.[request.policy];
|
|
612
|
+
if (!entry) {
|
|
613
|
+
throw covenantError(
|
|
614
|
+
"COVENANT_POLICY_NOT_FOUND",
|
|
615
|
+
`contract '${name}' declares no covenant policy '${request.policy}' (has: ${Object.keys(contract.cov_decl_to_abi ?? {}).join(", ") || "none"})`
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
if (!Buffer.from(contract.compiled.template_hash).equals(Buffer.from(next.compiled.template_hash))) {
|
|
619
|
+
throw covenantError("SILVER_SUCCESSOR_TEMPLATE_CHANGED", "the successor artifact is not the same template");
|
|
620
|
+
}
|
|
621
|
+
const bytecode = silContractBytecodeHex2(contract);
|
|
622
|
+
const lock = silverP2shLock2(bytecode);
|
|
623
|
+
const successorLock = silverP2shLock2(silContractBytecodeHex2(next));
|
|
624
|
+
const u = request.utxo;
|
|
625
|
+
if (Number(u.scriptPublicKey.version) !== lock.version || String(u.scriptPublicKey.script).toLowerCase() !== lock.script) {
|
|
626
|
+
throw covenantError("SILVER_SPEND_LOCK_MISMATCH", `output ${u.outpoint.transactionId}:${u.outpoint.index} is not locked to the current state of '${name}'`);
|
|
627
|
+
}
|
|
628
|
+
if (!/^[0-9a-f]{64}$/i.test(u.covenantId ?? "")) throw covenantError("COVENANT_ID_MISSING", "the covenant UTXO carries no covenant id");
|
|
629
|
+
const budget = checkBudget(request.computeBudget, "covenant input");
|
|
630
|
+
const unlock = silverUnlockScript2(bytecode, encodeSilverEntryArgs2({ artifact: request.current, contractName: name, entry, args: request.args }));
|
|
631
|
+
const make = (fee2) => {
|
|
632
|
+
const value = u.amountSompi - fee2;
|
|
633
|
+
if (value <= 0n) throw covenantError("COVENANT_INSUFFICIENT_VALUE", `covenant output of ${u.amountSompi} cannot pay a fee of ${fee2}`);
|
|
634
|
+
const tx2 = new k.Transaction({
|
|
635
|
+
version: 1,
|
|
636
|
+
inputs: [{
|
|
637
|
+
previousOutpoint: u.outpoint,
|
|
638
|
+
signatureScript: unlock,
|
|
639
|
+
sequence: 0n,
|
|
640
|
+
sigOpCount: 0,
|
|
641
|
+
computeBudget: budget,
|
|
642
|
+
utxo: {
|
|
643
|
+
outpoint: u.outpoint,
|
|
644
|
+
amount: u.amountSompi,
|
|
645
|
+
scriptPublicKey: new k.ScriptPublicKey(lock.version, lock.script),
|
|
646
|
+
blockDaaScore: u.blockDaaScore,
|
|
647
|
+
isCoinbase: u.isCoinbase,
|
|
648
|
+
covenantId: u.covenantId
|
|
649
|
+
}
|
|
650
|
+
}],
|
|
651
|
+
outputs: [{
|
|
652
|
+
value,
|
|
653
|
+
scriptPublicKey: new k.ScriptPublicKey(successorLock.version, successorLock.script),
|
|
654
|
+
covenant: { authorizingInput: 0, covenantId: u.covenantId }
|
|
655
|
+
}],
|
|
656
|
+
lockTime: 0n,
|
|
657
|
+
subnetworkId: ZERO_SUBNET,
|
|
658
|
+
gas: 0n,
|
|
659
|
+
payload: ""
|
|
660
|
+
});
|
|
661
|
+
tx2.storageMass = calculateUpstreamStorageMass2([u.amountSompi], [value], request.networkId);
|
|
662
|
+
return tx2;
|
|
663
|
+
};
|
|
664
|
+
requireExplicitFeeForBudgets([budget], request.feeSompi);
|
|
665
|
+
const { fee, measured } = settleFee(make, request.networkId, request.feeRateSompiPerGram, request.feeSompi);
|
|
666
|
+
const tx = make(fee);
|
|
667
|
+
return {
|
|
668
|
+
transaction: tx,
|
|
669
|
+
rpcTransaction: parseWasmTxToRpc(tx.serializeToObject()),
|
|
670
|
+
txId: String(tx.id),
|
|
671
|
+
covenantId: u.covenantId,
|
|
672
|
+
lockingScript: successorLock,
|
|
673
|
+
feeSompi: fee,
|
|
674
|
+
mass: measured.mass,
|
|
675
|
+
storageMass: BigInt(tx.storageMass),
|
|
676
|
+
successorSompi: u.amountSompi - fee,
|
|
677
|
+
computeBudgets: [budget],
|
|
678
|
+
assumptions: [
|
|
679
|
+
...measured.assumptions,
|
|
680
|
+
"compute budget supplied by the caller; validated only by the node",
|
|
681
|
+
...request.feeSompi !== void 0 ? ["fee supplied by the caller: the SDK does not price v1 compute budgets"] : []
|
|
682
|
+
]
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/silver-funding.ts
|
|
687
|
+
import { loadManagedKaspaWasmSync as loadManagedKaspaWasmSync3 } from "@hardkas/core";
|
|
688
|
+
import { calculateUpstreamStorageMass as calculateUpstreamStorageMass3, measureBuiltTransactionMass as measureBuiltTransactionMass3 } from "@hardkas/tx-builder";
|
|
689
|
+
function fundingError(code, message) {
|
|
690
|
+
const err = new Error(`${code}: ${message}`);
|
|
691
|
+
err.code = code;
|
|
692
|
+
return err;
|
|
693
|
+
}
|
|
694
|
+
function buildScriptFunding(request) {
|
|
695
|
+
const k = loadManagedKaspaWasmSync3();
|
|
696
|
+
const key = new k.PrivateKey(request.privateKey);
|
|
697
|
+
const address = key.toKeypair().toAddress(request.networkId);
|
|
698
|
+
const p2pk = k.payToAddressScript(address);
|
|
699
|
+
const own = { version: Number(p2pk.version), script: String(p2pk.script) };
|
|
700
|
+
const lock = request.lockingScript;
|
|
701
|
+
const make = (inputs, fee, signatureScripts) => {
|
|
702
|
+
const total = inputs.reduce((s, u) => s + u.amountSompi, 0n);
|
|
703
|
+
const change = total - request.valueSompi - fee;
|
|
704
|
+
const outputs = [{ value: request.valueSompi, scriptPublicKey: new k.ScriptPublicKey(lock.version, lock.script) }];
|
|
705
|
+
if (change > 0n) outputs.push({ value: change, scriptPublicKey: new k.ScriptPublicKey(own.version, own.script) });
|
|
706
|
+
const tx = new k.Transaction({
|
|
707
|
+
version: 0,
|
|
708
|
+
inputs: inputs.map((u, i) => ({
|
|
709
|
+
previousOutpoint: u.outpoint,
|
|
710
|
+
signatureScript: signatureScripts?.[i] ?? "",
|
|
711
|
+
sequence: 0n,
|
|
712
|
+
sigOpCount: 1,
|
|
713
|
+
utxo: {
|
|
714
|
+
outpoint: u.outpoint,
|
|
715
|
+
amount: u.amountSompi,
|
|
716
|
+
scriptPublicKey: new k.ScriptPublicKey(own.version, own.script),
|
|
717
|
+
blockDaaScore: u.blockDaaScore,
|
|
718
|
+
isCoinbase: u.isCoinbase
|
|
719
|
+
}
|
|
720
|
+
})),
|
|
721
|
+
outputs,
|
|
722
|
+
lockTime: 0n,
|
|
723
|
+
subnetworkId: "0000000000000000000000000000000000000000",
|
|
724
|
+
gas: 0n,
|
|
725
|
+
payload: ""
|
|
726
|
+
});
|
|
727
|
+
tx.storageMass = calculateUpstreamStorageMass3(
|
|
728
|
+
inputs.map((u) => u.amountSompi),
|
|
729
|
+
change > 0n ? [request.valueSompi, change] : [request.valueSompi],
|
|
730
|
+
request.networkId
|
|
731
|
+
);
|
|
732
|
+
return { tx, change };
|
|
733
|
+
};
|
|
734
|
+
for (const u of request.utxos) {
|
|
735
|
+
if (Number(u.scriptPublicKey.version) !== own.version || String(u.scriptPublicKey.script).toLowerCase() !== own.script) {
|
|
736
|
+
throw fundingError("FUNDING_KEY_MISMATCH", `${u.outpoint.transactionId}:${u.outpoint.index} is not a P2PK output of the funding key`);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
const selected = [];
|
|
740
|
+
for (const u of request.utxos) {
|
|
741
|
+
selected.push(u);
|
|
742
|
+
const total = selected.reduce((s, x) => s + x.amountSompi, 0n);
|
|
743
|
+
if (total <= request.valueSompi) continue;
|
|
744
|
+
let fee = 0n;
|
|
745
|
+
for (let round = 0; round < 8; round++) {
|
|
746
|
+
if (total < request.valueSompi + fee) break;
|
|
747
|
+
const measured = measureBuiltTransactionMass3(make(selected, fee).tx, request.networkId);
|
|
748
|
+
if (!measured.standard) throw fundingError("TX_MASS_ABOVE_STANDARD_LIMIT", `mass ${measured.mass} exceeds the maximum standard mass`);
|
|
749
|
+
if (measured.minimumFeeSompi <= fee) {
|
|
750
|
+
const unsigned = make(selected, fee).tx;
|
|
751
|
+
const signatures = selected.map((_, i) => String(k.createInputSignature(unsigned, i, key, k.SighashType.All)));
|
|
752
|
+
const { tx, change } = make(selected, fee, signatures);
|
|
753
|
+
return {
|
|
754
|
+
rpcTransaction: parseWasmTxToRpc(tx.serializeToObject()),
|
|
755
|
+
txId: String(tx.id),
|
|
756
|
+
outputIndex: 0,
|
|
757
|
+
feeSompi: fee,
|
|
758
|
+
changeSompi: change,
|
|
759
|
+
spent: selected.map((s) => s.outpoint)
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
fee = measured.minimumFeeSompi;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
throw fundingError("FUNDING_INSUFFICIENT", `the given outputs cannot cover ${request.valueSompi} sompi plus the fee`);
|
|
766
|
+
}
|
|
767
|
+
|
|
239
768
|
// src/kaspa-sdk-keygen.ts
|
|
769
|
+
import { getNetworkPrefix } from "@hardkas/core";
|
|
240
770
|
var KaspaSdkKeyGenerator = class {
|
|
241
771
|
networkId;
|
|
242
772
|
sdkLoader;
|
|
243
773
|
constructor(options) {
|
|
244
774
|
this.networkId = options?.networkId || "simnet";
|
|
245
775
|
const rawLoader = options?.sdkLoader || (async () => {
|
|
246
|
-
|
|
776
|
+
const { loadKaspaWasm: loadKaspaWasm2 } = await import("./signer-backend-LHWY7ULI.js");
|
|
777
|
+
return await loadKaspaWasm2();
|
|
247
778
|
});
|
|
248
779
|
this.sdkLoader = async () => {
|
|
249
780
|
try {
|
|
@@ -267,7 +798,7 @@ var KaspaSdkKeyGenerator = class {
|
|
|
267
798
|
const hex = randomBytes.toString("hex");
|
|
268
799
|
const privKey = new sdk.PrivateKey(hex);
|
|
269
800
|
const kp = privKey.toKeypair();
|
|
270
|
-
const address = kp.toAddress(network).toString();
|
|
801
|
+
const address = kp.toAddress(getNetworkPrefix(network)).toString();
|
|
271
802
|
const privateKeyStr = typeof kp.privateKey === "object" ? hex : kp.privateKey;
|
|
272
803
|
const publicKeyStr = typeof kp.publicKey === "object" ? kp.publicKey.toString() : kp.publicKey;
|
|
273
804
|
if (typeof privateKeyStr !== "string" || !/^[0-9a-f]{64}$/i.test(privateKeyStr)) {
|
|
@@ -321,6 +852,7 @@ var KaspaSdkRealTxSigner = class {
|
|
|
321
852
|
try {
|
|
322
853
|
sdk = await this.sdkLoader();
|
|
323
854
|
} catch (e) {
|
|
855
|
+
if (typeof e?.code === "string" && e.code.startsWith("WASM_TOOLCHAIN_")) throw e;
|
|
324
856
|
throw new Error(
|
|
325
857
|
"Kaspa SDK real transaction signer dependency is not installed. Install/configure the supported Kaspa WASM SDK adapter."
|
|
326
858
|
);
|
|
@@ -341,12 +873,6 @@ var KaspaSdkRealTxSigner = class {
|
|
|
341
873
|
`UTXO ${u.outpoint.transactionId}:${u.outpoint.index} is missing scriptPublicKey required for signing.`
|
|
342
874
|
);
|
|
343
875
|
}
|
|
344
|
-
let spkHex = String(u.scriptPublicKey);
|
|
345
|
-
let spkVersion = 0;
|
|
346
|
-
if (spkHex.length >= 68) {
|
|
347
|
-
spkVersion = parseInt(spkHex.slice(0, 4), 16) || 0;
|
|
348
|
-
spkHex = spkHex.slice(4);
|
|
349
|
-
}
|
|
350
876
|
return {
|
|
351
877
|
address: account.address,
|
|
352
878
|
outpoint: {
|
|
@@ -355,25 +881,19 @@ var KaspaSdkRealTxSigner = class {
|
|
|
355
881
|
},
|
|
356
882
|
utxoEntry: {
|
|
357
883
|
amount: BigInt(u.amountSompi),
|
|
358
|
-
scriptPublicKey:
|
|
884
|
+
scriptPublicKey: toWasmScriptPublicKey(sdk, u.scriptPublicKey),
|
|
359
885
|
blockDaaScore: BigInt(u.blockDaaScore ?? 0),
|
|
360
886
|
isCoinbase: u.isCoinbase ?? false
|
|
361
887
|
}
|
|
362
888
|
};
|
|
363
889
|
});
|
|
364
|
-
const
|
|
365
|
-
(o) => new sdk.PaymentOutput(new sdk.Address(o.address), BigInt(o.amountSompi))
|
|
366
|
-
);
|
|
367
|
-
const changeAddress = plan.change ? plan.change.address : account.address;
|
|
368
|
-
const priorityFee = BigInt(plan.estimatedFeeSompi);
|
|
369
|
-
const unsignedTx = sdk.createTransaction(
|
|
890
|
+
const unsignedTx = createBalancedTransaction(sdk, {
|
|
370
891
|
utxos,
|
|
371
|
-
outputs,
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
);
|
|
892
|
+
outputs: planOutputsWithChange(plan),
|
|
893
|
+
feeSompi: BigInt(plan.estimatedFeeSompi)
|
|
894
|
+
});
|
|
375
895
|
const signedTx = sdk.signTransaction(unsignedTx, [privateKey], true);
|
|
376
|
-
const innerTx = signedTx
|
|
896
|
+
const innerTx = signedTx;
|
|
377
897
|
const txId = innerTx?.id;
|
|
378
898
|
const payload = JSON.stringify(
|
|
379
899
|
innerTx.toJSON(),
|
|
@@ -480,8 +1000,7 @@ async function appendToKeystoreJson(workspaceRoot, alias, accountData) {
|
|
|
480
1000
|
|
|
481
1001
|
// src/address-manager.ts
|
|
482
1002
|
import { createHash } from "crypto";
|
|
483
|
-
import {
|
|
484
|
-
var require2 = createRequire(import.meta.url);
|
|
1003
|
+
import { getNetworkPrefix as getNetworkPrefix2 } from "@hardkas/core";
|
|
485
1004
|
function resolveChain(chain) {
|
|
486
1005
|
if (chain === "receive" || chain === 0) return 0;
|
|
487
1006
|
if (chain === "change" || chain === 1) return 1;
|
|
@@ -513,12 +1032,16 @@ var AddressManager = {
|
|
|
513
1032
|
const hash = createHash("sha256").update(payload).digest("hex");
|
|
514
1033
|
let address;
|
|
515
1034
|
try {
|
|
516
|
-
const kaspa =
|
|
1035
|
+
const kaspa = loadKaspaWasmSync();
|
|
517
1036
|
const priv = new kaspa.PrivateKey(hash);
|
|
518
|
-
address = priv.toKeypair().toAddress(network).toString();
|
|
1037
|
+
address = priv.toKeypair().toAddress(getNetworkPrefix2(network)).toString();
|
|
519
1038
|
} catch (e) {
|
|
520
|
-
|
|
521
|
-
|
|
1039
|
+
if (typeof e?.code === "string" && e.code.startsWith("WASM_TOOLCHAIN_")) throw e;
|
|
1040
|
+
const err = new Error(
|
|
1041
|
+
`ADDRESS_DERIVATION_UNAVAILABLE: the Kaspa WASM SDK could not derive an address: ${e instanceof Error ? e.message : String(e)}`
|
|
1042
|
+
);
|
|
1043
|
+
err.code = "ADDRESS_DERIVATION_UNAVAILABLE";
|
|
1044
|
+
throw err;
|
|
522
1045
|
}
|
|
523
1046
|
return {
|
|
524
1047
|
address,
|
|
@@ -708,6 +1231,7 @@ export {
|
|
|
708
1231
|
KeystoreManager,
|
|
709
1232
|
LazyAccountAuthorizer,
|
|
710
1233
|
PrivateKeyAuthorizer,
|
|
1234
|
+
SILVER_SPEND_DRAFT_SCHEMA,
|
|
711
1235
|
SimulatedSigner,
|
|
712
1236
|
StaticSignatureScriptAuthorizer,
|
|
713
1237
|
UnsupportedKaspaKeyGenerator,
|
|
@@ -717,13 +1241,22 @@ export {
|
|
|
717
1241
|
WalletManagerImpl,
|
|
718
1242
|
WalletStateStoreJson,
|
|
719
1243
|
appendToKeystoreJson,
|
|
1244
|
+
assertAccountCompatible,
|
|
720
1245
|
assertSigningNetworkAllowed,
|
|
1246
|
+
assertValueConservation,
|
|
1247
|
+
buildCovenantGenesis,
|
|
1248
|
+
buildCovenantTransition,
|
|
1249
|
+
buildScriptFunding,
|
|
1250
|
+
buildSilverSweep,
|
|
1251
|
+
createBalancedTransaction,
|
|
721
1252
|
createDevSigner,
|
|
722
1253
|
createEmptyRealAccountStore,
|
|
723
1254
|
createLocalKaspaWallet,
|
|
1255
|
+
createScriptTransaction,
|
|
724
1256
|
describeAccount,
|
|
725
1257
|
detectCapabilities,
|
|
726
1258
|
ensureDevAccounts,
|
|
1259
|
+
finalizeSilverSpend,
|
|
727
1260
|
getDefaultRealAccountsPath,
|
|
728
1261
|
getKaspaSigningBackendStatus,
|
|
729
1262
|
getOrCreateDevAccount,
|
|
@@ -734,16 +1267,22 @@ export {
|
|
|
734
1267
|
listHardkasAccounts,
|
|
735
1268
|
listRealDevAccounts,
|
|
736
1269
|
loadKaspaWasm,
|
|
1270
|
+
loadKaspaWasmSync,
|
|
737
1271
|
loadOrCreateRealAccountStore,
|
|
738
1272
|
loadRealAccountStore,
|
|
739
1273
|
loadRealAccountStoreSync,
|
|
1274
|
+
parseWasmTxToRpc,
|
|
1275
|
+
planOutputsWithChange,
|
|
740
1276
|
prepareEvmAccountExport,
|
|
1277
|
+
prepareSilverSpend,
|
|
741
1278
|
removeRealDevAccount,
|
|
742
1279
|
resolveHardkasAccount,
|
|
743
1280
|
resolveHardkasAccountAddress,
|
|
744
1281
|
resolveRealAccountOrAddress,
|
|
745
1282
|
saveRealAccountStore,
|
|
1283
|
+
signSilverSpend,
|
|
746
1284
|
signTxPlanArtifact,
|
|
1285
|
+
toWasmScriptPublicKey,
|
|
747
1286
|
validateAccountName,
|
|
748
1287
|
validateAddressNetwork,
|
|
749
1288
|
validateAddressPrefix,
|