@kaspacom/kcc20-tx-builder 0.1.0 → 0.2.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 (43) hide show
  1. package/dist/artifacts.d.ts +2 -0
  2. package/dist/artifacts.d.ts.map +1 -1
  3. package/dist/artifacts.js +3 -1
  4. package/dist/artifacts.js.map +1 -1
  5. package/dist/builder.d.ts +0 -2
  6. package/dist/builder.d.ts.map +1 -1
  7. package/dist/cjs/artifacts.d.ts +2 -0
  8. package/dist/cjs/artifacts.js +4 -2
  9. package/dist/cjs/artifacts.js.map +1 -1
  10. package/dist/cjs/builder.d.ts +0 -2
  11. package/dist/cjs/deploy-receipt.d.ts +45 -0
  12. package/dist/cjs/deploy-receipt.js +122 -0
  13. package/dist/cjs/deploy-receipt.js.map +1 -0
  14. package/dist/cjs/engine.js +336 -226
  15. package/dist/cjs/engine.js.map +1 -1
  16. package/dist/cjs/index.d.ts +1 -0
  17. package/dist/cjs/index.js +1 -0
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/protocol.d.ts +1 -0
  20. package/dist/cjs/protocol.js +15 -0
  21. package/dist/cjs/protocol.js.map +1 -1
  22. package/dist/deploy-receipt.d.ts +46 -0
  23. package/dist/deploy-receipt.d.ts.map +1 -0
  24. package/dist/deploy-receipt.js +119 -0
  25. package/dist/deploy-receipt.js.map +1 -0
  26. package/dist/engine.d.ts.map +1 -1
  27. package/dist/engine.js +337 -227
  28. package/dist/engine.js.map +1 -1
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/protocol.d.ts +1 -0
  34. package/dist/protocol.d.ts.map +1 -1
  35. package/dist/protocol.js +14 -0
  36. package/dist/protocol.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/artifacts.ts +5 -1
  39. package/src/builder.ts +0 -3
  40. package/src/deploy-receipt.ts +200 -0
  41. package/src/engine.ts +429 -296
  42. package/src/index.ts +1 -0
  43. package/src/protocol.ts +21 -0
package/dist/engine.js CHANGED
@@ -3,10 +3,11 @@ import { sha256 } from "@noble/hashes/sha256";
3
3
  import { DEFAULT_COMPUTE_BUDGET, DEFAULT_KCC20_FEE_BPS, DEFAULT_KCC20_MIN_PROTOCOL_FEE_SOMPI, DEFAULT_KCC20_PRICE_SCALE, DEFAULT_TOKEN_OUTPUT_SOMPI, KCC20_ORDERBOOK_EXPANDED_SWEEP_OUTPUT_SOMPI, KCC20_ORDERBOOK_MAX_SWEEP_BID_LEGS, KCC20_ORDERBOOK_MAX_EXPANDED_SWEEP_BID_LEGS, KCC20_PLATFORM_PROTOCOL_FEE_RECIPIENT, KCC20_ORDERBOOK_PROTOCOL_FEE_RECIPIENT, SUBNETWORK_ID_NATIVE, SOMPI_PER_TKAS, asciiToBytes32, buildKcc20FeeTicketScriptForState, buildNativeKcc20ScriptForState, buildKcc20WrapperScriptForState, buildKcc20OrderbookScriptForState, buildKcc20V3CreateBidSigScript, buildKcc20V3SellIntoBidSigScript, buildKcc20OrderbookFillBidFromSellerSweepSigScript, buildKcc20OrderbookFillAskSigScript, buildKcc20OrderbookFillBidSigScript, buildKcc20OrderbookSellIntoBidsSigScript, buildKcc20OrderbookSellIntoBids10SigScript, buildKcc20OrderbookCrossAskSigScript, buildKcc20OrderbookCrossAskLegacySigScript, buildKcc20OrderbookCrossBidSigScript, buildKcc20OrderbookCrossBidLegacySigScript, bytesToHex, calculateFeeSplit, findOutputIndex, hexToBytes, kcc20PsktBuilderError, mintPolicyName, normalizeSignature, p2pkScriptPubKey, p2shScriptHashHex, parseMintPolicy, requireHex32, selectFundingEntry, setVersionOneInputMassFields, stateToReceiptFields, utxoAmountSompi, ZERO_HASH, } from "./sale-common.js";
4
4
  import { buildKcc20BurnSigScript, buildKcc20MintByOwnerSigScript, buildKcc20MintPublicSigScript, buildKcc20ScriptForState, buildKcc20SetPublicMintActiveSigScript, buildKcc20TransferSigScript, dispatchTagFor, encodeKcc20StateRecordArrays, holderExtensionCommitment, mintExtensionCommitment, normalizeSilverScriptArtifact, ownerAuthorizationWitness, } from "./abi.js";
5
5
  import { KCC20_BUILDER_KEYS } from "./operations.js";
6
- import { KCC20_ARTIFACT_SCRIPT_SHA256, assertKcc20ArtifactScriptHash, } from "./artifacts.js";
6
+ import { splitKcc20MintSupply } from "./protocol.js";
7
+ import { buildKcc20DeployIntentOutputs } from "./deploy-receipt.js";
8
+ import { KCC20_ARTIFACT_SCRIPT_SHA256, KCC20_CURRENT_NATIVE_ARTIFACT_KEY, assertKcc20ArtifactScriptHash, } from "./artifacts.js";
7
9
  export function createKcc20PsktBuilderEngine(options) {
8
- const config = options.config ?? {};
9
- const process = { env: config };
10
+ const env = options.config ?? {};
10
11
  class InjectedRpcClient {
11
12
  inner;
12
13
  constructor(rpcConfig) {
@@ -99,7 +100,7 @@ export function createKcc20PsktBuilderEngine(options) {
99
100
  KCC20_ORDERBOOK_SWEEP_ASK_COMPUTE_BUDGET_PROFILE.feeTicket,
100
101
  ],
101
102
  ]);
102
- const KCC20_ARTIFACT_PATH = "KCC20.placeholder.json";
103
+ const KCC20_ARTIFACT_PATH = KCC20_CURRENT_NATIVE_ARTIFACT_KEY;
103
104
  const WRAPPER_ARTIFACT_PATH = "KCC20Wrapper.placeholder.json";
104
105
  const WRAPPED_ARTIFACT_PATH = "KCC20Orderbook.placeholder.json";
105
106
  const FEE_TICKET_ARTIFACT_PATH = "KCC20FeeTicket.placeholder.json";
@@ -254,7 +255,7 @@ export function createKcc20PsktBuilderEngine(options) {
254
255
  denomination: parsePositiveU64(input.utilityTokenAmount, "FeeTicket utility token amount"),
255
256
  };
256
257
  try {
257
- const artifact = selectFeeTicketArtifactForState(await readFeeTicketArtifacts(), rootState, requireKaspaAddress(input.rootAddress), input.network || process.env.KASPA_NETWORK || "testnet-10", "active FeeTicket root UTXO address");
258
+ const artifact = selectFeeTicketArtifactForState(await readFeeTicketArtifacts(), rootState, requireKaspaAddress(input.rootAddress), input.network || env.KASPA_NETWORK || "testnet-10", "active FeeTicket root UTXO address");
258
259
  return {
259
260
  recognizedArtifact: true,
260
261
  batchCreateSupported: artifact.supportsBatchCreate,
@@ -346,13 +347,13 @@ export function createKcc20PsktBuilderEngine(options) {
346
347
  const rootOwner = requireHex32(params.rootOwner || request.owner?.kcc20Owner, "FeeTicket root owner");
347
348
  const utilityTokenId = requireHex32(params.utilityTokenId, "FeeTicket utility token id");
348
349
  const newDenomination = parsePositiveU64(params.utilityTokenAmount, "utilityTokenAmount");
349
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
350
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
350
351
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
351
352
  const rootAddress = requireKaspaAddress(rootUtxo.address);
352
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
353
- const priorityFee = parseU64(process.env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
353
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
354
+ const priorityFee = parseU64(env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
354
355
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
355
- const computeBudget = parsePositiveNumber(process.env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
356
+ const computeBudget = parsePositiveNumber(env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
356
357
  const currentState = kcc20FeeTicketStateFromUtxo(rootUtxo, request.owner);
357
358
  if (currentState.mode !== 1) {
358
359
  throw new Error("FeeTicket denomination update requires a root UTXO");
@@ -490,13 +491,13 @@ export function createKcc20PsktBuilderEngine(options) {
490
491
  if (totalDenomination > MAX_U64) {
491
492
  throw new Error("FeeTicket batch utility token amount must fit in an unsigned 64-bit integer");
492
493
  }
493
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
494
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
494
495
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
495
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
496
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
496
497
  const tokenOutputSompi = configuredFeeTicketOutputSompiForQuantity(quantity);
497
- const priorityFee = parseU64(process.env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
498
+ const priorityFee = parseU64(env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
498
499
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
499
- const computeBudget = parsePositiveNumber(process.env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
500
+ const computeBudget = parsePositiveNumber(env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
500
501
  const feeTicketArtifacts = await readFeeTicketArtifacts();
501
502
  const rootState = {
502
503
  ownerIdentifier: hexToBytes(rootOwner),
@@ -718,12 +719,12 @@ export function createKcc20PsktBuilderEngine(options) {
718
719
  if (new Set(sourceOutpoints).size !== sourceOutpoints.length) {
719
720
  throw new Error("FeeTicket burn source outpoints must be unique");
720
721
  }
721
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
722
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
722
723
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
723
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
724
- const priorityFee = parseU64(process.env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
724
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
725
+ const priorityFee = parseU64(env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
725
726
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
726
- const computeBudget = parsePositiveNumber(process.env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
727
+ const computeBudget = parsePositiveNumber(env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
727
728
  const artifacts = await readFeeTicketArtifacts();
728
729
  const states = ticketUtxos.map((utxo) => kcc20FeeTicketStateFromUtxo(utxo, request.owner));
729
730
  for (const state of states) {
@@ -861,12 +862,12 @@ export function createKcc20PsktBuilderEngine(options) {
861
862
  if (new Set(sourceOutpoints).size !== sourceOutpoints.length) {
862
863
  throw new Error("FeeTicket transfer source outpoints must be unique");
863
864
  }
864
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
865
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
865
866
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
866
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
867
- const priorityFee = parseU64(process.env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
867
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
868
+ const priorityFee = parseU64(env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
868
869
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
869
- const computeBudget = parsePositiveNumber(process.env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
870
+ const computeBudget = parsePositiveNumber(env.KCC20_FEE_TICKET_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
870
871
  const artifacts = await readFeeTicketArtifacts();
871
872
  const states = ticketUtxos.map((utxo) => kcc20FeeTicketStateFromUtxo(utxo, request.owner));
872
873
  for (const state of states) {
@@ -1002,7 +1003,7 @@ export function createKcc20PsktBuilderEngine(options) {
1002
1003
  const configured = BigInt(configuredOutputSompi);
1003
1004
  return configured > minimum ? configured : minimum;
1004
1005
  }
1005
- function configuredFeeTicketOutputSompiForQuantity(quantity, environment = process.env) {
1006
+ function configuredFeeTicketOutputSompiForQuantity(quantity, environment = env) {
1006
1007
  const configured = parseU64(Number(quantity) === 1
1007
1008
  ? environment.KCC20_FEE_TICKET_OUTPUT_SOMPI ||
1008
1009
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString()
@@ -1649,14 +1650,14 @@ export function createKcc20PsktBuilderEngine(options) {
1649
1650
  params.tokenDisplayScale ??
1650
1651
  DEFAULT_KCC20_PRICE_SCALE, "priceScale");
1651
1652
  assertWrapperArtifactPriceScale(priceScale);
1652
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
1653
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
1653
1654
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
1654
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
1655
- const amountTkas = parseAmountTkas(process.env.KCC20_WRAPPER_DEPLOY_OUTPUT_TKAS ||
1656
- process.env.KCC20_DEPLOY_OUTPUT_TKAS ||
1655
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
1656
+ const amountTkas = parseAmountTkas(env.KCC20_WRAPPER_DEPLOY_OUTPUT_TKAS ||
1657
+ env.KCC20_DEPLOY_OUTPUT_TKAS ||
1657
1658
  DEFAULT_DEPLOY_TKAS, "KCC20_WRAPPER_DEPLOY_OUTPUT_TKAS");
1658
- const priorityFee = wrapperDeployPriorityFee(process.env.KCC20_WRAPPER_DEPLOY_PRIORITY_FEE_SOMPI);
1659
- const computeBudget = parsePositiveNumber(process.env.KCC20_WRAPPER_DEPLOY_COMPUTE_BUDGET || 600, "computeBudget");
1659
+ const priorityFee = wrapperDeployPriorityFee(env.KCC20_WRAPPER_DEPLOY_PRIORITY_FEE_SOMPI);
1660
+ const computeBudget = parsePositiveNumber(env.KCC20_WRAPPER_DEPLOY_COMPUTE_BUDGET || 600, "computeBudget");
1660
1661
  const wrapperArtifact = await readStaticArtifact(WRAPPER_ARTIFACT_PATH);
1661
1662
  const wrappedArtifacts = await readWrappedArtifacts();
1662
1663
  const wrappedArtifact = wrappedArtifacts[0].artifact;
@@ -1842,14 +1843,14 @@ export function createKcc20PsktBuilderEngine(options) {
1842
1843
  const recipientOwner = requireHex32(params.recipientOwner || request.owner?.kcc20Owner, "wrapped recipient owner");
1843
1844
  const tokenAmount = parsePositiveU64(params.tokenAmount, "tokenAmount");
1844
1845
  const feeTicketId = requireHex32(params.feeTicketId || ZERO_HASH, "fee ticket id");
1845
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
1846
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
1846
1847
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
1847
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
1848
- const tokenOutputSompi = parseU64(process.env.KCC20_WRAP_TOKEN_OUTPUT_SOMPI ||
1848
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
1849
+ const tokenOutputSompi = parseU64(env.KCC20_WRAP_TOKEN_OUTPUT_SOMPI ||
1849
1850
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
1850
- const priorityFee = parseU64(process.env.KCC20_WRAP_PRIORITY_FEE_SOMPI ||
1851
+ const priorityFee = parseU64(env.KCC20_WRAP_PRIORITY_FEE_SOMPI ||
1851
1852
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
1852
- const computeBudget = parsePositiveNumber(process.env.KCC20_WRAP_COMPUTE_BUDGET || 700, "computeBudget");
1853
+ const computeBudget = parsePositiveNumber(env.KCC20_WRAP_COMPUTE_BUDGET || 700, "computeBudget");
1853
1854
  const [wrapperArtifacts, wrappedArtifacts] = await Promise.all([
1854
1855
  readWrapperArtifacts(),
1855
1856
  readWrappedArtifacts(),
@@ -2113,14 +2114,14 @@ export function createKcc20PsktBuilderEngine(options) {
2113
2114
  const wrapperId = requireHex32(params.wrappedMarketId || params.wrapperId, "wrapped market id");
2114
2115
  const recipientOwner = requireHex32(params.recipientOwner || request.owner?.kcc20Owner, "KCC20 recipient owner");
2115
2116
  const tokenAmount = parsePositiveU64(params.tokenAmount, "tokenAmount");
2116
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
2117
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
2117
2118
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
2118
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2119
- const tokenOutputSompi = parseU64(process.env.KCC20_UNWRAP_TOKEN_OUTPUT_SOMPI ||
2119
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2120
+ const tokenOutputSompi = parseU64(env.KCC20_UNWRAP_TOKEN_OUTPUT_SOMPI ||
2120
2121
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
2121
- const priorityFee = parseU64(process.env.KCC20_UNWRAP_PRIORITY_FEE_SOMPI ||
2122
+ const priorityFee = parseU64(env.KCC20_UNWRAP_PRIORITY_FEE_SOMPI ||
2122
2123
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
2123
- const computeBudget = parsePositiveNumber(process.env.KCC20_UNWRAP_COMPUTE_BUDGET || 700, "computeBudget");
2124
+ const computeBudget = parsePositiveNumber(env.KCC20_UNWRAP_COMPUTE_BUDGET || 700, "computeBudget");
2124
2125
  const [wrapperArtifacts, wrappedArtifacts] = await Promise.all([
2125
2126
  readWrapperArtifacts(),
2126
2127
  readWrappedArtifacts(),
@@ -2442,14 +2443,14 @@ export function createKcc20PsktBuilderEngine(options) {
2442
2443
  const expectedFeeTicketId = params.feeTicketId
2443
2444
  ? requireHex32(params.feeTicketId, "fee ticket id")
2444
2445
  : null;
2445
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
2446
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
2446
2447
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
2447
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2448
- const tokenOutputSompi = parseU64(process.env.KCC20_ORDER_TOKEN_OUTPUT_SOMPI ||
2448
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2449
+ const tokenOutputSompi = parseU64(env.KCC20_ORDER_TOKEN_OUTPUT_SOMPI ||
2449
2450
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
2450
- const priorityFee = parseU64(process.env.KCC20_ORDER_PRIORITY_FEE_SOMPI ||
2451
+ const priorityFee = parseU64(env.KCC20_ORDER_PRIORITY_FEE_SOMPI ||
2451
2452
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
2452
- const computeBudget = parsePositiveNumber(process.env.KCC20_ORDER_COMPUTE_BUDGET || 700, "computeBudget");
2453
+ const computeBudget = parsePositiveNumber(env.KCC20_ORDER_COMPUTE_BUDGET || 700, "computeBudget");
2453
2454
  const wrappedArtifacts = await readWrappedArtifacts();
2454
2455
  const activeUtxo = isBid ? rootUtxo : holderUtxo;
2455
2456
  const activeState = kcc20V3WrappedStateFromUtxo(activeUtxo, canonicalTokenId, request.owner);
@@ -2689,14 +2690,14 @@ export function createKcc20PsktBuilderEngine(options) {
2689
2690
  const buyerOwner = requireHex32(request.owner?.kcc20Owner, "buyer owner");
2690
2691
  const fillAmount = parsePositiveU64(params.tokenAmount, "tokenAmount");
2691
2692
  const unitPriceSompi = parsePositiveU64(params.unitPriceSompi, "unitPriceSompi");
2692
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
2693
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
2693
2694
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
2694
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2695
- const tokenOutputSompi = parseU64(process.env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
2695
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2696
+ const tokenOutputSompi = parseU64(env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
2696
2697
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
2697
- const priorityFee = parseU64(process.env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
2698
+ const priorityFee = parseU64(env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
2698
2699
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
2699
- const computeBudget = parsePositiveNumber(process.env.KCC20_FILL_COMPUTE_BUDGET || 800, "computeBudget");
2700
+ const computeBudget = parsePositiveNumber(env.KCC20_FILL_COMPUTE_BUDGET || 800, "computeBudget");
2700
2701
  const wrappedArtifacts = await readWrappedArtifacts();
2701
2702
  const ticketArtifacts = ticketUtxo ? await readFeeTicketArtifacts() : null;
2702
2703
  const askState = kcc20V3WrappedStateFromUtxo(askUtxo, canonicalTokenId, request.owner);
@@ -2974,14 +2975,14 @@ export function createKcc20PsktBuilderEngine(options) {
2974
2975
  const sellerOwner = requireHex32(request.owner?.kcc20Owner, "seller owner");
2975
2976
  const fillAmount = parsePositiveU64(params.tokenAmount, "tokenAmount");
2976
2977
  const unitPriceSompi = parsePositiveU64(params.unitPriceSompi, "unitPriceSompi");
2977
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
2978
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
2978
2979
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
2979
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2980
- const tokenOutputSompi = parseU64(process.env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
2980
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
2981
+ const tokenOutputSompi = parseU64(env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
2981
2982
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
2982
- const priorityFee = parseU64(process.env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
2983
+ const priorityFee = parseU64(env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
2983
2984
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
2984
- const computeBudget = parsePositiveNumber(process.env.KCC20_FILL_COMPUTE_BUDGET || 800, "computeBudget");
2985
+ const computeBudget = parsePositiveNumber(env.KCC20_FILL_COMPUTE_BUDGET || 800, "computeBudget");
2985
2986
  const wrappedArtifacts = await readWrappedArtifacts();
2986
2987
  const ticketArtifacts = ticketUtxo ? await readFeeTicketArtifacts() : null;
2987
2988
  const bidState = kcc20V3WrappedStateFromUtxo(bidUtxo, canonicalTokenId, request.owner);
@@ -3380,12 +3381,12 @@ export function createKcc20PsktBuilderEngine(options) {
3380
3381
  const canonicalTokenId = requireHex32(params.canonicalCovenantId || params.covenantId, "canonical token id");
3381
3382
  const wrapperId = requireHex32(params.wrappedMarketId || params.wrapperId, "wrapped market id");
3382
3383
  const buyerOwner = requireHex32(request.owner?.kcc20Owner, "buyer owner");
3383
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
3384
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
3384
3385
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
3385
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
3386
- const tokenOutputSompi = parseU64(process.env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
3386
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
3387
+ const tokenOutputSompi = parseU64(env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
3387
3388
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
3388
- const priorityFee = parseU64(process.env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
3389
+ const priorityFee = parseU64(env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
3389
3390
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
3390
3391
  const wrappedArtifacts = await readWrappedArtifacts();
3391
3392
  const ticketArtifacts = params.feeTicketId
@@ -3743,12 +3744,12 @@ export function createKcc20PsktBuilderEngine(options) {
3743
3744
  const canonicalTokenId = requireHex32(params.canonicalCovenantId || params.covenantId, "canonical token id");
3744
3745
  const wrapperId = requireHex32(params.wrappedMarketId || params.wrapperId, "wrapped market id");
3745
3746
  const sellerOwner = requireHex32(request.owner?.kcc20Owner, "seller owner");
3746
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
3747
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
3747
3748
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
3748
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
3749
- const tokenOutputSompi = parseU64(process.env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
3749
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
3750
+ const tokenOutputSompi = parseU64(env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
3750
3751
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
3751
- const priorityFee = parseU64(process.env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
3752
+ const priorityFee = parseU64(env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
3752
3753
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
3753
3754
  const wrappedArtifacts = await readWrappedArtifacts();
3754
3755
  const wrappedArtifact = wrappedArtifacts[0].artifact;
@@ -4240,12 +4241,12 @@ export function createKcc20PsktBuilderEngine(options) {
4240
4241
  const canonicalTokenId = requireHex32(params.canonicalCovenantId || params.covenantId, "canonical token id");
4241
4242
  const wrapperId = requireHex32(params.wrappedMarketId || params.wrapperId, "wrapped market id");
4242
4243
  const sellerOwner = requireHex32(request.owner?.kcc20Owner, "seller owner");
4243
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
4244
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
4244
4245
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
4245
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
4246
- const configuredTokenOutputSompi = parseU64(process.env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
4246
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
4247
+ const configuredTokenOutputSompi = parseU64(env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
4247
4248
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
4248
- const priorityFee = parseU64(process.env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
4249
+ const priorityFee = parseU64(env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
4249
4250
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
4250
4251
  const wrappedArtifacts = await readWrappedArtifacts();
4251
4252
  const ticketArtifacts = params.feeTicketId
@@ -4755,16 +4756,16 @@ export function createKcc20PsktBuilderEngine(options) {
4755
4756
  params.wrapperId, "wrapped market id");
4756
4757
  const requestedWrapperId = requireHex32(params.wrappedMarketId || params.wrapperId || wrapperId, "requested wrapped market id");
4757
4758
  const owner = requireHex32(request.owner?.kcc20Owner, "token owner");
4758
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
4759
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
4759
4760
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
4760
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
4761
- const priorityFee = parseU64(process.env.KCC20_CONSOLIDATE_PRIORITY_FEE_SOMPI ||
4762
- process.env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
4761
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
4762
+ const priorityFee = parseU64(env.KCC20_CONSOLIDATE_PRIORITY_FEE_SOMPI ||
4763
+ env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
4763
4764
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
4764
- const configuredPrimaryComputeBudget = parsePositiveNumber(process.env.KCC20_CONSOLIDATE_COMPUTE_BUDGET ||
4765
- process.env.KCC20_FILL_COMPUTE_BUDGET ||
4765
+ const configuredPrimaryComputeBudget = parsePositiveNumber(env.KCC20_CONSOLIDATE_COMPUTE_BUDGET ||
4766
+ env.KCC20_FILL_COMPUTE_BUDGET ||
4766
4767
  800, "configuredPrimaryComputeBudget");
4767
- const peerComputeBudget = parsePositiveNumber(process.env.KCC20_CONSOLIDATE_PEER_COMPUTE_BUDGET || 200, "peerComputeBudget");
4768
+ const peerComputeBudget = parsePositiveNumber(env.KCC20_CONSOLIDATE_PEER_COMPUTE_BUDGET || 200, "peerComputeBudget");
4768
4769
  const computeBudget = Math.max(configuredPrimaryComputeBudget, 500 + holderUtxos.length * 100);
4769
4770
  const wrappedArtifacts = await readWrappedArtifacts();
4770
4771
  const states = holderUtxos.map((utxo) => kcc20V3WrappedStateFromUtxo(utxo, canonicalTokenId, request.owner));
@@ -4966,24 +4967,24 @@ export function createKcc20PsktBuilderEngine(options) {
4966
4967
  ? requireHex32(params.feeTicketId, "fee ticket id")
4967
4968
  : null;
4968
4969
  const maxFeeSompi = parseU64(params.maxFeeSompi || "0", "maxFeeSompi");
4969
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
4970
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
4970
4971
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
4971
4972
  const expectedOwner = request.owner?.kcc20Owner
4972
4973
  ? requireHex32(request.owner.kcc20Owner, "matcher owner")
4973
4974
  : null;
4974
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
4975
- const tokenOutputSompi = parseU64(process.env.KCC20_MATCHER_TOKEN_OUTPUT_SOMPI ||
4976
- process.env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
4975
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
4976
+ const tokenOutputSompi = parseU64(env.KCC20_MATCHER_TOKEN_OUTPUT_SOMPI ||
4977
+ env.KCC20_FILL_TOKEN_OUTPUT_SOMPI ||
4977
4978
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
4978
- const priorityFee = parseU64(process.env.KCC20_MATCHER_PRIORITY_FEE_SOMPI ||
4979
- process.env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
4979
+ const priorityFee = parseU64(env.KCC20_MATCHER_PRIORITY_FEE_SOMPI ||
4980
+ env.KCC20_FILL_PRIORITY_FEE_SOMPI ||
4980
4981
  DEFAULT_MATCHER_PRIORITY_FEE.toString(), "priorityFee");
4981
- const networkFeeReserve = parseU64(process.env.KCC20_MATCHER_NETWORK_FEE_RESERVE_SOMPI || "5000000", "networkFeeReserve");
4982
+ const networkFeeReserve = parseU64(env.KCC20_MATCHER_NETWORK_FEE_RESERVE_SOMPI || "5000000", "networkFeeReserve");
4982
4983
  const transactionFeeReserve = priorityFee + networkFeeReserve;
4983
- const computeBudget = parsePositiveNumber(process.env.KCC20_MATCHER_COMPUTE_BUDGET ||
4984
- process.env.KCC20_FILL_COMPUTE_BUDGET ||
4984
+ const computeBudget = parsePositiveNumber(env.KCC20_MATCHER_COMPUTE_BUDGET ||
4985
+ env.KCC20_FILL_COMPUTE_BUDGET ||
4985
4986
  800, "computeBudget");
4986
- const privateKeyHex = String(process.env.KCC20_WRAPPER_OPERATOR_PRIVATE_KEY || "")
4987
+ const privateKeyHex = String(env.KCC20_WRAPPER_OPERATOR_PRIVATE_KEY || "")
4987
4988
  .trim()
4988
4989
  .replace(/^0x/i, "");
4989
4990
  if (!privateKeyHex) {
@@ -5429,12 +5430,12 @@ export function createKcc20PsktBuilderEngine(options) {
5429
5430
  const wrapperId = requireHex32(params.wrappedMarketId || params.wrapperId, "wrapped market id");
5430
5431
  const owner = requireHex32(request.owner?.kcc20Owner, "order owner");
5431
5432
  const targetOrderId = requireOrderId(params.targetOrderId, "target order id");
5432
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
5433
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
5433
5434
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
5434
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
5435
- const priorityFee = parseU64(process.env.KCC20_CANCEL_PRIORITY_FEE_SOMPI ||
5435
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
5436
+ const priorityFee = parseU64(env.KCC20_CANCEL_PRIORITY_FEE_SOMPI ||
5436
5437
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
5437
- const computeBudget = parsePositiveNumber(process.env.KCC20_CANCEL_COMPUTE_BUDGET || 800, "computeBudget");
5438
+ const computeBudget = parsePositiveNumber(env.KCC20_CANCEL_COMPUTE_BUDGET || 800, "computeBudget");
5438
5439
  const wrappedArtifacts = await readWrappedArtifacts();
5439
5440
  const orderState = kcc20V3WrappedStateFromUtxo(orderUtxo, canonicalTokenId, request.owner);
5440
5441
  if (orderState.mode !== expectedMode) {
@@ -5646,14 +5647,14 @@ export function createKcc20PsktBuilderEngine(options) {
5646
5647
  const minterTxid = requireHex32(activeMinterUtxo.txidHex, "minter txid");
5647
5648
  const minterVout = parseVout(activeMinterUtxo.vout, "minter vout");
5648
5649
  const minterAddress = requireKaspaAddress(activeMinterUtxo.address);
5649
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
5650
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
5650
5651
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
5651
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
5652
- const tokenOutputSompi = assertKcc20TokenOutputSompi(parseU64(process.env.KCC20_MINT_TOKEN_OUTPUT_SOMPI ||
5652
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
5653
+ const tokenOutputSompi = assertKcc20TokenOutputSompi(parseU64(env.KCC20_MINT_TOKEN_OUTPUT_SOMPI ||
5653
5654
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi"), "mint");
5654
- const priorityFee = parseU64(process.env.KCC20_MINT_PRIORITY_FEE_SOMPI ||
5655
+ const priorityFee = parseU64(env.KCC20_MINT_PRIORITY_FEE_SOMPI ||
5655
5656
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
5656
- const computeBudget = parsePositiveNumber(process.env.KCC20_MINT_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
5657
+ const computeBudget = parsePositiveNumber(env.KCC20_MINT_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
5657
5658
  const inputState = {
5658
5659
  amount: 0n,
5659
5660
  owner: hexToBytes(minterOwner),
@@ -5891,84 +5892,130 @@ export function createKcc20PsktBuilderEngine(options) {
5891
5892
  async function buildKcc20SetPublicMintActivePskt(input) {
5892
5893
  const request = input.request || {};
5893
5894
  const params = request.params || {};
5894
- const activeMinterUtxo = params.activeMinterUtxo;
5895
- if (!activeMinterUtxo) {
5895
+ const requestedMinterUtxos = Array.isArray(params.activeMinterUtxos) &&
5896
+ params.activeMinterUtxos.length > 0
5897
+ ? params.activeMinterUtxos
5898
+ : params.activeMinterUtxo
5899
+ ? [params.activeMinterUtxo]
5900
+ : [];
5901
+ if (requestedMinterUtxos.length === 0) {
5896
5902
  throw new Error("active KCC20 mint-authority UTXO is required");
5897
5903
  }
5898
5904
  if (typeof params.active !== "boolean") {
5899
5905
  throw new Error("active must be a boolean");
5900
5906
  }
5901
5907
  const covenantId = requireHex32(params.covenantId, "canonical covenant id");
5902
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
5908
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
5903
5909
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
5904
5910
  const walletOwner = requireHex32(request.owner?.kcc20Owner, "authenticated wallet owner");
5905
- const minterAddress = requireKaspaAddress(activeMinterUtxo.address);
5906
- const minterOwner = requireHex32(activeMinterUtxo.state?.owner ?? activeMinterUtxo.state?.ownerIdentifier, "active mint-authority owner");
5907
- const minterOwnerScheme = parseOwnerScheme(activeMinterUtxo.state?.ownerScheme ??
5908
- activeMinterUtxo.state?.identifierType ??
5909
- 0, "active mint-authority owner scheme");
5910
- if (minterOwnerScheme !== 0) {
5911
- throw new Error("public mint availability requires a pubkey-owned minter");
5912
- }
5913
- if (minterOwner !== walletOwner) {
5914
- throw new Error("public mint availability requires authenticated wallet to own the active minter UTXO");
5915
- }
5916
5911
  const mintPolicy = params.mintPolicy || {};
5917
- const remainingSupply = parsePositiveU64(activeMinterUtxo.state?.remainingSupply ?? mintPolicy.remainingSupply, "active mint-authority remaining supply");
5918
5912
  const displayScale = parsePositiveU64(params.priceScale ??
5919
5913
  params.tokenDisplayScale ??
5920
5914
  DEFAULT_KCC20_PRICE_SCALE, "displayScale");
5921
- const extension = kcc20MintExtensionFromSources(activeMinterUtxo, params, mintPolicy, 2, remainingSupply, displayScale);
5922
- if (extension.publicMintActive === params.active) {
5915
+ const seenOutpoints = new Set();
5916
+ const laneContexts = (await Promise.all(requestedMinterUtxos.map(async (activeMinterUtxo, laneIndex) => {
5917
+ if (activeMinterUtxo.state?.isMintAuthority !== true ||
5918
+ parseMintPolicy(activeMinterUtxo.state?.mintPolicy) !== 2) {
5919
+ throw new Error("public mint availability requires public mint-authority lanes");
5920
+ }
5921
+ const minterAddress = requireKaspaAddress(activeMinterUtxo.address);
5922
+ const minterOwner = requireHex32(activeMinterUtxo.state?.owner ??
5923
+ activeMinterUtxo.state?.ownerIdentifier, "active mint-authority owner");
5924
+ const minterOwnerScheme = parseOwnerScheme(activeMinterUtxo.state?.ownerScheme ??
5925
+ activeMinterUtxo.state?.identifierType ??
5926
+ 0, "active mint-authority owner scheme");
5927
+ if (minterOwnerScheme !== 0) {
5928
+ throw new Error("public mint availability requires a pubkey-owned minter");
5929
+ }
5930
+ if (minterOwner !== walletOwner) {
5931
+ throw new Error("public mint availability requires authenticated wallet to own every active minter UTXO");
5932
+ }
5933
+ const remainingSupply = parsePositiveU64(activeMinterUtxo.state?.remainingSupply ??
5934
+ mintPolicy.remainingSupply, "active mint-authority remaining supply");
5935
+ const extension = kcc20MintExtensionFromSources(activeMinterUtxo, params, mintPolicy, 2, remainingSupply, displayScale);
5936
+ if (extension.publicMintActive === params.active) {
5937
+ return null;
5938
+ }
5939
+ const inputState = {
5940
+ amount: 0n,
5941
+ owner: hexToBytes(minterOwner),
5942
+ ownerScheme: minterOwnerScheme,
5943
+ borrowScheme: 0,
5944
+ borrowGuard: hexToBytes(ZERO_HASH),
5945
+ extensionCommitment: mintExtensionCommitment(extension),
5946
+ };
5947
+ const nextExtension = {
5948
+ ...extension,
5949
+ publicMintActive: params.active,
5950
+ };
5951
+ const outputState = {
5952
+ ...inputState,
5953
+ extensionCommitment: mintExtensionCommitment(nextExtension),
5954
+ };
5955
+ const resolvedArtifact = await resolveKcc20ArtifactForState(inputState, minterAddress, network);
5956
+ dispatchTagFor(resolvedArtifact.artifact, "set_public_mint_active");
5957
+ const minterTxid = requireHex32(activeMinterUtxo.txidHex, "minter txid");
5958
+ const minterVout = parseVout(activeMinterUtxo.vout, "minter vout");
5959
+ const outpoint = `${minterTxid}:${minterVout}`;
5960
+ if (seenOutpoints.has(outpoint)) {
5961
+ throw new Error(`duplicate active minter outpoint ${outpoint}`);
5962
+ }
5963
+ seenOutpoints.add(outpoint);
5964
+ return {
5965
+ activeMinterUtxo,
5966
+ laneIndex,
5967
+ minterAddress,
5968
+ minterTxid,
5969
+ minterVout,
5970
+ outpoint,
5971
+ remainingSupply,
5972
+ extension,
5973
+ nextExtension,
5974
+ inputState,
5975
+ outputState,
5976
+ resolvedArtifact,
5977
+ };
5978
+ }))).filter(Boolean);
5979
+ if (laneContexts.length === 0) {
5923
5980
  throw new Error(params.active
5924
5981
  ? "public mint is not paused"
5925
5982
  : "public mint is not active");
5926
5983
  }
5927
- const inputState = {
5928
- amount: 0n,
5929
- owner: hexToBytes(minterOwner),
5930
- ownerScheme: minterOwnerScheme,
5931
- borrowScheme: 0,
5932
- borrowGuard: hexToBytes(ZERO_HASH),
5933
- extensionCommitment: mintExtensionCommitment(extension),
5934
- };
5935
- const nextExtension = { ...extension, publicMintActive: params.active };
5936
- const outputState = {
5937
- ...inputState,
5938
- extensionCommitment: mintExtensionCommitment(nextExtension),
5939
- };
5940
- const resolvedArtifact = await resolveKcc20ArtifactForState(inputState, minterAddress, network);
5941
- const artifact = resolvedArtifact.artifact;
5942
- dispatchTagFor(artifact, "set_public_mint_active");
5943
- const minterTxid = requireHex32(activeMinterUtxo.txidHex, "minter txid");
5944
- const minterVout = parseVout(activeMinterUtxo.vout, "minter vout");
5945
- const priorityFee = parseU64(process.env.KCC20_MINT_AVAILABILITY_PRIORITY_FEE_SOMPI ||
5984
+ const priorityFee = parseU64(env.KCC20_MINT_AVAILABILITY_PRIORITY_FEE_SOMPI ||
5946
5985
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
5947
- const computeBudget = parsePositiveNumber(process.env.KCC20_MINT_AVAILABILITY_COMPUTE_BUDGET ||
5986
+ const computeBudget = parsePositiveNumber(env.KCC20_MINT_AVAILABILITY_COMPUTE_BUDGET ||
5948
5987
  DEFAULT_COMPUTE_BUDGET, "computeBudget");
5949
5988
  const rpc = new kaspaWasm.RpcClient({
5950
- url: process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL,
5989
+ url: env.KASPA_WRPC_URL || DEFAULT_WRPC_URL,
5951
5990
  encoding: kaspaWasm.Encoding.Borsh,
5952
5991
  networkId: network,
5953
5992
  });
5954
5993
  await rpc.connect();
5955
5994
  try {
5956
5995
  const [minterUtxos, walletUtxos] = await Promise.all([
5957
- getUtxosByAddresses(rpc, [minterAddress]),
5996
+ getUtxosByAddresses(rpc, [
5997
+ ...new Set(laneContexts.map((lane) => lane.minterAddress)),
5998
+ ]),
5958
5999
  getUtxosByAddresses(rpc, [walletAddress]),
5959
6000
  ]);
5960
- const minterEntry = findUtxoEntry(minterUtxos.entries, minterTxid, minterVout);
5961
- if (!minterEntry) {
5962
- throw new Error(`active minter UTXO ${minterTxid}:${minterVout} not found`);
5963
- }
5964
- const spendCovenantId = covenantIdFromUtxoEntry(minterEntry) ?? covenantId;
5965
- const minterInputSompi = BigInt(minterEntry.amount);
6001
+ const resolvedLanes = laneContexts.map((lane, laneIndex) => {
6002
+ const minterEntry = findUtxoEntry(minterUtxos.entries, lane.minterTxid, lane.minterVout);
6003
+ if (!minterEntry) {
6004
+ throw new Error(`active minter UTXO ${lane.outpoint} not found`);
6005
+ }
6006
+ const spendCovenantId = requireMatchingCovenantId(minterEntry, covenantId, `active minter lane ${laneIndex}`);
6007
+ return {
6008
+ ...lane,
6009
+ laneIndex,
6010
+ minterEntry,
6011
+ spendCovenantId,
6012
+ minterInputSompi: BigInt(minterEntry.amount),
6013
+ };
6014
+ });
5966
6015
  const fundingEntry = selectFundingEntry(walletUtxos.entries, priorityFee + 10000n);
5967
- const fundingInputIndex = 1;
6016
+ const fundingInputIndex = resolvedLanes.length;
5968
6017
  const fundingChange = BigInt(fundingEntry.amount) - priorityFee;
5969
- const outputs = [
5970
- tokenOutput(kaspaWasm, artifact, outputState, minterInputSompi, spendCovenantId, 0),
5971
- ];
6018
+ const outputs = resolvedLanes.map((lane, laneIndex) => tokenOutput(kaspaWasm, lane.resolvedArtifact.artifact, lane.outputState, lane.minterInputSompi, lane.spendCovenantId, laneIndex));
5972
6019
  let fundingChangeOutputIndex = -1;
5973
6020
  if (fundingChange > 10000n) {
5974
6021
  fundingChangeOutputIndex = outputs.length;
@@ -5978,13 +6025,13 @@ export function createKcc20PsktBuilderEngine(options) {
5978
6025
  version: 1,
5979
6026
  lockTime: 0n,
5980
6027
  inputs: [
5981
- {
5982
- previousOutpoint: minterEntry.outpoint,
5983
- utxo: minterEntry,
6028
+ ...resolvedLanes.map((lane) => ({
6029
+ previousOutpoint: lane.minterEntry.outpoint,
6030
+ utxo: lane.minterEntry,
5984
6031
  sequence: 0n,
5985
6032
  sigOpCount: 0,
5986
6033
  computeBudget,
5987
- },
6034
+ })),
5988
6035
  {
5989
6036
  previousOutpoint: fundingEntry.outpoint,
5990
6037
  utxo: fundingEntry,
@@ -5999,25 +6046,29 @@ export function createKcc20PsktBuilderEngine(options) {
5999
6046
  payload: new Uint8Array(),
6000
6047
  });
6001
6048
  setVersionOneInputMassFields(unsignedTx, computeBudget);
6002
- const scriptDescriptor = {
6003
- inputIndex: 0,
6004
- scriptHex: bytesToHex(resolvedArtifact.script),
6049
+ unsignedTx.inputs[fundingInputIndex].computeBudget = 30;
6050
+ const scripts = resolvedLanes.map((lane, laneIndex) => ({
6051
+ inputIndex: laneIndex,
6052
+ scriptHex: bytesToHex(lane.resolvedArtifact.script),
6005
6053
  signType: 1,
6006
6054
  signatureScript: {
6007
6055
  mode: "ordered-args",
6008
- args: kcc20SetPublicMintActiveOrderedArgs(artifact, extension, params.active, 0),
6056
+ args: kcc20SetPublicMintActiveOrderedArgs(lane.resolvedArtifact.artifact, lane.extension, params.active, laneIndex),
6009
6057
  },
6010
- };
6058
+ }));
6011
6059
  const predictSignedTransaction = (transaction) => {
6012
6060
  const predicted = cloneTransactionForMassPreflight(kaspaWasm, transaction, "KCC20 public mint availability");
6013
6061
  const dummySignature = dummySignatureBytes();
6014
- const prefix = buildKcc20SetPublicMintActiveSigScript(kaspaWasm, artifact, {
6015
- extension,
6016
- authoritySignature: dummySignature,
6017
- active: params.active,
6018
- minterOutputIndex: 0,
6062
+ resolvedLanes.forEach((lane, laneIndex) => {
6063
+ const prefix = buildKcc20SetPublicMintActiveSigScript(kaspaWasm, lane.resolvedArtifact.artifact, {
6064
+ extension: lane.extension,
6065
+ authoritySignature: dummySignature,
6066
+ active: params.active,
6067
+ minterOutputIndex: laneIndex,
6068
+ });
6069
+ predicted.inputs[laneIndex].signatureScript =
6070
+ encodeCovenantP2shSignatureScript(prefix, lane.resolvedArtifact.script);
6019
6071
  });
6020
- predicted.inputs[0].signatureScript = encodeCovenantP2shSignatureScript(prefix, resolvedArtifact.script);
6021
6072
  predicted.inputs[fundingInputIndex].signatureScript =
6022
6073
  encodeP2pkSignatureScript(bytesToHex(dummySignature));
6023
6074
  return predicted;
@@ -6031,21 +6082,28 @@ export function createKcc20PsktBuilderEngine(options) {
6031
6082
  schema: OUTPUT_SCHEMA,
6032
6083
  psktTransactionJson,
6033
6084
  signInputs: [{ index: fundingInputIndex, sighashType: 1 }],
6034
- scripts: [scriptDescriptor],
6085
+ scripts,
6035
6086
  submitTransactionSupported: true,
6036
6087
  metadata: {
6037
6088
  builderKey: "kcc20.set-public-mint-active",
6038
6089
  contract: "KCC20",
6039
6090
  network,
6040
6091
  walletAddress,
6041
- covenantId: spendCovenantId,
6042
- minterOutpoint: `${minterTxid}:${minterVout}`,
6092
+ covenantId,
6093
+ minterOutpoint: resolvedLanes[0].outpoint,
6094
+ minterOutpoints: resolvedLanes.map((lane) => lane.outpoint),
6043
6095
  minterOutputIndex: 0,
6096
+ minterOutputIndexes: resolvedLanes.map((_, index) => index),
6097
+ mintLaneCount: Number(resolvedLanes[0].extension.mintLaneCount),
6098
+ updatedMintLaneCount: resolvedLanes.length,
6044
6099
  publicMintActive: params.active,
6045
6100
  mintPolicy: 2,
6046
- remainingSupply: remainingSupply.toString(),
6047
- extension: jsonKcc20MintExtension(nextExtension),
6048
- artifactVersion: resolvedArtifact.version,
6101
+ remainingSupply: resolvedLanes[0].remainingSupply.toString(),
6102
+ remainingSupplies: resolvedLanes.map((lane) => lane.remainingSupply.toString()),
6103
+ extension: jsonKcc20MintExtension(resolvedLanes[0].nextExtension),
6104
+ extensions: resolvedLanes.map((lane) => jsonKcc20MintExtension(lane.nextExtension)),
6105
+ artifactVersion: resolvedLanes[0].resolvedArtifact.version,
6106
+ artifactVersions: resolvedLanes.map((lane) => lane.resolvedArtifact.version),
6049
6107
  },
6050
6108
  };
6051
6109
  }
@@ -6102,16 +6160,16 @@ export function createKcc20PsktBuilderEngine(options) {
6102
6160
  const covenantId = requireHex32(params.activeHolderNativeCovenantId || params.covenantId, "canonical covenant id");
6103
6161
  const appCanonicalTokenId = requireHex32(params.appCanonicalCovenantId || params.covenantId || covenantId, "app canonical token id");
6104
6162
  const owner = requireHex32(request.owner?.kcc20Owner, "token owner");
6105
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
6163
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
6106
6164
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
6107
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6108
- const priorityFee = parseU64(process.env.KCC20_CONSOLIDATE_PRIORITY_FEE_SOMPI ||
6109
- process.env.KCC20_TRANSFER_PRIORITY_FEE_SOMPI ||
6165
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6166
+ const priorityFee = parseU64(env.KCC20_CONSOLIDATE_PRIORITY_FEE_SOMPI ||
6167
+ env.KCC20_TRANSFER_PRIORITY_FEE_SOMPI ||
6110
6168
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
6111
- const configuredPrimaryComputeBudget = parsePositiveNumber(process.env.KCC20_CONSOLIDATE_COMPUTE_BUDGET ||
6112
- process.env.KCC20_TRANSFER_COMPUTE_BUDGET ||
6169
+ const configuredPrimaryComputeBudget = parsePositiveNumber(env.KCC20_CONSOLIDATE_COMPUTE_BUDGET ||
6170
+ env.KCC20_TRANSFER_COMPUTE_BUDGET ||
6113
6171
  DEFAULT_COMPUTE_BUDGET, "configuredPrimaryComputeBudget");
6114
- const peerComputeBudget = parsePositiveNumber(process.env.KCC20_CONSOLIDATE_PEER_COMPUTE_BUDGET || 200, "peerComputeBudget");
6172
+ const peerComputeBudget = parsePositiveNumber(env.KCC20_CONSOLIDATE_PEER_COMPUTE_BUDGET || 200, "peerComputeBudget");
6115
6173
  const computeBudget = Math.max(configuredPrimaryComputeBudget, 500 + holderUtxos.length * 100);
6116
6174
  const states = holderUtxos.map((utxo) => kcc20StateFromUtxo(utxo, request.owner));
6117
6175
  const primaryState = states[0];
@@ -6272,12 +6330,12 @@ export function createKcc20PsktBuilderEngine(options) {
6272
6330
  const params = request.params || {};
6273
6331
  const covenantId = requireHex32(params.covenantId, "canonical covenant id");
6274
6332
  const owner = requireHex32(request.owner?.kcc20Owner, "token owner");
6275
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
6333
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
6276
6334
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
6277
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6278
- const priorityFee = parseU64(process.env.KCC20_REVEAL_PRIORITY_FEE_SOMPI ||
6335
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6336
+ const priorityFee = parseU64(env.KCC20_REVEAL_PRIORITY_FEE_SOMPI ||
6279
6337
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
6280
- const computeBudget = parsePositiveNumber(process.env.KCC20_REVEAL_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
6338
+ const computeBudget = parsePositiveNumber(env.KCC20_REVEAL_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
6281
6339
  const inputState = kcc20StateFromUtxo(activeTokenUtxo, request.owner);
6282
6340
  if (inputState.isMintAuthority) {
6283
6341
  throw new Error("self-transfer reveal requires a KCC20 holder UTXO");
@@ -6412,14 +6470,14 @@ export function createKcc20PsktBuilderEngine(options) {
6412
6470
  const recipientOwner = requireHex32(params.recipientOwner, "transfer recipient owner");
6413
6471
  const recipientOwnerScheme = parseOwnerScheme(params.recipientOwnerScheme ?? params.recipientOwnerType ?? 0, "recipientOwnerScheme");
6414
6472
  const transferAmount = parsePositiveU64(params.tokenAmount, "tokenAmount");
6415
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
6473
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
6416
6474
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
6417
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6418
- const tokenOutputSompi = assertKcc20TokenOutputSompi(parseU64(process.env.KCC20_TRANSFER_TOKEN_OUTPUT_SOMPI ||
6475
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6476
+ const tokenOutputSompi = assertKcc20TokenOutputSompi(parseU64(env.KCC20_TRANSFER_TOKEN_OUTPUT_SOMPI ||
6419
6477
  DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi"), "transfer");
6420
- const priorityFee = parseU64(process.env.KCC20_TRANSFER_PRIORITY_FEE_SOMPI ||
6478
+ const priorityFee = parseU64(env.KCC20_TRANSFER_PRIORITY_FEE_SOMPI ||
6421
6479
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
6422
- const computeBudget = parsePositiveNumber(process.env.KCC20_TRANSFER_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
6480
+ const computeBudget = parsePositiveNumber(env.KCC20_TRANSFER_COMPUTE_BUDGET || DEFAULT_COMPUTE_BUDGET, "computeBudget");
6423
6481
  const inputState = kcc20StateFromUtxo(activeHolderUtxo, request.owner);
6424
6482
  if (inputState.isMintAuthority || inputState.amount <= 0n) {
6425
6483
  throw new Error("KCC20 transfer requires a holder UTXO");
@@ -6588,15 +6646,15 @@ export function createKcc20PsktBuilderEngine(options) {
6588
6646
  const mintPolicy = parseMintPolicy(params.mintPolicy || mintPolicyName(params.mintPolicyValue ?? 0));
6589
6647
  const mintPriceSompi = parseU64(params.mintPricePerTokenSompi || "0", "mintPricePerTokenSompi");
6590
6648
  const feeBps = parseFeeBps(params.protocolFeeBps ??
6591
- config.KCC20_PROTOCOL_FEE_BPS ??
6649
+ env.KCC20_PROTOCOL_FEE_BPS ??
6592
6650
  DEFAULT_KCC20_FEE_BPS);
6593
6651
  const decimals = parseU64(params.decimals ?? "0", "decimals");
6594
6652
  const priceScale = 10n ** decimals;
6595
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
6653
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
6596
6654
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
6597
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6598
- const amountTkas = parseAmountTkas(process.env.KCC20_DEPLOY_OUTPUT_TKAS || DEFAULT_DEPLOY_TKAS);
6599
- const priorityFee = parseU64(process.env.KCC20_DEPLOY_PRIORITY_FEE_SOMPI ||
6655
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6656
+ const amountTkas = parseAmountTkas(env.KCC20_DEPLOY_OUTPUT_TKAS || DEFAULT_DEPLOY_TKAS);
6657
+ const priorityFee = parseU64(env.KCC20_DEPLOY_PRIORITY_FEE_SOMPI ||
6600
6658
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
6601
6659
  const metadata = {
6602
6660
  ticker: normalizeTicker(params.ticker || ""),
@@ -6613,6 +6671,12 @@ export function createKcc20PsktBuilderEngine(options) {
6613
6671
  const artifact = await readStaticArtifact(KCC20_ARTIFACT_PATH);
6614
6672
  const displayScale = priceScale;
6615
6673
  const remainingSupply = maxSupply - premintSupply;
6674
+ const mintLaneCount = mintPolicy === 0
6675
+ ? 1n
6676
+ : parseMintLaneCount(params.mintLaneCount ?? 1, "mintLaneCount");
6677
+ const mintLaneSupplies = mintPolicy === 0
6678
+ ? []
6679
+ : splitKcc20MintSupply(remainingSupply, mintLaneCount);
6616
6680
  const immutableExtension = {
6617
6681
  kind: 1,
6618
6682
  creator: hexToBytes(owner),
@@ -6620,8 +6684,7 @@ export function createKcc20PsktBuilderEngine(options) {
6620
6684
  name: asciiToBytes32(metadata.name, "token name"),
6621
6685
  displayScale,
6622
6686
  maxSupply,
6623
- // The backend currently creates one mint authority output.
6624
- mintLaneCount: 1n,
6687
+ mintLaneCount,
6625
6688
  mintPolicy,
6626
6689
  mintPriceSompi,
6627
6690
  treasury: hexToBytes(treasury),
@@ -6629,23 +6692,32 @@ export function createKcc20PsktBuilderEngine(options) {
6629
6692
  protocolFeeBps: BigInt(feeBps),
6630
6693
  };
6631
6694
  const holderCommitment = holderExtensionCommitment(immutableExtension);
6632
- const extension = mintPolicy === 0
6695
+ const baseExtension = mintPolicy === 0
6633
6696
  ? null
6634
6697
  : {
6635
6698
  ...immutableExtension,
6636
- remainingSupply,
6637
6699
  publicMintActive: false,
6638
6700
  holderExtensionCommitment: holderCommitment,
6639
6701
  };
6702
+ const minterStates = baseExtension
6703
+ ? mintLaneSupplies.map((laneSupply) => {
6704
+ const extension = { ...baseExtension, remainingSupply: laneSupply };
6705
+ return {
6706
+ extension,
6707
+ state: {
6708
+ amount: 0n,
6709
+ owner: hexToBytes(owner),
6710
+ ownerScheme: 0,
6711
+ borrowScheme: 0,
6712
+ borrowGuard: hexToBytes(ZERO_HASH),
6713
+ extensionCommitment: mintExtensionCommitment(extension),
6714
+ },
6715
+ };
6716
+ })
6717
+ : [];
6718
+ const extension = minterStates[0]?.extension ?? null;
6640
6719
  const state = extension
6641
- ? {
6642
- amount: 0n,
6643
- owner: hexToBytes(owner),
6644
- ownerScheme: 0,
6645
- borrowScheme: 0,
6646
- borrowGuard: hexToBytes(ZERO_HASH),
6647
- extensionCommitment: mintExtensionCommitment(extension),
6648
- }
6720
+ ? minterStates[0].state
6649
6721
  : {
6650
6722
  amount: maxSupply,
6651
6723
  owner: hexToBytes(premintRecipient),
@@ -6664,19 +6736,26 @@ export function createKcc20PsktBuilderEngine(options) {
6664
6736
  extensionCommitment: holderCommitment,
6665
6737
  }
6666
6738
  : null;
6739
+ const covenantStates = extension
6740
+ ? minterStates.map(({ state }) => state)
6741
+ : [state];
6742
+ if (premintState)
6743
+ covenantStates.push(premintState);
6667
6744
  const kw = kaspaWasm;
6668
6745
  const { Encoding, GenesisCovenantGroup, RpcClient, Transaction, TransactionOutput, addressFromScriptPublicKey, payToAddressScript, payToScriptHashScript, } = kw;
6669
- const contractScript = buildKcc20ScriptForState(artifact, state);
6670
- const contractScriptPubKey = payToScriptHashScript(contractScript);
6671
- const canonicalCovenantId = p2shScriptHashHex(kw, contractScript);
6672
- const contractAddress = addressFromScriptPublicKey(contractScriptPubKey, network).toString();
6746
+ const covenantOutputs = covenantStates.map((covenantState) => {
6747
+ const script = buildKcc20ScriptForState(artifact, covenantState);
6748
+ const scriptPublicKey = payToScriptHashScript(script);
6749
+ return {
6750
+ script,
6751
+ scriptPublicKey,
6752
+ address: addressFromScriptPublicKey(scriptPublicKey, network).toString(),
6753
+ };
6754
+ });
6755
+ const contractAddress = covenantOutputs[0].address;
6756
+ const canonicalCovenantId = p2shScriptHashHex(kw, covenantOutputs[0].script);
6673
6757
  const deploySompi = BigInt(Math.round(amountTkas * Number(SOMPI_PER_TKAS)));
6674
- const deployOutputs = [{ address: contractAddress, amount: deploySompi }];
6675
- let premintAddress = null;
6676
- if (premintState) {
6677
- premintAddress = addressFromScriptPublicKey(payToScriptHashScript(buildKcc20ScriptForState(artifact, premintState)), network).toString();
6678
- deployOutputs.push({ address: premintAddress, amount: deploySompi });
6679
- }
6758
+ const premintOutputIndex = premintState ? covenantOutputs.length - 1 : null;
6680
6759
  const rpc = new RpcClient({
6681
6760
  url: rpcUrl,
6682
6761
  encoding: Encoding.Borsh,
@@ -6685,20 +6764,17 @@ export function createKcc20PsktBuilderEngine(options) {
6685
6764
  await rpc.connect();
6686
6765
  try {
6687
6766
  const utxos = await getUtxosByAddresses(rpc, [walletAddress]);
6688
- const outputSompi = deploySompi * BigInt(deployOutputs.length);
6767
+ const outputSompi = deploySompi * BigInt(covenantOutputs.length);
6689
6768
  const fundingEntry = selectFundingEntry(utxos.entries, outputSompi + priorityFee + 10000000n);
6690
- const fundingChangeOutputIndex = 1;
6769
+ const fundingChangeOutputIndex = covenantOutputs.length;
6691
6770
  const change = utxoAmountSompi(fundingEntry) - outputSompi - priorityFee;
6692
6771
  if (change <= 10000n) {
6693
6772
  throw kcc20PsktBuilderError("deploy PSKT builder selected insufficient change", "KAS_FUNDING_CHANGE_TOO_SMALL");
6694
6773
  }
6695
6774
  const outputs = [
6696
- new TransactionOutput(deploySompi, contractScriptPubKey),
6775
+ ...covenantOutputs.map(({ scriptPublicKey }) => new TransactionOutput(deploySompi, scriptPublicKey)),
6697
6776
  new TransactionOutput(change, payToAddressScript(walletAddress)),
6698
6777
  ];
6699
- if (premintState) {
6700
- outputs.push(new TransactionOutput(deploySompi, payToScriptHashScript(buildKcc20ScriptForState(artifact, premintState))));
6701
- }
6702
6778
  const unsignedTx = new Transaction({
6703
6779
  version: 1,
6704
6780
  lockTime: 0n,
@@ -6733,17 +6809,8 @@ export function createKcc20PsktBuilderEngine(options) {
6733
6809
  });
6734
6810
  unsignedTx.version = 1;
6735
6811
  setVersionOneInputMassFields(unsignedTx);
6736
- const covenantOutputIndex = findOutputIndex(unsignedTx, contractAddress, network, addressFromScriptPublicKey);
6737
- if (covenantOutputIndex < 0)
6738
- throw new Error("final transaction did not contain the KCC20 output");
6739
- const covenantOutputIndexes = [covenantOutputIndex];
6740
- let premintOutputIndex = null;
6741
- if (premintAddress) {
6742
- premintOutputIndex = findOutputIndex(unsignedTx, premintAddress, network, addressFromScriptPublicKey);
6743
- if (premintOutputIndex < 0)
6744
- throw new Error("final transaction did not contain the KCC20 premint output");
6745
- covenantOutputIndexes.push(premintOutputIndex);
6746
- }
6812
+ const covenantOutputIndex = 0;
6813
+ const covenantOutputIndexes = covenantOutputs.map((_, index) => index);
6747
6814
  unsignedTx.populateGenesisCovenants([
6748
6815
  new GenesisCovenantGroup(0, covenantOutputIndexes),
6749
6816
  ]);
@@ -6756,6 +6823,7 @@ export function createKcc20PsktBuilderEngine(options) {
6756
6823
  if (typeof psktTransactionJson !== "string") {
6757
6824
  throw new Error("KCC20 deploy PSKT serialization did not return JSON text");
6758
6825
  }
6826
+ const revealScriptHex = bytesToHex(covenantOutputs[covenantOutputIndex].script);
6759
6827
  return {
6760
6828
  schema: OUTPUT_SCHEMA,
6761
6829
  psktTransactionJson,
@@ -6771,6 +6839,9 @@ export function createKcc20PsktBuilderEngine(options) {
6771
6839
  walletAddress,
6772
6840
  contractAddress,
6773
6841
  covenantOutputIndex,
6842
+ minterOutputIndexes: extension
6843
+ ? minterStates.map((_, index) => index)
6844
+ : undefined,
6774
6845
  premintOutputIndex,
6775
6846
  covenantId: kip20BindingCovenantId,
6776
6847
  scriptHashHex: canonicalCovenantId,
@@ -6781,6 +6852,44 @@ export function createKcc20PsktBuilderEngine(options) {
6781
6852
  mintPolicy,
6782
6853
  publicMintActive: mintPolicy === 2 ? false : undefined,
6783
6854
  mintLaneCount: immutableExtension.mintLaneCount.toString(),
6855
+ holderExtensionCommitment: bytesToHex(holderCommitment),
6856
+ revealScriptHex,
6857
+ maximumFeeSompi: ([...feeAdjustedTx.inputs].reduce((sum, input) => sum + BigInt(input.utxo?.amount ?? input.utxo?.value), 0n) -
6858
+ [...feeAdjustedTx.outputs].reduce((sum, output) => sum + BigInt(output.value ?? output.amount), 0n)).toString(),
6859
+ intentInputs: [{ role: "creator-funding", index: 0 }],
6860
+ intentOutputs: buildKcc20DeployIntentOutputs({
6861
+ mintPolicy,
6862
+ covenantId: kip20BindingCovenantId,
6863
+ creator: owner,
6864
+ premintRecipient,
6865
+ premintOwnerScheme,
6866
+ maxSupply,
6867
+ premintSupply,
6868
+ borrowGuard: ZERO_HASH,
6869
+ fixedOutput: mintPolicy === 0
6870
+ ? {
6871
+ index: covenantOutputIndex,
6872
+ revealScriptHex,
6873
+ extensionCommitment: bytesToHex(holderCommitment),
6874
+ }
6875
+ : undefined,
6876
+ minterOutputs: minterStates.map(({ state }, index) => ({
6877
+ index,
6878
+ revealScriptHex: bytesToHex(covenantOutputs[index].script),
6879
+ extensionCommitment: bytesToHex(state.extensionCommitment),
6880
+ remainingSupply: mintLaneSupplies[index],
6881
+ })),
6882
+ premintOutput: premintState && premintOutputIndex !== null
6883
+ ? {
6884
+ index: premintOutputIndex,
6885
+ revealScriptHex: bytesToHex(covenantOutputs[premintOutputIndex].script),
6886
+ extensionCommitment: bytesToHex(premintState.extensionCommitment),
6887
+ }
6888
+ : undefined,
6889
+ }),
6890
+ mintLaneSupplies: extension
6891
+ ? mintLaneSupplies.map((supply) => supply.toString())
6892
+ : undefined,
6784
6893
  extension: extension ? jsonKcc20MintExtension(extension) : undefined,
6785
6894
  ...stateToReceiptFields(state),
6786
6895
  },
@@ -6796,11 +6905,11 @@ export function createKcc20PsktBuilderEngine(options) {
6796
6905
  const owner = requireHex32(params.rootOwner || request.owner?.kcc20Owner, "root owner");
6797
6906
  const utilityTokenId = requireHex32(params.utilityTokenId, "utility token id");
6798
6907
  const denomination = parsePositiveU64(params.utilityTokenAmount, "utilityTokenAmount");
6799
- const network = request.network || process.env.KASPA_NETWORK || "testnet-10";
6908
+ const network = request.network || env.KASPA_NETWORK || "testnet-10";
6800
6909
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
6801
- const rpcUrl = process.env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6802
- const amountTkas = parseAmountTkas(process.env.KCC20_FEE_TICKET_OUTPUT_TKAS || DEFAULT_DEPLOY_TKAS);
6803
- const priorityFee = parseU64(process.env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
6910
+ const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
6911
+ const amountTkas = parseAmountTkas(env.KCC20_FEE_TICKET_OUTPUT_TKAS || DEFAULT_DEPLOY_TKAS);
6912
+ const priorityFee = parseU64(env.KCC20_FEE_TICKET_PRIORITY_FEE_SOMPI ||
6804
6913
  DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
6805
6914
  const artifact = await readStaticArtifact(FEE_TICKET_ARTIFACT_PATH);
6806
6915
  const state = {
@@ -7793,8 +7902,8 @@ export function createKcc20PsktBuilderEngine(options) {
7793
7902
  return rpc.getUtxosByAddresses({ addresses });
7794
7903
  }
7795
7904
  async function retryUtxosByAddresses(rpc, addresses, isReady, initial) {
7796
- const attempts = parseRetryInteger(process.env.KCC20_SOURCE_UTXO_RETRY_ATTEMPTS, 3);
7797
- const delayMs = parseRetryInteger(process.env.KCC20_SOURCE_UTXO_RETRY_DELAY_MS, 500);
7905
+ const attempts = parseRetryInteger(env.KCC20_SOURCE_UTXO_RETRY_ATTEMPTS, 3);
7906
+ const delayMs = parseRetryInteger(env.KCC20_SOURCE_UTXO_RETRY_DELAY_MS, 500);
7798
7907
  let latest = initial ?? { entries: [] };
7799
7908
  for (let attempt = 1; attempt < attempts; attempt += 1) {
7800
7909
  if (delayMs > 0) {
@@ -8963,6 +9072,7 @@ export function createKcc20PsktBuilderEngine(options) {
8963
9072
  assertTransactionStorageMassStandard,
8964
9073
  calculateToccataStorageMass,
8965
9074
  parseQuotedProtocolFeeSompi,
9075
+ splitKcc20MintSupply,
8966
9076
  }),
8967
9077
  };
8968
9078
  }