@chainvue/verus-sdk 0.9.0 → 0.10.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.
Files changed (49) hide show
  1. package/README.md +1 -0
  2. package/dist/assemble/assembler.d.ts +66 -0
  3. package/dist/assemble/assembler.d.ts.map +1 -0
  4. package/dist/assemble/assembler.js +155 -0
  5. package/dist/assemble/assembler.js.map +1 -0
  6. package/dist/assemble/fundedIdentityUpdate.d.ts +35 -0
  7. package/dist/assemble/fundedIdentityUpdate.d.ts.map +1 -0
  8. package/dist/assemble/fundedIdentityUpdate.js +114 -0
  9. package/dist/assemble/fundedIdentityUpdate.js.map +1 -0
  10. package/dist/bundle.js +29167 -29285
  11. package/dist/currency/index.d.ts.map +1 -1
  12. package/dist/currency/index.js +32 -66
  13. package/dist/currency/index.js.map +1 -1
  14. package/dist/fork/boundary.d.ts +19 -0
  15. package/dist/fork/boundary.d.ts.map +1 -0
  16. package/dist/fork/boundary.js +49 -0
  17. package/dist/fork/boundary.js.map +1 -0
  18. package/dist/fork-shims.d.ts +7 -0
  19. package/dist/identity/index.d.ts +2 -2
  20. package/dist/identity/index.d.ts.map +1 -1
  21. package/dist/identity/index.js +180 -296
  22. package/dist/identity/index.js.map +1 -1
  23. package/dist/identity/public.d.ts +21 -0
  24. package/dist/identity/public.d.ts.map +1 -0
  25. package/dist/identity/public.js +38 -0
  26. package/dist/identity/public.js.map +1 -0
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/message/index.js +7 -7
  32. package/dist/message/index.js.map +1 -1
  33. package/dist/signing/index.d.ts +1 -1
  34. package/dist/signing/index.d.ts.map +1 -1
  35. package/dist/signing/index.js +10 -10
  36. package/dist/signing/index.js.map +1 -1
  37. package/dist/transfer/index.d.ts.map +1 -1
  38. package/dist/transfer/index.js +40 -62
  39. package/dist/transfer/index.js.map +1 -1
  40. package/dist/types/index.d.ts +0 -47
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/types/index.js +6 -0
  43. package/dist/types/index.js.map +1 -1
  44. package/dist/utils/index.d.ts.map +1 -1
  45. package/dist/utils/index.js +6 -11
  46. package/dist/utils/index.js.map +1 -1
  47. package/dist/utxo/index.js +4 -4
  48. package/dist/utxo/index.js.map +1 -1
  49. package/package.json +1 -1
@@ -38,19 +38,20 @@ exports.buildAndSignRegistration = buildAndSignRegistration;
38
38
  exports.buildAndSignIdentityUpdate = buildAndSignIdentityUpdate;
39
39
  const crypto_1 = require("crypto");
40
40
  const bn_js_1 = __importDefault(require("bn.js"));
41
- const verus_typescript_primitives_1 = require("verus-typescript-primitives");
42
- const verus_typescript_primitives_2 = require("verus-typescript-primitives");
43
- const verus_typescript_primitives_3 = require("verus-typescript-primitives");
44
- Object.defineProperty(exports, "nameAndParentAddrToIAddr", { enumerable: true, get: function () { return verus_typescript_primitives_3.nameAndParentAddrToIAddr; } });
45
- const utxo_lib_1 = require("@bitgo/utxo-lib");
41
+ const boundary_js_1 = require("../fork/boundary.js");
42
+ const boundary_js_2 = require("../fork/boundary.js");
43
+ const boundary_js_3 = require("../fork/boundary.js");
44
+ Object.defineProperty(exports, "nameAndParentAddrToIAddr", { enumerable: true, get: function () { return boundary_js_3.nameAndParentAddrToIAddr; } });
45
+ const boundary_js_4 = require("../fork/boundary.js");
46
46
  const index_js_1 = require("../constants/index.js");
47
47
  const index_js_2 = require("../utils/index.js");
48
48
  const index_js_3 = require("../signing/index.js");
49
- const index_js_4 = require("../utxo/index.js");
49
+ const assembler_js_1 = require("../assemble/assembler.js");
50
+ const fundedIdentityUpdate_js_1 = require("../assemble/fundedIdentityUpdate.js");
50
51
  const brands_js_1 = require("../core/brands.js");
51
52
  const errors_js_1 = require("../errors.js");
52
- const index_js_5 = require("../keys/index.js");
53
- const { createUnfundedIdentityUpdate, completeFundedIdentityUpdate } = utxo_lib_1.smarttxs;
53
+ const index_js_4 = require("../keys/index.js");
54
+ const { createUnfundedIdentityUpdate } = boundary_js_4.smarttxs;
54
55
  const HASH160_BYTE_LENGTH = 20;
55
56
  const HASH256_BYTE_LENGTH = 32;
56
57
  /** Null identity hash (20 zero bytes) */
@@ -75,7 +76,7 @@ const LOCK_DELAY_SANITY_BLOCKS = 525600;
75
76
  function assertAddressVersion(address, expectedVersion, label) {
76
77
  let version;
77
78
  try {
78
- version = (0, verus_typescript_primitives_3.fromBase58Check)(address).version;
79
+ version = (0, boundary_js_3.fromBase58Check)(address).version;
79
80
  }
80
81
  catch {
81
82
  throw new errors_js_1.TransactionBuildError(`${label} is not a valid base58check address: ${JSON.stringify(address)}`);
@@ -93,7 +94,7 @@ function assertAddressVersion(address, expectedVersion, label) {
93
94
  * primary authority (currency define; update/lock/unlock check inline).
94
95
  */
95
96
  function assertWifIsPrimary(wif, identity, network) {
96
- const signerAddress = utxo_lib_1.ECPair.fromWIF(wif, network).getAddress();
97
+ const signerAddress = boundary_js_4.ECPair.fromWIF(wif, network).getAddress();
97
98
  const currentPrimaries = (identity.primary_addresses ?? []).map((k) => k.toAddress());
98
99
  if (!currentPrimaries.includes(signerAddress)) {
99
100
  throw new errors_js_1.TransactionBuildError(`the provided WIF (${signerAddress}) is not among the identity's primary addresses ` +
@@ -150,9 +151,9 @@ function calculateCommitmentHash(serializedReservation) {
150
151
  * Serialize a CCommitmentHash
151
152
  */
152
153
  function serializeCommitmentHash(hash) {
153
- const tokenOutput = new verus_typescript_primitives_1.TokenOutput({
154
+ const tokenOutput = new boundary_js_1.TokenOutput({
154
155
  version: new bn_js_1.default(0),
155
- values: new verus_typescript_primitives_1.CurrencyValueMap(),
156
+ values: new boundary_js_1.CurrencyValueMap(),
156
157
  });
157
158
  const tokenBuf = tokenOutput.toBuffer();
158
159
  return Buffer.concat([tokenBuf, hash]);
@@ -161,43 +162,43 @@ function serializeCommitmentHash(hash) {
161
162
  * Build the commitment output script
162
163
  */
163
164
  function buildCommitmentScript(commitmentHashBuf, controlAddress) {
164
- const controlDest = new verus_typescript_primitives_1.TxDestination(verus_typescript_primitives_1.KeyID.fromAddress(controlAddress));
165
- const master = new verus_typescript_primitives_1.OptCCParams({
165
+ const controlDest = new boundary_js_1.TxDestination(boundary_js_1.KeyID.fromAddress(controlAddress));
166
+ const master = new boundary_js_1.OptCCParams({
166
167
  version: new bn_js_1.default(3),
167
- eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_NONE),
168
+ eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_NONE),
168
169
  m: new bn_js_1.default(1),
169
170
  n: new bn_js_1.default(1),
170
171
  destinations: [controlDest],
171
172
  vdata: [],
172
173
  });
173
- const params = new verus_typescript_primitives_1.OptCCParams({
174
+ const params = new boundary_js_1.OptCCParams({
174
175
  version: new bn_js_1.default(3),
175
- eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_IDENTITY_COMMITMENT),
176
+ eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_IDENTITY_COMMITMENT),
176
177
  m: new bn_js_1.default(1),
177
178
  n: new bn_js_1.default(1),
178
179
  destinations: [controlDest],
179
180
  vdata: [commitmentHashBuf],
180
181
  });
181
- const script = new verus_typescript_primitives_1.SmartTransactionScript(master, params);
182
+ const script = new boundary_js_1.SmartTransactionScript(master, params);
182
183
  return script.toBuffer();
183
184
  }
184
185
  /**
185
186
  * Build the name reservation output script
186
187
  */
187
188
  function buildReservationScript(newIdentityIAddress, serializedReservation, isAdvanced = false) {
188
- const identityDest = new verus_typescript_primitives_1.TxDestination(verus_typescript_primitives_1.IdentityID.fromAddress(newIdentityIAddress));
189
+ const identityDest = new boundary_js_1.TxDestination(boundary_js_1.IdentityID.fromAddress(newIdentityIAddress));
189
190
  const evalCode = isAdvanced
190
191
  ? EVAL_IDENTITY_ADVANCEDRESERVATION
191
- : verus_typescript_primitives_2.EVALS.EVAL_IDENTITY_RESERVATION;
192
- const master = new verus_typescript_primitives_1.OptCCParams({
192
+ : boundary_js_2.EVALS.EVAL_IDENTITY_RESERVATION;
193
+ const master = new boundary_js_1.OptCCParams({
193
194
  version: new bn_js_1.default(3),
194
- eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_NONE),
195
+ eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_NONE),
195
196
  m: new bn_js_1.default(1),
196
197
  n: new bn_js_1.default(1),
197
198
  destinations: [identityDest],
198
199
  vdata: [],
199
200
  });
200
- const params = new verus_typescript_primitives_1.OptCCParams({
201
+ const params = new boundary_js_1.OptCCParams({
201
202
  version: new bn_js_1.default(3),
202
203
  eval_code: new bn_js_1.default(evalCode),
203
204
  m: new bn_js_1.default(1),
@@ -205,14 +206,14 @@ function buildReservationScript(newIdentityIAddress, serializedReservation, isAd
205
206
  destinations: [identityDest],
206
207
  vdata: [serializedReservation],
207
208
  });
208
- const script = new verus_typescript_primitives_1.SmartTransactionScript(master, params);
209
+ const script = new boundary_js_1.SmartTransactionScript(master, params);
209
210
  return script.toBuffer();
210
211
  }
211
212
  /**
212
213
  * Build an identity definition output script from an Identity object
213
214
  */
214
215
  function buildIdentityScript(identity) {
215
- const identityScript = verus_typescript_primitives_1.IdentityScript.fromIdentity(identity);
216
+ const identityScript = boundary_js_1.IdentityScript.fromIdentity(identity);
216
217
  return identityScript.toBuffer();
217
218
  }
218
219
  /**
@@ -227,7 +228,7 @@ function deriveIdentityAddress(name, parentIAddress) {
227
228
  if (parentIAddress) {
228
229
  assertAddressVersion(parentIAddress, index_js_1.I_ADDR_VERSION, 'parent');
229
230
  }
230
- return (0, verus_typescript_primitives_3.nameAndParentAddrToIAddr)(name, parentIAddress || undefined);
231
+ return (0, boundary_js_3.nameAndParentAddrToIAddr)(name, parentIAddress || undefined);
231
232
  }
232
233
  /**
233
234
  * Determine if a parent is the VRSC root system
@@ -322,26 +323,26 @@ function identityPaymentScript(iAddress) {
322
323
  * raw string here is exactly the hole that let a wrong-kind address through.
323
324
  */
324
325
  function buildReferralPaymentScript(iAddress) {
325
- const identityDest = new verus_typescript_primitives_1.TxDestination(verus_typescript_primitives_1.IdentityID.fromAddress(iAddress));
326
+ const identityDest = new boundary_js_1.TxDestination(boundary_js_1.IdentityID.fromAddress(iAddress));
326
327
  // Master: EVAL_NONE outputs have empty master (no index destinations)
327
328
  // This matches the daemon's MakeMofNCCScript for EVAL_NONE condition objects
328
- const master = new verus_typescript_primitives_1.OptCCParams({
329
+ const master = new boundary_js_1.OptCCParams({
329
330
  version: new bn_js_1.default(3),
330
- eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_NONE),
331
+ eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_NONE),
331
332
  m: new bn_js_1.default(0),
332
333
  n: new bn_js_1.default(0),
333
334
  destinations: [],
334
335
  vdata: [],
335
336
  });
336
- const params = new verus_typescript_primitives_1.OptCCParams({
337
+ const params = new boundary_js_1.OptCCParams({
337
338
  version: new bn_js_1.default(3),
338
- eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_NONE),
339
+ eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_NONE),
339
340
  m: new bn_js_1.default(1),
340
341
  n: new bn_js_1.default(1),
341
342
  destinations: [identityDest],
342
343
  vdata: [],
343
344
  });
344
- const script = new verus_typescript_primitives_1.SmartTransactionScript(master, params);
345
+ const script = new boundary_js_1.SmartTransactionScript(master, params);
345
346
  return script.toBuffer();
346
347
  }
347
348
  /**
@@ -364,17 +365,17 @@ function createIdentityObject(params) {
364
365
  // R-address primary or an i-address authority is now a compile error at the
365
366
  // call site, where the raw string is parsed.
366
367
  validateMinSigs(params.minSigs ?? 1, params.primaryAddresses.length);
367
- const primaryKeys = params.primaryAddresses.map(addr => verus_typescript_primitives_1.KeyID.fromAddress(addr));
368
- const identity = new verus_typescript_primitives_1.Identity({
369
- version: verus_typescript_primitives_1.Identity.VERSION_CURRENT,
368
+ const primaryKeys = params.primaryAddresses.map(addr => boundary_js_1.KeyID.fromAddress(addr));
369
+ const identity = new boundary_js_1.Identity({
370
+ version: boundary_js_1.Identity.VERSION_CURRENT,
370
371
  flags: new bn_js_1.default(0),
371
372
  min_sigs: new bn_js_1.default(params.minSigs || 1),
372
373
  primary_addresses: primaryKeys,
373
- parent: verus_typescript_primitives_1.IdentityID.fromAddress(params.parentIAddress),
374
- system_id: verus_typescript_primitives_1.IdentityID.fromAddress(params.systemId),
374
+ parent: boundary_js_1.IdentityID.fromAddress(params.parentIAddress),
375
+ system_id: boundary_js_1.IdentityID.fromAddress(params.systemId),
375
376
  name: params.name,
376
- revocation_authority: verus_typescript_primitives_1.IdentityID.fromAddress(params.revocationAuthority),
377
- recovery_authority: verus_typescript_primitives_1.IdentityID.fromAddress(params.recoveryAuthority),
377
+ revocation_authority: boundary_js_1.IdentityID.fromAddress(params.revocationAuthority),
378
+ recovery_authority: boundary_js_1.IdentityID.fromAddress(params.recoveryAuthority),
378
379
  private_addresses: [],
379
380
  unlock_after: new bn_js_1.default(0),
380
381
  });
@@ -411,15 +412,15 @@ function buildRegistrationFeeOutput(parentCurrencyId, feeAmount, systemId, _cont
411
412
  * RESERVE_TRANSFER_FEE native.
412
413
  */
413
414
  function buildRegistrationFeeReserveTransfer(parentCurrencyId, feeAmount, systemId) {
414
- const destination = new verus_typescript_primitives_1.TxDestination(verus_typescript_primitives_1.KeyID.fromAddress(index_js_1.RESERVE_TRANSFER_EVAL_PKH));
415
- const values = new verus_typescript_primitives_1.CurrencyValueMap({
415
+ const destination = new boundary_js_1.TxDestination(boundary_js_1.KeyID.fromAddress(index_js_1.RESERVE_TRANSFER_EVAL_PKH));
416
+ const values = new boundary_js_1.CurrencyValueMap({
416
417
  value_map: new Map([[parentCurrencyId, new bn_js_1.default(feeAmount.toString(10))]]),
417
418
  multivalue: false,
418
419
  });
419
- const parentHash = (0, verus_typescript_primitives_3.fromBase58Check)(parentCurrencyId).hash;
420
- const transferDest = new verus_typescript_primitives_1.TransferDestination({ type: verus_typescript_primitives_1.DEST_ID, destination_bytes: Buffer.from(parentHash) });
421
- const flags = verus_typescript_primitives_1.RESERVE_TRANSFER_VALID.or(verus_typescript_primitives_1.RESERVE_TRANSFER_BURN_CHANGE_PRICE);
422
- const resTransfer = new verus_typescript_primitives_1.ReserveTransfer({
420
+ const parentHash = (0, boundary_js_3.fromBase58Check)(parentCurrencyId).hash;
421
+ const transferDest = new boundary_js_1.TransferDestination({ type: boundary_js_1.DEST_ID, destination_bytes: Buffer.from(parentHash) });
422
+ const flags = boundary_js_1.RESERVE_TRANSFER_VALID.or(boundary_js_1.RESERVE_TRANSFER_BURN_CHANGE_PRICE);
423
+ const resTransfer = new boundary_js_1.ReserveTransfer({
423
424
  values,
424
425
  version: new bn_js_1.default(1),
425
426
  flags,
@@ -428,15 +429,15 @@ function buildRegistrationFeeReserveTransfer(parentCurrencyId, feeAmount, system
428
429
  transfer_destination: transferDest,
429
430
  dest_currency_id: parentCurrencyId,
430
431
  });
431
- const master = new verus_typescript_primitives_1.OptCCParams({
432
- version: new bn_js_1.default(3), eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_NONE), m: new bn_js_1.default(1), n: new bn_js_1.default(1),
432
+ const master = new boundary_js_1.OptCCParams({
433
+ version: new bn_js_1.default(3), eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_NONE), m: new bn_js_1.default(1), n: new bn_js_1.default(1),
433
434
  destinations: [destination], vdata: [],
434
435
  });
435
- const params = new verus_typescript_primitives_1.OptCCParams({
436
- version: new bn_js_1.default(3), eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_RESERVE_TRANSFER), m: new bn_js_1.default(1), n: new bn_js_1.default(1),
436
+ const params = new boundary_js_1.OptCCParams({
437
+ version: new bn_js_1.default(3), eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_RESERVE_TRANSFER), m: new bn_js_1.default(1), n: new bn_js_1.default(1),
437
438
  destinations: [destination], vdata: [resTransfer.toBuffer()],
438
439
  });
439
- const script = new verus_typescript_primitives_1.SmartTransactionScript(master, params);
440
+ const script = new boundary_js_1.SmartTransactionScript(master, params);
440
441
  return { script: script.toBuffer(), nativeValue: index_js_1.RESERVE_TRANSFER_FEE };
441
442
  }
442
443
  /**
@@ -449,10 +450,10 @@ function buildTokenChangeOutput(changeAddress, currencyChanges) {
449
450
  // R-addresses, and reject a P2SH address (not a valid reserve destination).
450
451
  let destination;
451
452
  if ((0, brands_js_1.isIAddress)(changeAddress)) {
452
- destination = new verus_typescript_primitives_1.TxDestination(verus_typescript_primitives_1.IdentityID.fromAddress(changeAddress));
453
+ destination = new boundary_js_1.TxDestination(boundary_js_1.IdentityID.fromAddress(changeAddress));
453
454
  }
454
455
  else if ((0, brands_js_1.isRAddress)(changeAddress)) {
455
- destination = new verus_typescript_primitives_1.TxDestination(verus_typescript_primitives_1.KeyID.fromAddress(changeAddress));
456
+ destination = new boundary_js_1.TxDestination(boundary_js_1.KeyID.fromAddress(changeAddress));
456
457
  }
457
458
  else {
458
459
  throw new errors_js_1.TransactionBuildError(`token change address must be an R-address or identity i-address, got: ${changeAddress}`);
@@ -463,28 +464,28 @@ function buildTokenChangeOutput(changeAddress, currencyChanges) {
463
464
  valueMap.set(currency, new bn_js_1.default(amount.toString(10)));
464
465
  }
465
466
  }
466
- const values = new verus_typescript_primitives_1.CurrencyValueMap({
467
+ const values = new boundary_js_1.CurrencyValueMap({
467
468
  value_map: valueMap,
468
469
  multivalue: false,
469
470
  });
470
- const tokenOutput = new verus_typescript_primitives_1.TokenOutput({ version: new bn_js_1.default(1), values });
471
- const master = new verus_typescript_primitives_1.OptCCParams({
471
+ const tokenOutput = new boundary_js_1.TokenOutput({ version: new bn_js_1.default(1), values });
472
+ const master = new boundary_js_1.OptCCParams({
472
473
  version: new bn_js_1.default(3),
473
- eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_NONE),
474
+ eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_NONE),
474
475
  m: new bn_js_1.default(1),
475
476
  n: new bn_js_1.default(1),
476
477
  destinations: [destination],
477
478
  vdata: [],
478
479
  });
479
- const params = new verus_typescript_primitives_1.OptCCParams({
480
+ const params = new boundary_js_1.OptCCParams({
480
481
  version: new bn_js_1.default(3),
481
- eval_code: new bn_js_1.default(verus_typescript_primitives_2.EVALS.EVAL_RESERVE_OUTPUT),
482
+ eval_code: new bn_js_1.default(boundary_js_2.EVALS.EVAL_RESERVE_OUTPUT),
482
483
  m: new bn_js_1.default(1),
483
484
  n: new bn_js_1.default(1),
484
485
  destinations: [destination],
485
486
  vdata: [tokenOutput.toBuffer()],
486
487
  });
487
- const script = new verus_typescript_primitives_1.SmartTransactionScript(master, params);
488
+ const script = new boundary_js_1.SmartTransactionScript(master, params);
488
489
  return { script: script.toBuffer(), nativeValue: 0n };
489
490
  }
490
491
  // ─── Validation ──────────────────────────────────────────────────
@@ -493,7 +494,7 @@ function validateIdentityWif(wif) {
493
494
  if (!wif || typeof wif !== 'string') {
494
495
  throw new errors_js_1.InvalidWifError('WIF is required');
495
496
  }
496
- const check = (0, index_js_5.validateWif)(wif);
497
+ const check = (0, index_js_4.validateWif)(wif);
497
498
  if (!check.valid) {
498
499
  throw new errors_js_1.InvalidWifError(check.error);
499
500
  }
@@ -517,59 +518,30 @@ function buildAndSignCommitment(params, network) {
517
518
  throw new errors_js_1.TransactionBuildError('At least one UTXO is required');
518
519
  }
519
520
  const verusNetwork = (0, index_js_3.getNetwork)(network === 'testnet');
520
- const networkConfig = index_js_1.NETWORK_CONFIG[network];
521
521
  // The commitment output is controlled by, and must be spent by, the key that
522
522
  // completes the registration in step 2 — which signs with this same WIF. Using
523
523
  // changeAddress as the control address broke that when changeAddress differed
524
524
  // from the WIF's address (unsignable commitment), or was an i-address
525
525
  // (KeyID.fromAddress laundered it to an uncontrollable key — permanently
526
526
  // unspendable, wasting the commitment fee). Derive it from the WIF instead.
527
- const controlAddress = utxo_lib_1.ECPair.fromWIF(params.wif, verusNetwork).getAddress();
527
+ const controlAddress = boundary_js_4.ECPair.fromWIF(params.wif, verusNetwork).getAddress();
528
528
  const commitment = prepareNameCommitment(params.name, controlAddress, params.referral, params.parent, network, params.salt);
529
- const utxos = params.utxos;
530
- const selection = (0, index_js_4.selectUtxos)(utxos, 0n, new Map(), 1, networkConfig.chainId, undefined, true);
531
- const txb = new utxo_lib_1.TransactionBuilder(verusNetwork);
532
- txb.setVersion(4);
533
- txb.setExpiryHeight((0, index_js_3.resolveExpiryHeight)(params.expiryHeight));
534
- txb.setVersionGroupId(index_js_1.VERSION_GROUP_ID);
535
- for (const utxo of selection.selected) {
536
- txb.addInput(Buffer.from(utxo.txid, 'hex').reverse(), utxo.outputIndex, 0xffffffff, Buffer.from(utxo.script, 'hex'));
537
- }
538
- txb.addOutput(commitment.commitmentScript, 0);
539
- // If native-only UTXOs can't cover the fee, selectUtxos falls back to a
540
- // token-bearing UTXO and returns its token value as currencyChanges. Emit it
541
- // as a reserve-output change (bundled with the native change) — otherwise
542
- // that token value is silently forfeited to the miner.
543
- const hasTokenChange = selection.currencyChanges.size > 0;
544
- if (hasTokenChange || selection.nativeChange > 0n) {
545
- if (hasTokenChange) {
546
- const tokenChangeScript = buildTokenChangeOutput((0, brands_js_1.parseAddress)(params.changeAddress, 'changeAddress'), selection.currencyChanges);
547
- txb.addOutput(tokenChangeScript.script, (0, index_js_2.toSafeNumber)(selection.nativeChange));
548
- }
549
- else if (params.changeAddress.startsWith('i')) {
550
- // utxo-lib's addOutput only resolves base58 R-addresses; an i-address
551
- // changeAddress needs the explicit P2ID script (matching sendCurrency), or
552
- // it throws an untyped "no matching Script".
553
- txb.addOutput(identityPaymentScript((0, brands_js_1.parseIAddress)(params.changeAddress, 'changeAddress')), (0, index_js_2.toSafeNumber)(selection.nativeChange));
554
- }
555
- else {
556
- txb.addOutput(params.changeAddress, (0, index_js_2.toSafeNumber)(selection.nativeChange));
557
- }
558
- }
559
- // No token is paid out here (the commitment output carries none), so every
560
- // token in the selected inputs must return as change.
561
- (0, index_js_4.assertTokenConservation)(selection.selected, new Map(), selection.currencyChanges, networkConfig.chainId, 'name commitment');
562
- const unsignedTx = txb.buildIncomplete();
563
- // Native value conservation: the commitment output is 0 and change is native,
564
- // so the assembled native fee must equal selection.fee. The fork's absurd-fee
565
- // guard is blind for inputs > 2^32 sats (it truncates input value mod 2^32),
566
- // so this bigint check is the real backstop against a change-accounting slip.
567
- (0, index_js_3.assertNativeConservation)(selection.selected, unsignedTx.outs, selection.fee, 'name commitment');
568
- const { signedTx, txid } = (0, index_js_3.signTransactionSmart)(unsignedTx.toHex(), params.wif, selection.selected, verusNetwork);
529
+ // The commitment output carries no token and no native value; the assembler
530
+ // selects funding, emits change, and enforces conservation by construction.
531
+ const assembled = (0, assembler_js_1.assembleAndSign)({
532
+ network,
533
+ wif: params.wif,
534
+ expiryHeight: params.expiryHeight,
535
+ funding: params.utxos,
536
+ outputs: [{ script: commitment.commitmentScript, nativeSat: 0n }],
537
+ changeAddress: params.changeAddress,
538
+ fee: { policy: 'estimate' },
539
+ label: 'name commitment',
540
+ });
569
541
  return {
570
- signedTx,
571
- txid,
572
- fee: selection.fee,
542
+ signedTx: assembled.signedTx,
543
+ txid: assembled.txid,
544
+ fee: assembled.fee,
573
545
  identityAddress: commitment.identityAddress,
574
546
  commitmentData: {
575
547
  name: params.name,
@@ -600,7 +572,7 @@ function buildAndSignRegistration(params, network) {
600
572
  // is handed, so a mismatched WIF produces a tx the daemon rejects at broadcast
601
573
  // (and the commitment fee is wasted). Verify the WIF's hash is the commitment's
602
574
  // control hash up front. (The 20-byte control hash is embedded in the CC script.)
603
- const signerAddr = utxo_lib_1.ECPair.fromWIF(params.wif, verusNetwork).getAddress();
575
+ const signerAddr = boundary_js_4.ECPair.fromWIF(params.wif, verusNetwork).getAddress();
604
576
  const signerHash = (0, index_js_2.addressToScriptPubKey)(signerAddr).subarray(3, 23).toString('hex');
605
577
  if (!params.commitmentUtxo.script.toLowerCase().includes(signerHash)) {
606
578
  throw new errors_js_1.TransactionBuildError(`the provided WIF (${signerAddr}) does not control the name-commitment output; step 2 must be ` +
@@ -623,11 +595,11 @@ function buildAndSignRegistration(params, network) {
623
595
  const identityScript = buildIdentityScript(identity);
624
596
  const reservationScript = buildReservationScript((0, brands_js_1.parseIAddress)(identityAddress, 'identityAddress'), Buffer.from(commitData.namereservationHex, 'hex'), isSubId);
625
597
  if (isSubId) {
626
- return _buildSubIdRegistration(params, identity, identityScript, reservationScript, identityAddress, parentIAddress, systemId, verusNetwork);
598
+ return _buildSubIdRegistration(params, identityScript, reservationScript, identityAddress, parentIAddress, systemId, network);
627
599
  }
628
- return _buildVrscRegistration(params, identityScript, reservationScript, identityAddress, parentIAddress, systemId, verusNetwork);
600
+ return _buildVrscRegistration(params, identityScript, reservationScript, identityAddress, parentIAddress, network);
629
601
  }
630
- function _buildVrscRegistration(params, identityScript, reservationScript, identityAddress, parentIAddress, systemId, network) {
602
+ function _buildVrscRegistration(params, identityScript, reservationScript, identityAddress, parentIAddress, network) {
631
603
  const commitData = params.commitmentData;
632
604
  const hasReferral = !!commitData.referral;
633
605
  const fees = calculateRegistrationFees(hasReferral, params.registrationFee, params.referralLevels);
@@ -661,84 +633,52 @@ function _buildVrscRegistration(params, identityScript, reservationScript, ident
661
633
  // exactly (totalFee - issuerFee) every referred registration.
662
634
  const totalFee = params.registrationFee ?? index_js_1.DEFAULT_REGISTRATION_FEE;
663
635
  const totalReferralPayments = referralOutputs.reduce((sum, o) => sum + o.value, 0n);
664
- const requiredNative = hasReferral ? fees.issuerFee : totalFee;
665
- const numOutputs = 2 + referralOutputs.length + 1;
666
- const selection = (0, index_js_4.selectUtxos)(params.utxos, requiredNative, new Map(), numOutputs, systemId, undefined, true);
667
- const txb = new utxo_lib_1.TransactionBuilder(network);
668
- txb.setVersion(4);
669
- txb.setExpiryHeight((0, index_js_3.resolveExpiryHeight)(params.expiryHeight));
670
- txb.setVersionGroupId(index_js_1.VERSION_GROUP_ID);
671
- const commitUtxo = params.commitmentUtxo;
672
- txb.addInput(Buffer.from(commitUtxo.txid, 'hex').reverse(), commitUtxo.outputIndex, 0xffffffff, Buffer.from(commitUtxo.script, 'hex'));
673
- for (const utxo of selection.selected) {
674
- txb.addInput(Buffer.from(utxo.txid, 'hex').reverse(), utxo.outputIndex, 0xffffffff, Buffer.from(utxo.script, 'hex'));
675
- }
676
- txb.addOutput(identityScript, 0);
677
- for (const referralOut of referralOutputs) {
678
- txb.addOutput(referralOut.script, (0, index_js_2.toSafeNumber)(referralOut.value));
679
- }
680
- txb.addOutput(reservationScript, 0);
681
- // Registration needs ~80-100 native, so Phase-2 selection is especially
682
- // likely to exhaust pure-native UTXOs and pull a token-bearing one; return
683
- // its token value as reserve-output change instead of forfeiting it to the
684
- // miner. (The commitment input carries no currency.)
685
- const hasTokenChange = selection.currencyChanges.size > 0;
686
- if (hasTokenChange || selection.nativeChange > 0n) {
687
- if (hasTokenChange) {
688
- const tokenChangeScript = buildTokenChangeOutput((0, brands_js_1.parseAddress)(params.changeAddress, 'changeAddress'), selection.currencyChanges);
689
- txb.addOutput(tokenChangeScript.script, (0, index_js_2.toSafeNumber)(selection.nativeChange));
690
- }
691
- else if (params.changeAddress.startsWith('i')) {
692
- // utxo-lib's addOutput only resolves base58 R-addresses; an i-address
693
- // changeAddress needs the explicit P2ID script (matching sendCurrency), or
694
- // it throws an untyped "no matching Script".
695
- txb.addOutput(identityPaymentScript((0, brands_js_1.parseIAddress)(params.changeAddress, 'changeAddress')), (0, index_js_2.toSafeNumber)(selection.nativeChange));
696
- }
697
- else {
698
- txb.addOutput(params.changeAddress, (0, index_js_2.toSafeNumber)(selection.nativeChange));
699
- }
700
- }
701
- // Referral payouts are native; no token is paid out, so all token value in the
702
- // selected inputs must return as change.
703
- (0, index_js_4.assertTokenConservation)(selection.selected, new Map(), selection.currencyChanges, systemId, 'identity registration');
704
- const unsignedTx = txb.buildIncomplete();
705
- const allUtxos = [commitUtxo, ...selection.selected];
706
- // The registration fee is burned as an IMPLICIT miner fee (identity and
707
- // reservation outputs carry 0; referral payouts come out of the total) —
708
- // this matches on-chain registrations, and the daemon exempts recognized
709
- // identity definitions from its absurd-fee check (IS_HIGH_FEE). utxo-lib's
710
- // client-side fee-rate cap (default 2500 sat/vbyte) must be told the
711
- // intended absolute fee or build() throws "Transaction has absurd fees".
712
- const expectedImplicitFee = commitUtxo.satoshis + requiredNative - totalReferralPayments + selection.fee;
713
- // Independent value-conservation check on the assembled transaction: recompute
714
- // the native fee straight from inputs and outputs and require it to equal the
715
- // fee this path intends to pay. buildAndSign has the same guard; registration
716
- // moves the largest amounts (the registration fee is burned as implicit fee),
717
- // so a selection/accounting slip must fail loudly here instead of being paid
718
- // to miners.
719
- const assembledNativeFee = allUtxos.reduce((sum, u) => sum + u.satoshis, 0n) -
720
- unsignedTx.outs.reduce((sum, o) => sum + BigInt(o.value), 0n);
721
- if (assembledNativeFee !== expectedImplicitFee) {
722
- throw new errors_js_1.TransactionBuildError(`identity registration value conservation failed: assembled native fee ${assembledNativeFee} sat ` +
723
- `!= intended ${expectedImplicitFee} sat`);
724
- }
725
- const { signedTx, txid } = (0, index_js_3.signTransactionSmart)(unsignedTx.toHex(), params.wif, allUtxos, network, expectedImplicitFee);
636
+ // With a referral the registrant pays the discounted issuer fee, otherwise the
637
+ // full registration fee. Either way the referral payouts come OUT OF that
638
+ // outlay; the remainder is burned as the implicit miner fee.
639
+ const registrationOutlay = hasReferral ? fees.issuerFee : totalFee;
640
+ // The identity and reservation outputs carry 0 native; the referral payouts are
641
+ // the only value-bearing outputs. The rest of the outlay is a DECLARED burn, so
642
+ // the assembler funds it, sizes the fee cap for it, and enforces conservation.
643
+ const assembled = (0, assembler_js_1.assembleAndSign)({
644
+ network,
645
+ wif: params.wif,
646
+ expiryHeight: params.expiryHeight,
647
+ funding: params.utxos,
648
+ // The name-commitment output is spent as input 0 (it carries no currency).
649
+ leadingInputs: [params.commitmentUtxo],
650
+ outputs: [
651
+ { script: identityScript, nativeSat: 0n },
652
+ ...referralOutputs.map((o) => ({ script: o.script, nativeSat: o.value })),
653
+ { script: reservationScript, nativeSat: 0n },
654
+ ],
655
+ changeAddress: params.changeAddress,
656
+ // Legacy fee estimate: identity + referrals + reservation, plus the one extra
657
+ // change slot the original path counted on top of selectUtxos' own reserve.
658
+ feeOutputCount: 2 + referralOutputs.length + 1,
659
+ fee: {
660
+ policy: 'declared',
661
+ burnSat: registrationOutlay - totalReferralPayments,
662
+ reason: 'identity registration fee (burned as implicit miner fee)',
663
+ },
664
+ label: 'identity registration',
665
+ });
726
666
  return {
727
- signedTx,
728
- txid,
729
- fee: selection.fee,
667
+ signedTx: assembled.signedTx,
668
+ txid: assembled.txid,
669
+ fee: assembled.fee,
730
670
  identityAddress,
731
671
  // The registrant's registration outlay: the discounted issuer fee when
732
672
  // referred, the full fee otherwise. (Of this, referralPayments go to the
733
673
  // referrers and the remainder is the implicit miner fee.)
734
- registrationFee: requiredNative,
674
+ registrationFee: registrationOutlay,
735
675
  referralPayments: referralOutputs.length,
736
676
  referralAmountEach: fees.referralAmount,
737
- inputsUsed: allUtxos.length,
738
- nativeChange: selection.nativeChange,
677
+ inputsUsed: assembled.inputsUsed,
678
+ nativeChange: assembled.nativeChange,
739
679
  };
740
680
  }
741
- function _buildSubIdRegistration(params, identity, identityScript, reservationScript, identityAddress, parentIAddress, systemId, network) {
681
+ function _buildSubIdRegistration(params, identityScript, reservationScript, identityAddress, parentIAddress, systemId, network) {
742
682
  const registrationFeeAmount = params.registrationFeeAmount;
743
683
  if (!registrationFeeAmount || registrationFeeAmount <= 0n) {
744
684
  throw new errors_js_1.TransactionBuildError('registrationFeeAmount is required for sub-ID registration. ' +
@@ -764,67 +704,48 @@ function _buildSubIdRegistration(params, identity, identityScript, reservationSc
764
704
  '(from `getcurrency <parent>`), or 0n if it charges none.');
765
705
  }
766
706
  const nativeImportFee = params.nativeImportFee;
767
- const nativeTarget = feeOutput.nativeValue + nativeImportFee;
768
- const numOutputs = 4;
769
- const selection = (0, index_js_4.selectUtxos)(params.utxos, nativeTarget, requiredCurrencies, numOutputs, systemId, undefined, true,
770
- // The identity and reservation outputs embed the full serialized identity /
771
- // advanced name reservation (a large contentMultimap can make them
772
- // multi-KB); size the fee from their real bytes, matching the VRSC
773
- // registration / update / define paths, so a big sub-ID isn't fee-estimated
774
- // below the relay minimum and rejected.
775
- identityScript.length + reservationScript.length + feeOutput.script.length);
776
- // The parent-currency fee (requiredCurrencies) is paid to the fee output and
777
- // any excess returns as token change; guard that no token value is dropped.
778
- (0, index_js_4.assertTokenConservation)(selection.selected, requiredCurrencies, selection.currencyChanges, systemId, 'sub-ID registration');
779
- const txb = new utxo_lib_1.TransactionBuilder(network);
780
- txb.setVersion(4);
781
- txb.setExpiryHeight((0, index_js_3.resolveExpiryHeight)(params.expiryHeight));
782
- txb.setVersionGroupId(index_js_1.VERSION_GROUP_ID);
783
- const commitUtxo = params.commitmentUtxo;
784
- txb.addInput(Buffer.from(commitUtxo.txid, 'hex').reverse(), commitUtxo.outputIndex, 0xffffffff, Buffer.from(commitUtxo.script, 'hex'));
785
- for (const utxo of selection.selected) {
786
- txb.addInput(Buffer.from(utxo.txid, 'hex').reverse(), utxo.outputIndex, 0xffffffff, Buffer.from(utxo.script, 'hex'));
787
- }
788
- txb.addOutput(identityScript, 0);
789
- txb.addOutput(feeOutput.script, (0, index_js_2.toSafeNumber)(feeOutput.nativeValue));
790
- txb.addOutput(reservationScript, 0);
791
- const hasTokenChange = selection.currencyChanges.size > 0;
792
- if (hasTokenChange || selection.nativeChange > 0n) {
793
- if (hasTokenChange) {
794
- const tokenChangeScript = buildTokenChangeOutput((0, brands_js_1.parseAddress)(params.changeAddress, 'changeAddress'), selection.currencyChanges);
795
- txb.addOutput(tokenChangeScript.script, (0, index_js_2.toSafeNumber)(selection.nativeChange));
796
- }
797
- else {
798
- // utxo-lib's addOutput only resolves base58 R-addresses; an i-address
799
- // changeAddress needs the explicit P2ID script (matching sendCurrency), or
800
- // it throws an untyped "no matching Script".
801
- if (params.changeAddress.startsWith('i')) {
802
- txb.addOutput(identityPaymentScript((0, brands_js_1.parseIAddress)(params.changeAddress, 'changeAddress')), (0, index_js_2.toSafeNumber)(selection.nativeChange));
803
- }
804
- else {
805
- txb.addOutput(params.changeAddress, (0, index_js_2.toSafeNumber)(selection.nativeChange));
806
- }
807
- }
808
- }
809
- const unsignedTx = txb.buildIncomplete();
810
- const allUtxos = [commitUtxo, ...selection.selected];
811
- // Native value conservation. The parent-currency registration fee is a token
812
- // reserve-transfer (selection returns any excess as token change), so the
813
- // NATIVE fee this path pays is the commitment input's value (folded to fee,
814
- // like VRSC registration) + the native import fee + the miner fee. Verified
815
- // live on VRSCTEST: a sub-ID under `ownora` (1.0 token fee) paid 0.02 native.
816
- (0, index_js_3.assertNativeConservation)(allUtxos, unsignedTx.outs, commitUtxo.satoshis + nativeImportFee + selection.fee, 'sub-ID registration');
817
- const { signedTx, txid } = (0, index_js_3.signTransactionSmart)(unsignedTx.toHex(), params.wif, allUtxos, network);
707
+ // The identity + reservation outputs carry 0 native but embed the full
708
+ // serialized identity / advanced name reservation (a large contentMultimap
709
+ // makes them multi-KB), so the fee is sized from their real bytes — matching
710
+ // the VRSC/update/define paths instead of the fixed smart-output estimate.
711
+ // The fee output carries the parent-currency registration fee (a reserve output
712
+ // for pp2, a reserve transfer for pp1); the parent's idimportfees leaves as a
713
+ // DECLARED native burn. Verified live on VRSCTEST: a sub-ID under `ownora`
714
+ // (1.0 token fee) paid 0.02 native.
715
+ const assembled = (0, assembler_js_1.assembleAndSign)({
716
+ network,
717
+ wif: params.wif,
718
+ expiryHeight: params.expiryHeight,
719
+ funding: params.utxos,
720
+ // The name-commitment output is spent as input 0 (it carries no currency).
721
+ leadingInputs: [params.commitmentUtxo],
722
+ outputs: [
723
+ { script: identityScript, nativeSat: 0n },
724
+ { script: feeOutput.script, nativeSat: feeOutput.nativeValue, carries: requiredCurrencies },
725
+ { script: reservationScript, nativeSat: 0n },
726
+ ],
727
+ changeAddress: params.changeAddress,
728
+ // Legacy fee estimate: identity + fee + reservation, plus the one extra change
729
+ // slot the original path counted on top of selectUtxos' own reserve.
730
+ feeOutputCount: 4,
731
+ extraOutputBytes: identityScript.length + reservationScript.length + feeOutput.script.length,
732
+ fee: {
733
+ policy: 'declared',
734
+ burnSat: nativeImportFee,
735
+ reason: "parent currency's idimportfees (leaves as native import fee)",
736
+ },
737
+ label: 'sub-ID registration',
738
+ });
818
739
  return {
819
- signedTx,
820
- txid,
821
- fee: selection.fee,
740
+ signedTx: assembled.signedTx,
741
+ txid: assembled.txid,
742
+ fee: assembled.fee,
822
743
  identityAddress,
823
744
  registrationFee: registrationFeeAmount,
824
745
  referralPayments: 0,
825
746
  referralAmountEach: 0n,
826
- inputsUsed: allUtxos.length,
827
- nativeChange: selection.nativeChange,
747
+ inputsUsed: assembled.inputsUsed,
748
+ nativeChange: assembled.nativeChange,
828
749
  };
829
750
  }
830
751
  /**
@@ -839,9 +760,7 @@ function buildAndSignIdentityUpdate(params, network, operation = 'update', lockU
839
760
  throw new errors_js_1.TransactionBuildError('At least one funding UTXO is required');
840
761
  }
841
762
  const verusNetwork = (0, index_js_3.getNetwork)(network === 'testnet');
842
- const networkConfig = index_js_1.NETWORK_CONFIG[network];
843
- const systemId = networkConfig.chainId;
844
- const identity = new verus_typescript_primitives_1.Identity();
763
+ const identity = new boundary_js_1.Identity();
845
764
  identity.fromBuffer(Buffer.from(params.identityHex, 'hex'));
846
765
  // update/lock/unlock are authorized by the identity's primary key(s). The fork
847
766
  // signs CC inputs with whatever key it is given, so a WIF that does not control
@@ -863,7 +782,7 @@ function buildAndSignIdentityUpdate(params, network, operation = 'update', lockU
863
782
  requiresPrimary = authority === self;
864
783
  }
865
784
  if (requiresPrimary) {
866
- const signerAddress = utxo_lib_1.ECPair.fromWIF(params.wif, verusNetwork).getAddress();
785
+ const signerAddress = boundary_js_4.ECPair.fromWIF(params.wif, verusNetwork).getAddress();
867
786
  const currentPrimaries = (identity.primary_addresses ?? []).map((k) => k.toAddress());
868
787
  if (!currentPrimaries.includes(signerAddress)) {
869
788
  throw new errors_js_1.TransactionBuildError(`the provided WIF (${signerAddress}) is not among the identity's primary addresses ` +
@@ -934,7 +853,7 @@ function buildAndSignIdentityUpdate(params, network, operation = 'update', lockU
934
853
  }
935
854
  jsonObj[key] = items;
936
855
  }
937
- identity.content_multimap = verus_typescript_primitives_1.ContentMultiMap.fromJson(jsonObj);
856
+ identity.content_multimap = boundary_js_1.ContentMultiMap.fromJson(jsonObj);
938
857
  }
939
858
  break;
940
859
  }
@@ -1007,67 +926,32 @@ function buildAndSignIdentityUpdate(params, network, operation = 'update', lockU
1007
926
  }
1008
927
  const identityBuf = identity.toBuffer();
1009
928
  const unfundedHex = createUnfundedIdentityUpdate(identityBuf.toString('hex'), verusNetwork, (0, index_js_3.resolveExpiryHeight)(params.expiryHeight));
1010
- const selection = (0, index_js_4.selectUtxos)(params.utxos, 0n, new Map(), 1, systemId, undefined, true,
1011
- // The identity output embeds the full serialized identity (a large
1012
- // contentMultimap can make it multi-KB); size the fee from its real bytes
1013
- // so a big update isn't fee-estimated below the relay minimum.
1014
- unfundedHex.length / 2);
1015
- // Update spends only native fees and emits no token-change output, so a
1016
- // token-bearing funding UTXO would be silently dropped. Fail closed if one
1017
- // was selected (both maps empty ⇒ assert no token enters).
1018
- (0, index_js_4.assertTokenConservation)(selection.selected, new Map(), new Map(), systemId, 'identity update');
1019
- const txb = new utxo_lib_1.TransactionBuilder(verusNetwork);
1020
- txb.setVersion(4);
1021
- txb.setExpiryHeight((0, index_js_3.resolveExpiryHeight)(params.expiryHeight));
1022
- txb.setVersionGroupId(index_js_1.VERSION_GROUP_ID);
1023
- for (const utxo of selection.selected) {
1024
- txb.addInput(Buffer.from(utxo.txid, 'hex').reverse(), utxo.outputIndex, 0xffffffff, Buffer.from(utxo.script, 'hex'));
1025
- }
1026
- const unfundedTx = utxo_lib_1.Transaction.fromHex(unfundedHex, verusNetwork);
1027
- for (const out of unfundedTx.outs) {
1028
- txb.addOutput(out.script, out.value);
1029
- }
1030
- if (selection.nativeChange > 0n) {
1031
- // utxo-lib's addOutput only resolves base58 R-addresses; an i-address
1032
- // changeAddress needs the explicit P2ID script (matching sendCurrency), or
1033
- // it throws an untyped "no matching Script".
1034
- if (params.changeAddress.startsWith('i')) {
1035
- txb.addOutput(identityPaymentScript((0, brands_js_1.parseIAddress)(params.changeAddress, 'changeAddress')), (0, index_js_2.toSafeNumber)(selection.nativeChange));
1036
- }
1037
- else {
1038
- txb.addOutput(params.changeAddress, (0, index_js_2.toSafeNumber)(selection.nativeChange));
1039
- }
1040
- }
1041
- const fundedTx = txb.buildIncomplete();
1042
- const fundedHex = fundedTx.toHex();
1043
- const prevOutScripts = selection.selected.map(u => Buffer.from(u.script, 'hex'));
1044
- const idUtxo = params.identityUtxo;
1045
- // The identity input is spent and its definition output is recreated with
1046
- // value 0, so any native value riding on identityUtxo would be silently
1047
- // burned to miner fee. Identity outputs normally carry 0; fail closed if not.
1048
- if (idUtxo.satoshis !== 0n) {
1049
- throw new errors_js_1.TransactionBuildError(`identityUtxo carries ${idUtxo.satoshis} native satoshis, which would be burned to miner fee ` +
1050
- `(the recreated identity output is value 0). Spend that value separately before updating.`);
1051
- }
1052
- const completedHex = completeFundedIdentityUpdate(fundedHex, verusNetwork, prevOutScripts, {
1053
- hash: Buffer.from(idUtxo.txid, 'hex').reverse(),
1054
- index: idUtxo.outputIndex,
1055
- sequence: 0xffffffff,
1056
- script: Buffer.from(idUtxo.script, 'hex'),
929
+ const unfundedTx = boundary_js_4.Transaction.fromHex(unfundedHex, verusNetwork);
930
+ // Respend the identity UTXO and recreate its (value-0) definition output; the
931
+ // shared assembler funds it, emits native change, grafts on the identity input
932
+ // (re-signed last by the fork), and enforces native + token conservation.
933
+ const assembled = (0, fundedIdentityUpdate_js_1.assembleFundedIdentityUpdate)({
934
+ network,
935
+ wif: params.wif,
936
+ expiryHeight: params.expiryHeight,
937
+ funding: params.utxos,
938
+ identityUtxo: params.identityUtxo,
939
+ outputs: unfundedTx.outs.map((o) => ({ script: o.script, nativeSat: BigInt(o.value) })),
940
+ changeAddress: params.changeAddress,
941
+ // The identity output embeds the full serialized identity (a large
942
+ // contentMultimap can make it multi-KB); size the fee from the unfunded tx's
943
+ // real bytes so a big update isn't fee-estimated below the relay minimum.
944
+ extraOutputBytes: unfundedHex.length / 2,
945
+ label: `identity ${operation}`,
1057
946
  });
1058
- const allUtxos = [...selection.selected, idUtxo];
1059
- // The identity input and its recreated output are both value 0, so the
1060
- // assembled native fee must equal selection.fee. Fail loudly on any slip.
1061
- (0, index_js_3.assertNativeConservation)(allUtxos, utxo_lib_1.Transaction.fromHex(completedHex, verusNetwork).outs, selection.fee, `identity ${operation}`);
1062
- const { signedTx, txid } = (0, index_js_3.signTransactionSmart)(completedHex, params.wif, allUtxos, verusNetwork);
1063
947
  return {
1064
- signedTx,
1065
- txid,
1066
- fee: selection.fee,
948
+ signedTx: assembled.signedTx,
949
+ txid: assembled.txid,
950
+ fee: assembled.fee,
1067
951
  identityAddress: identity.getIdentityAddress(),
1068
952
  operation,
1069
- inputsUsed: allUtxos.length,
1070
- nativeChange: selection.nativeChange,
953
+ inputsUsed: assembled.inputsUsed,
954
+ nativeChange: assembled.nativeChange,
1071
955
  };
1072
956
  }
1073
957
  //# sourceMappingURL=index.js.map