@kaspacom/kcc20-tx-builder 0.5.0 → 0.6.1

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 (119) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +2 -2
  3. package/RELEASING.md +19 -14
  4. package/artifacts/ArgentKCC20.reference.json +12428 -0
  5. package/artifacts/ArgentKCC20Wrapper.placeholder.json +12455 -0
  6. package/artifacts/KCC20.placeholder.json +1447 -1973
  7. package/artifacts/KCC20FeeTicket.placeholder.json +816 -1447
  8. package/artifacts/KCC20Orderbook.placeholder.json +1 -2
  9. package/artifacts/KCC20SnapshotBootstrap.placeholder.json +101 -100
  10. package/artifacts/KCC20SnapshotController.placeholder.json +101 -100
  11. package/artifacts/KCC20Vesting.placeholder.json +427 -429
  12. package/artifacts/KCC20Wrapper.placeholder.json +733 -734
  13. package/artifacts/kcc20-snapshot-bootstrap/KCC20SnapshotBootstrap.placeholder.json +101 -100
  14. package/artifacts/kcc20-snapshot-controller/KCC20SnapshotController.placeholder.json +101 -100
  15. package/artifacts/snapshot-standards.lock.json +6 -3
  16. package/artifacts/token-profiles.json +109 -0
  17. package/artifacts/token-profiles.sha256 +1 -0
  18. package/dist/action-source-resolver.d.ts.map +1 -1
  19. package/dist/action-source-resolver.js +11 -2
  20. package/dist/action-source-resolver.js.map +1 -1
  21. package/dist/artifacts.d.ts +10 -10
  22. package/dist/artifacts.d.ts.map +1 -1
  23. package/dist/artifacts.js +10 -10
  24. package/dist/artifacts.js.map +1 -1
  25. package/dist/cjs/action-source-resolver.js +11 -2
  26. package/dist/cjs/action-source-resolver.js.map +1 -1
  27. package/dist/cjs/artifacts.d.ts +10 -10
  28. package/dist/cjs/artifacts.js +10 -10
  29. package/dist/cjs/artifacts.js.map +1 -1
  30. package/dist/cjs/engine.d.ts +10 -0
  31. package/dist/cjs/engine.js +129 -77
  32. package/dist/cjs/engine.js.map +1 -1
  33. package/dist/cjs/index.d.ts +5 -0
  34. package/dist/cjs/index.js +5 -0
  35. package/dist/cjs/index.js.map +1 -1
  36. package/dist/cjs/profile-transfer.d.ts +60 -0
  37. package/dist/cjs/profile-transfer.js +248 -0
  38. package/dist/cjs/profile-transfer.js.map +1 -0
  39. package/dist/cjs/snapshot-signerless-transactions.js +2 -5
  40. package/dist/cjs/snapshot-signerless-transactions.js.map +1 -1
  41. package/dist/cjs/snapshot-signerless.js +5 -3
  42. package/dist/cjs/snapshot-signerless.js.map +1 -1
  43. package/dist/cjs/token-authorization.d.ts +42 -0
  44. package/dist/cjs/token-authorization.js +93 -0
  45. package/dist/cjs/token-authorization.js.map +1 -0
  46. package/dist/cjs/token-profiles.d.ts +82 -0
  47. package/dist/cjs/token-profiles.generated.d.ts +3 -0
  48. package/dist/cjs/token-profiles.generated.js +114 -0
  49. package/dist/cjs/token-profiles.generated.js.map +1 -0
  50. package/dist/cjs/token-profiles.js +257 -0
  51. package/dist/cjs/token-profiles.js.map +1 -0
  52. package/dist/cjs/transfer-payload.d.ts +9 -0
  53. package/dist/cjs/transfer-payload.js +37 -0
  54. package/dist/cjs/transfer-payload.js.map +1 -0
  55. package/dist/cjs/wrapper-operation.d.ts +1 -0
  56. package/dist/cjs/wrapper-operation.js +1 -0
  57. package/dist/cjs/wrapper-operation.js.map +1 -1
  58. package/dist/engine.d.ts +10 -0
  59. package/dist/engine.d.ts.map +1 -1
  60. package/dist/engine.js +130 -78
  61. package/dist/engine.js.map +1 -1
  62. package/dist/index.d.ts +5 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +5 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/profile-transfer.d.ts +61 -0
  67. package/dist/profile-transfer.d.ts.map +1 -0
  68. package/dist/profile-transfer.js +245 -0
  69. package/dist/profile-transfer.js.map +1 -0
  70. package/dist/snapshot-signerless-transactions.d.ts.map +1 -1
  71. package/dist/snapshot-signerless-transactions.js +2 -5
  72. package/dist/snapshot-signerless-transactions.js.map +1 -1
  73. package/dist/snapshot-signerless.d.ts.map +1 -1
  74. package/dist/snapshot-signerless.js +5 -3
  75. package/dist/snapshot-signerless.js.map +1 -1
  76. package/dist/token-authorization.d.ts +43 -0
  77. package/dist/token-authorization.d.ts.map +1 -0
  78. package/dist/token-authorization.js +88 -0
  79. package/dist/token-authorization.js.map +1 -0
  80. package/dist/token-profiles.d.ts +83 -0
  81. package/dist/token-profiles.d.ts.map +1 -0
  82. package/dist/token-profiles.generated.d.ts +4 -0
  83. package/dist/token-profiles.generated.d.ts.map +1 -0
  84. package/dist/token-profiles.generated.js +111 -0
  85. package/dist/token-profiles.generated.js.map +1 -0
  86. package/dist/token-profiles.js +245 -0
  87. package/dist/token-profiles.js.map +1 -0
  88. package/dist/transfer-payload.d.ts +10 -0
  89. package/dist/transfer-payload.d.ts.map +1 -0
  90. package/dist/transfer-payload.js +34 -0
  91. package/dist/transfer-payload.js.map +1 -0
  92. package/dist/wrapper-operation.d.ts +1 -0
  93. package/dist/wrapper-operation.d.ts.map +1 -1
  94. package/dist/wrapper-operation.js +1 -0
  95. package/dist/wrapper-operation.js.map +1 -1
  96. package/docs/COMPATIBILITY.json +24 -33
  97. package/docs/LAST_CALL.md +50 -0
  98. package/examples/README.md +3 -0
  99. package/examples/backend/cli.ts +2 -1
  100. package/examples/frontend/main.ts +2 -1
  101. package/examples/shared/build.ts +3 -0
  102. package/examples/shared/offline-profile.ts +27 -0
  103. package/examples/shared/recipe-fixtures.ts +3 -2
  104. package/examples/test/browser.ts +2 -2
  105. package/examples/test/build.test.ts +21 -8
  106. package/examples/test/sources.test.ts +3 -2
  107. package/package.json +2 -2
  108. package/src/action-source-resolver.ts +22 -4
  109. package/src/artifacts.ts +12 -10
  110. package/src/engine.ts +215 -105
  111. package/src/index.ts +7 -0
  112. package/src/profile-transfer.ts +425 -0
  113. package/src/snapshot-signerless-transactions.ts +7 -16
  114. package/src/snapshot-signerless.ts +5 -3
  115. package/src/token-authorization.ts +135 -0
  116. package/src/token-profiles.generated.ts +112 -0
  117. package/src/token-profiles.ts +456 -0
  118. package/src/transfer-payload.ts +45 -0
  119. package/src/wrapper-operation.ts +2 -0
@@ -2,7 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createKcc20PsktBuilderEngine = createKcc20PsktBuilderEngine;
4
4
  // @ts-nocheck
5
+ const token_authorization_js_1 = require("./token-authorization.js");
5
6
  const sha256_1 = require("@noble/hashes/sha256");
7
+ const token_profiles_js_1 = require("./token-profiles.js");
8
+ const transfer_payload_js_1 = require("./transfer-payload.js");
9
+ const token_profiles_generated_js_1 = require("./token-profiles.generated.js");
6
10
  const sale_common_js_1 = require("./sale-common.js");
7
11
  const abi_js_1 = require("./abi.js");
8
12
  const operations_js_1 = require("./operations.js");
@@ -105,6 +109,7 @@ function createKcc20PsktBuilderEngine(options) {
105
109
  const WRAPPED_ARTIFACT_PATH = "KCC20Orderbook.placeholder.json";
106
110
  const FEE_TICKET_ARTIFACT_PATH = "KCC20FeeTicket.placeholder.json";
107
111
  const staticArtifactCache = new Map();
112
+ const tokenProfiles = (0, token_profiles_js_1.validateTokenProfileRegistry)(options.tokenProfileRegistry?.manifest ?? token_profiles_generated_js_1.BUNDLED_TOKEN_PROFILES, options.tokenProfileRegistry?.sha256 ?? token_profiles_generated_js_1.BUNDLED_TOKEN_PROFILE_DIGEST);
108
113
  function readStaticArtifact(path) {
109
114
  let cached = staticArtifactCache.get(path);
110
115
  if (!cached) {
@@ -117,7 +122,16 @@ function createKcc20PsktBuilderEngine(options) {
117
122
  ? (artifact.artifact ?? artifact)
118
123
  : artifact;
119
124
  const normalized = (0, abi_js_1.normalizeSilverScriptArtifact)(artifactValue);
120
- (0, artifacts_js_1.assertKcc20ArtifactScriptHash)(path, normalized);
125
+ const profile = tokenProfiles.profiles.find((p) => p.artifactKey === path);
126
+ if (profile)
127
+ (0, token_profiles_js_1.authenticateTokenArtifact)(profile, artifactValue);
128
+ else {
129
+ const ownerProfile = tokenProfiles.profiles.find((p) => p.wrapper?.artifactKey === path);
130
+ if (ownerProfile)
131
+ (0, token_profiles_js_1.authenticateTokenWrapper)(ownerProfile, artifactValue);
132
+ else
133
+ (0, artifacts_js_1.assertKcc20ArtifactScriptHash)(path, normalized);
134
+ }
121
135
  return normalized;
122
136
  })
123
137
  .catch((error) => {
@@ -135,15 +149,20 @@ function createKcc20PsktBuilderEngine(options) {
135
149
  };
136
150
  }
137
151
  async function resolveKcc20ArtifactForState(state, address, network) {
138
- const artifact = await readStaticArtifact(KCC20_ARTIFACT_PATH);
139
- const script = (0, abi_js_1.buildKcc20ScriptForState)(artifact, state);
140
- const candidateAddress = kaspaWasm
141
- .addressFromScriptPublicKey(kaspaWasm.payToScriptHashScript(script), network)
142
- .toString();
143
- if (candidateAddress !== address) {
144
- throw new Error("KCC20 UTXO address does not match the current artifact");
152
+ for (const profile of tokenProfiles.profiles) {
153
+ const artifact = await readStaticArtifact(profile.artifactKey);
154
+ const script = (0, abi_js_1.buildKcc20ScriptForState)(artifact, state);
155
+ const candidateAddress = kaspaWasm
156
+ .addressFromScriptPublicKey(kaspaWasm.payToScriptHashScript(script), network)
157
+ .toString();
158
+ if (candidateAddress !== address)
159
+ continue;
160
+ (0, token_profiles_js_1.requireTokenCapability)(profile, "transfer");
161
+ if (!profile.ownerSchemes.includes(Number(state.ownerScheme ?? state.identifierType)))
162
+ throw new Error("owner scheme is unsupported by this token profile");
163
+ return { version: profile.id, profile, artifact, script };
145
164
  }
146
- return { version: "standard-native-v1", artifact, script };
165
+ throw new Error("KCC20 UTXO address does not match a bundled token profile");
147
166
  }
148
167
  function artifactEntrypointDispatchTag(artifact, entrypoint) {
149
168
  try {
@@ -178,13 +197,14 @@ function createKcc20PsktBuilderEngine(options) {
178
197
  },
179
198
  ];
180
199
  }
181
- async function readWrapperArtifacts() {
182
- return [
183
- {
184
- artifact: await readStaticArtifact(WRAPPER_ARTIFACT_PATH),
200
+ async function readWrapperArtifacts(profile) {
201
+ if (!profile.wrapper)
202
+ return [];
203
+ return [{
204
+ artifact: await readStaticArtifact(profile.wrapper.artifactKey),
185
205
  version: "standard-native-v1",
186
- },
187
- ];
206
+ tokenProfileId: profile.id,
207
+ }];
188
208
  }
189
209
  function wrappedArtifactSupportsEntrypoint(info, name) {
190
210
  return Array.isArray(info?.artifact?.abi)
@@ -544,7 +564,7 @@ function createKcc20PsktBuilderEngine(options) {
544
564
  };
545
565
  const kw = kaspaWasm;
546
566
  const { CovenantBinding, Encoding, Hash, RpcClient, ScriptBuilder, Transaction, TransactionOutput, addressFromScriptPublicKey, payToAddressScript, payToScriptHashScript, } = kw;
547
- const utilityScript = (0, sale_common_js_1.buildNativeKcc20ScriptForState)(kcc20Artifact.script, utilityState);
567
+ const utilityScript = (0, abi_js_1.buildKcc20ScriptForState)(kcc20Artifact, utilityState);
548
568
  const rootAddress = requireKaspaAddress(rootUtxo.address);
549
569
  const utilityAddress = requireKaspaAddress(utilityUtxo.address);
550
570
  const rootArtifactInfo = selectFeeTicketArtifactForState(feeTicketArtifacts, rootState, rootAddress, network, "active FeeTicket root UTXO address");
@@ -1662,10 +1682,7 @@ function createKcc20PsktBuilderEngine(options) {
1662
1682
  const feeTicketId = (0, sale_common_js_1.requireHex32)(params.feeTicketId || sale_common_js_1.ZERO_HASH, "fee ticket id");
1663
1683
  const deployerOwner = (0, sale_common_js_1.requireHex32)(params.deployerOwner || request.owner?.kcc20Owner, "deployer owner");
1664
1684
  const rootAmount = parseU64(params.wrappedRootAmount ?? "0", "wrappedRootAmount");
1665
- const priceScale = parsePositiveU64(params.priceScale ??
1666
- params.tokenDisplayScale ??
1667
- sale_common_js_1.DEFAULT_KCC20_PRICE_SCALE, "priceScale");
1668
- assertWrapperArtifactPriceScale(priceScale);
1685
+ const requestedPriceScale = params.priceScale ?? params.tokenDisplayScale;
1669
1686
  const network = request.network || env.KASPA_NETWORK || "testnet-10";
1670
1687
  const walletAddress = requireKaspaAddress(request.owner?.walletAddress);
1671
1688
  const rpcUrl = env.KASPA_WRPC_URL || DEFAULT_WRPC_URL;
@@ -1674,7 +1691,19 @@ function createKcc20PsktBuilderEngine(options) {
1674
1691
  DEFAULT_DEPLOY_TKAS, "KCC20_WRAPPER_DEPLOY_OUTPUT_TKAS");
1675
1692
  const priorityFee = wrapperDeployPriorityFee(env.KCC20_WRAPPER_DEPLOY_PRIORITY_FEE_SOMPI);
1676
1693
  const computeBudget = parsePositiveNumber(env.KCC20_WRAPPER_DEPLOY_COMPUTE_BUDGET || 600, "computeBudget");
1677
- const wrapperArtifact = await readStaticArtifact(WRAPPER_ARTIFACT_PATH);
1694
+ const evidence = params.tokenUtxo;
1695
+ if (!evidence)
1696
+ throw new Error("authenticated token output is required before wrapper deployment");
1697
+ const sourceState = kcc20StateFromUtxo(evidence, request.owner);
1698
+ const sourceProfile = await resolveKcc20ArtifactForState(sourceState, requireKaspaAddress(evidence.address), network);
1699
+ (0, token_profiles_js_1.requireTokenCapability)(sourceProfile.profile, "wrap");
1700
+ if (!sourceProfile.profile.wrapper)
1701
+ throw new Error("token profile has no wrapper adapter");
1702
+ const priceScale = (0, token_profiles_js_1.resolveTokenProfilePriceScale)(sourceProfile.profile, requestedPriceScale === undefined
1703
+ ? undefined
1704
+ : parsePositiveU64(requestedPriceScale, "priceScale"), sale_common_js_1.DEFAULT_KCC20_PRICE_SCALE);
1705
+ assertWrapperArtifactPriceScale(priceScale);
1706
+ const wrapperArtifact = await readStaticArtifact(sourceProfile.profile.wrapper.artifactKey);
1678
1707
  const wrappedArtifacts = await readWrappedArtifacts();
1679
1708
  const wrappedArtifact = wrappedArtifacts[0].artifact;
1680
1709
  const wrapperState = {
@@ -1707,6 +1736,18 @@ function createKcc20PsktBuilderEngine(options) {
1707
1736
  });
1708
1737
  await rpc.connect();
1709
1738
  try {
1739
+ const evidenceUtxos = await getUtxosByAddresses(rpc, [evidence.address]);
1740
+ const sourceEntry = findUtxoEntry(evidenceUtxos.entries, (0, sale_common_js_1.requireHex32)(evidence.txidHex, "token evidence txid"), parseVout(evidence.vout, "token evidence vout"));
1741
+ if (!sourceEntry)
1742
+ throw new Error("token evidence is spent or unavailable");
1743
+ requireMatchingCovenantId(sourceEntry, contractCanonicalTokenId, "wrapper token evidence");
1744
+ const sourceSpk = sourceEntry.scriptPublicKey ??
1745
+ sourceEntry.entry?.scriptPublicKey ??
1746
+ sourceEntry.utxoEntry?.scriptPublicKey;
1747
+ if (!sourceSpk ||
1748
+ kw.addressFromScriptPublicKey(sourceSpk, network)?.toString() !==
1749
+ evidence.address)
1750
+ throw new Error("token evidence script does not match RPC");
1710
1751
  const utxos = await getUtxosByAddresses(rpc, [walletAddress]);
1711
1752
  const fundingEntry = (0, sale_common_js_1.selectFundingEntry)(utxos.entries, deploySompi * 2n + priorityFee + 10000000n);
1712
1753
  const fundingChangeOutputIndex = 2;
@@ -1787,6 +1828,9 @@ function createKcc20PsktBuilderEngine(options) {
1787
1828
  submitTransactionSupported: true,
1788
1829
  metadata: {
1789
1830
  builderKey: "kcc20wrapper.deploy-market",
1831
+ tokenProfileId: sourceProfile.profile.id,
1832
+ tokenProfileRegistryHash: options.tokenProfileRegistry?.sha256 ??
1833
+ token_profiles_generated_js_1.BUNDLED_TOKEN_PROFILE_DIGEST,
1790
1834
  contract: "KCC20Wrapper",
1791
1835
  network,
1792
1836
  walletAddress,
@@ -1866,10 +1910,7 @@ function createKcc20PsktBuilderEngine(options) {
1866
1910
  sale_common_js_1.DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
1867
1911
  const priorityFee = parseU64(env.KCC20_WRAP_PRIORITY_FEE_SOMPI || DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
1868
1912
  const computeBudget = parsePositiveNumber(env.KCC20_WRAP_COMPUTE_BUDGET || 700, "computeBudget");
1869
- const [wrapperArtifacts, wrappedArtifacts] = await Promise.all([
1870
- readWrapperArtifacts(),
1871
- readWrappedArtifacts(),
1872
- ]);
1913
+ const wrappedArtifacts = await readWrappedArtifacts();
1873
1914
  const holderState = kcc20StateFromUtxo(holderUtxo, request.owner);
1874
1915
  if (holderState.identifierType !== 0) {
1875
1916
  throw new Error("wrap requires pubkey-owned KCC20 holder UTXO");
@@ -1884,6 +1925,8 @@ function createKcc20PsktBuilderEngine(options) {
1884
1925
  }
1885
1926
  const kcc20ArtifactInfo = await resolveKcc20ArtifactForState(holderState, requireKaspaAddress(holderUtxo.address), network);
1886
1927
  const kcc20Artifact = kcc20ArtifactInfo.artifact;
1928
+ (0, token_profiles_js_1.requireTokenCapability)(kcc20ArtifactInfo.profile, "wrap");
1929
+ const wrapperArtifacts = await readWrapperArtifacts(kcc20ArtifactInfo.profile);
1887
1930
  const remaining = holderState.amount - tokenAmount;
1888
1931
  const priceScale = parsePositiveU64(wrapperUtxo.state?.priceScale ??
1889
1932
  wrapperUtxo.state?.tokenDisplayScale ??
@@ -1910,7 +1953,7 @@ function createKcc20PsktBuilderEngine(options) {
1910
1953
  const { CovenantBinding, Encoding, Hash, RpcClient, ScriptBuilder, Transaction, TransactionOutput, payToAddressScript, payToScriptHashScript, } = kw;
1911
1954
  const wrapperArtifactInfo = selectWrapperArtifactForUtxo({
1912
1955
  kw,
1913
- artifacts: wrapperArtifacts,
1956
+ artifacts: wrapperArtifacts.filter((info) => info.tokenProfileId === kcc20ArtifactInfo.profile.id),
1914
1957
  state: wrapperState,
1915
1958
  utxo: wrapperUtxo,
1916
1959
  network,
@@ -1923,7 +1966,7 @@ function createKcc20PsktBuilderEngine(options) {
1923
1966
  const wrapperArtifact = wrapperArtifactInfo.artifact;
1924
1967
  const wrappedArtifact = wrappedArtifactInfo.artifact;
1925
1968
  const wrapperScript = wrapperArtifactInfo.script;
1926
- const holderScript = (0, sale_common_js_1.buildNativeKcc20ScriptForState)(kcc20Artifact.script, holderState);
1969
+ const holderScript = (0, abi_js_1.buildKcc20ScriptForState)(kcc20Artifact, holderState);
1927
1970
  const wrapperAddress = requireKaspaAddress(wrapperUtxo.address);
1928
1971
  const holderAddress = requireKaspaAddress(holderUtxo.address);
1929
1972
  assertScriptAddress(kw, holderScript, holderAddress, network, "KCC20 holder UTXO address");
@@ -2136,10 +2179,7 @@ function createKcc20PsktBuilderEngine(options) {
2136
2179
  sale_common_js_1.DEFAULT_TOKEN_OUTPUT_SOMPI.toString(), "tokenOutputSompi");
2137
2180
  const priorityFee = parseU64(env.KCC20_UNWRAP_PRIORITY_FEE_SOMPI || DEFAULT_PRIORITY_FEE.toString(), "priorityFee");
2138
2181
  const computeBudget = parsePositiveNumber(env.KCC20_UNWRAP_COMPUTE_BUDGET || 700, "computeBudget");
2139
- const [wrapperArtifacts, wrappedArtifacts] = await Promise.all([
2140
- readWrapperArtifacts(),
2141
- readWrappedArtifacts(),
2142
- ]);
2182
+ const wrappedArtifacts = await readWrappedArtifacts();
2143
2183
  const reserveState = kcc20StateFromUtxo(reserveUtxo, request.owner);
2144
2184
  if (reserveState.ownerScheme !== 4 || reserveState.isMintAuthority) {
2145
2185
  throw new Error("KCC20 reserve UTXO must be covenant-owned holder state");
@@ -2149,6 +2189,8 @@ function createKcc20PsktBuilderEngine(options) {
2149
2189
  }
2150
2190
  const kcc20ArtifactInfo = await resolveKcc20ArtifactForState(reserveState, requireKaspaAddress(reserveUtxo.address), network);
2151
2191
  const kcc20Artifact = kcc20ArtifactInfo.artifact;
2192
+ (0, token_profiles_js_1.requireTokenCapability)(kcc20ArtifactInfo.profile, "unwrap");
2193
+ const wrapperArtifacts = await readWrapperArtifacts(kcc20ArtifactInfo.profile);
2152
2194
  const wrappedState = kcc20V3WrappedStateFromUtxo(wrappedUtxo, canonicalTokenId, request.owner);
2153
2195
  if ((0, sale_common_js_1.bytesToHex)(wrappedState.ownerIdentifier) !== recipientOwner) {
2154
2196
  throw new Error("KCC20 orderbook holder UTXO is not owned by authenticated wallet");
@@ -2192,7 +2234,7 @@ function createKcc20PsktBuilderEngine(options) {
2192
2234
  const { CovenantBinding, Encoding, Hash, RpcClient, ScriptBuilder, Transaction, TransactionOutput, payToAddressScript, payToScriptHashScript, } = kw;
2193
2235
  const wrapperArtifactInfo = selectWrapperArtifactForUtxo({
2194
2236
  kw,
2195
- artifacts: wrapperArtifacts,
2237
+ artifacts: wrapperArtifacts.filter((info) => info.tokenProfileId === kcc20ArtifactInfo.profile.id),
2196
2238
  state: wrapperState,
2197
2239
  utxo: wrapperUtxo,
2198
2240
  network,
@@ -2214,7 +2256,7 @@ function createKcc20PsktBuilderEngine(options) {
2214
2256
  const wrapperScript = wrapperArtifactInfo.script;
2215
2257
  const wrappedScript = wrappedArtifactInfo.script;
2216
2258
  const refundAware = wrappedArtifactRefundsHolderDeposits(wrappedArtifactInfo);
2217
- const reserveScript = (0, sale_common_js_1.buildNativeKcc20ScriptForState)(kcc20Artifact.script, reserveState);
2259
+ const reserveScript = (0, abi_js_1.buildKcc20ScriptForState)(kcc20Artifact, reserveState);
2218
2260
  const wrapperAddress = wrapperArtifactInfo.address;
2219
2261
  const wrappedAddress = wrappedArtifactInfo.address;
2220
2262
  const reserveAddress = requireKaspaAddress(reserveUtxo.address);
@@ -5668,6 +5710,7 @@ function createKcc20PsktBuilderEngine(options) {
5668
5710
  extensionCommitment: (0, abi_js_1.mintExtensionCommitment)(extension),
5669
5711
  };
5670
5712
  const resolvedArtifact = await resolveKcc20ArtifactForState(inputState, minterAddress, network);
5713
+ (0, token_profiles_js_1.requireTokenCapability)(resolvedArtifact.profile, "mint");
5671
5714
  const artifact = resolvedArtifact.artifact;
5672
5715
  const recipientState = {
5673
5716
  amount: mintAmount,
@@ -5905,6 +5948,11 @@ function createKcc20PsktBuilderEngine(options) {
5905
5948
  if (requestedMinterUtxos.length === 0) {
5906
5949
  throw new Error("active KCC20 mint-authority UTXO is required");
5907
5950
  }
5951
+ // The caller submits larger updates as sequential batches. Never truncate
5952
+ // this array: every supplied authority must be represented in the result.
5953
+ if (requestedMinterUtxos.length > 5) {
5954
+ throw new Error("Public mint availability updates support at most 5 authorities per transaction");
5955
+ }
5908
5956
  if (typeof params.active !== "boolean") {
5909
5957
  throw new Error("active must be a boolean");
5910
5958
  }
@@ -5957,6 +6005,7 @@ function createKcc20PsktBuilderEngine(options) {
5957
6005
  extensionCommitment: (0, abi_js_1.mintExtensionCommitment)(nextExtension),
5958
6006
  };
5959
6007
  const resolvedArtifact = await resolveKcc20ArtifactForState(inputState, minterAddress, network);
6008
+ (0, token_profiles_js_1.requireTokenCapability)(resolvedArtifact.profile, "mint");
5960
6009
  (0, abi_js_1.dispatchTagFor)(resolvedArtifact.artifact, "set_public_mint_active");
5961
6010
  const minterTxid = (0, sale_common_js_1.requireHex32)(activeMinterUtxo.txidHex, "minter txid");
5962
6011
  const minterVout = parseVout(activeMinterUtxo.vout, "minter vout");
@@ -6180,6 +6229,10 @@ function createKcc20PsktBuilderEngine(options) {
6180
6229
  if (resolvedArtifacts.some((candidate) => candidate.version !== resolvedArtifacts[0].version)) {
6181
6230
  throw new Error("consolidation requires holder UTXOs from one artifact");
6182
6231
  }
6232
+ const profile = resolvedArtifacts[0].profile;
6233
+ if (holderUtxos.length > profile.maxTokenInputs) {
6234
+ throw new Error("consolidation exceeds the token profile input bound");
6235
+ }
6183
6236
  const artifact = resolvedArtifacts[0].artifact;
6184
6237
  for (const peerState of states.slice(1)) {
6185
6238
  assertKcc20MergeableStates(primaryState, peerState, owner);
@@ -6483,12 +6536,6 @@ function createKcc20PsktBuilderEngine(options) {
6483
6536
  if (inputState.isMintAuthority || inputState.amount <= 0n) {
6484
6537
  throw new Error("KCC20 transfer requires a holder UTXO");
6485
6538
  }
6486
- if (inputState.ownerScheme !== 0) {
6487
- throw new Error("KCC20 transfer requires a Schnorr P2PK holder UTXO");
6488
- }
6489
- if ((0, sale_common_js_1.bytesToHex)(inputState.ownerIdentifier) !== owner) {
6490
- throw new Error("KCC20 transfer requires wallet to own the active holder UTXO");
6491
- }
6492
6539
  if (transferAmount > inputState.amount) {
6493
6540
  throw new Error("tokenAmount exceeds active holder balance");
6494
6541
  }
@@ -6497,6 +6544,21 @@ function createKcc20PsktBuilderEngine(options) {
6497
6544
  const tokenAddress = requireKaspaAddress(activeHolderUtxo.address);
6498
6545
  const resolvedArtifact = await resolveKcc20ArtifactForState(inputState, tokenAddress, network);
6499
6546
  const artifact = resolvedArtifact.artifact;
6547
+ if (params.mode && params.mode !== "owner")
6548
+ throw new Error("borrowed receive requires the explicit borrow transaction builder");
6549
+ const authorization = (0, token_authorization_js_1.planTokenOwnerWitness)({
6550
+ profile: resolvedArtifact.profile,
6551
+ owner: (0, sale_common_js_1.bytesToHex)(inputState.ownerIdentifier),
6552
+ ownerScheme: inputState.ownerScheme,
6553
+ publicKey: request.owner?.publicKey ?? request.owner?.kcc20Owner,
6554
+ capabilities: options.walletSigningCapabilities ?? {
6555
+ schnorr: true,
6556
+ ecdsa: false,
6557
+ },
6558
+ role: "leader",
6559
+ });
6560
+ if (!resolvedArtifact.profile.ownerSchemes.includes(recipientOwnerScheme))
6561
+ throw new Error("recipient owner scheme is unsupported by the token profile");
6500
6562
  const recipientState = {
6501
6563
  ...inputState,
6502
6564
  owner: (0, sale_common_js_1.hexToBytes)(recipientOwner),
@@ -6528,8 +6590,11 @@ function createKcc20PsktBuilderEngine(options) {
6528
6590
  throw new Error(`active holder UTXO ${tokenTxid}:${tokenVout} not found`);
6529
6591
  }
6530
6592
  const rpcScript = tokenEntry.scriptPublicKey ??
6531
- tokenEntry.entry?.scriptPublicKey ?? tokenEntry.utxoEntry?.scriptPublicKey;
6532
- if (!rpcScript || kw.addressFromScriptPublicKey(rpcScript, network)?.toString() !== tokenAddress) {
6593
+ tokenEntry.entry?.scriptPublicKey ??
6594
+ tokenEntry.utxoEntry?.scriptPublicKey;
6595
+ if (!rpcScript ||
6596
+ kw.addressFromScriptPublicKey(rpcScript, network)?.toString() !==
6597
+ tokenAddress) {
6533
6598
  throw new Error("active holder RPC script does not match rebuilt covenant state");
6534
6599
  }
6535
6600
  if (activeHolderUtxo.amountSompi != null &&
@@ -6538,7 +6603,7 @@ function createKcc20PsktBuilderEngine(options) {
6538
6603
  }
6539
6604
  const spendCovenantId = params.activeHolderNativeCovenantId
6540
6605
  ? requireMatchingCovenantId(tokenEntry, covenantId, "active holder")
6541
- : covenantIdFromUtxoEntry(tokenEntry) ?? covenantId;
6606
+ : (covenantIdFromUtxoEntry(tokenEntry) ?? covenantId);
6542
6607
  let outputSompi = 0n;
6543
6608
  const recipientOutputIndex = 0;
6544
6609
  const outputs = [
@@ -6590,9 +6655,9 @@ function createKcc20PsktBuilderEngine(options) {
6590
6655
  outputs,
6591
6656
  subnetworkId: sale_common_js_1.SUBNETWORK_ID_NATIVE,
6592
6657
  gas: 0n,
6593
- payload: buildTransferPayload({
6658
+ payload: (0, transfer_payload_js_1.buildAuthenticatedKcc20TransferPayload)({
6594
6659
  covenantId: spendCovenantId,
6595
- fromOwner: owner,
6660
+ fromOwnerIdentifier: (0, sale_common_js_1.bytesToHex)(inputState.ownerIdentifier),
6596
6661
  recipientOwner,
6597
6662
  recipientOwnerScheme,
6598
6663
  tokenAmount: transferAmount,
@@ -6605,9 +6670,10 @@ function createKcc20PsktBuilderEngine(options) {
6605
6670
  inputIndex: 0,
6606
6671
  scriptHex: (0, sale_common_js_1.bytesToHex)(tokenScript),
6607
6672
  signType: 1,
6673
+ signatureAlgorithm: authorization.signatureAlgorithm,
6608
6674
  signatureScript: {
6609
6675
  mode: "ordered-args",
6610
- args: kcc20TransferOrderedArgs(artifact, changeState ? [recipientState, changeState] : [recipientState]),
6676
+ args: kcc20TransferOrderedArgs(artifact, changeState ? [recipientState, changeState] : [recipientState], authorization.argument),
6611
6677
  },
6612
6678
  },
6613
6679
  ];
@@ -6623,6 +6689,9 @@ function createKcc20PsktBuilderEngine(options) {
6623
6689
  scripts,
6624
6690
  submitTransactionSupported: true,
6625
6691
  metadata: {
6692
+ tokenProfileId: resolvedArtifact.profile.id,
6693
+ tokenProfileRegistryHash: options.tokenProfileRegistry?.sha256 ??
6694
+ token_profiles_generated_js_1.BUNDLED_TOKEN_PROFILE_DIGEST,
6626
6695
  builderKey: "kcc20.transfer",
6627
6696
  operation: "transfer-token",
6628
6697
  action: "transfer",
@@ -7617,34 +7686,6 @@ function createKcc20PsktBuilderEngine(options) {
7617
7686
  },
7618
7687
  }));
7619
7688
  }
7620
- function buildTransferPayload(fields) {
7621
- return new TextEncoder().encode(JSON.stringify({
7622
- tn12: {
7623
- v: 1,
7624
- tmpl: "KCC20",
7625
- op: "transfer",
7626
- args: [
7627
- { name: "covenantId", type: "byte[32]", value: fields.covenantId },
7628
- { name: "fromOwner", type: "byte[32]", value: fields.fromOwner },
7629
- {
7630
- name: "recipientOwner",
7631
- type: "byte[32]",
7632
- value: fields.recipientOwner,
7633
- },
7634
- {
7635
- name: "recipientOwnerScheme",
7636
- type: "u64",
7637
- value: String(fields.recipientOwnerScheme),
7638
- },
7639
- {
7640
- name: "tokenAmount",
7641
- type: "u64",
7642
- value: fields.tokenAmount.toString(),
7643
- },
7644
- ],
7645
- },
7646
- }));
7647
- }
7648
7689
  function tokenOutput(kw, artifact, state, sompi, covenantId, authorizingInput) {
7649
7690
  return new kw.TransactionOutput(sompi, kw.payToScriptHashScript((0, abi_js_1.buildKcc20ScriptForState)(artifact, state)), new kw.CovenantBinding(authorizingInput, new kw.Hash(covenantId)));
7650
7691
  }
@@ -8940,18 +8981,29 @@ function createKcc20PsktBuilderEngine(options) {
8940
8981
  values.push({ type: "signature" }, i64TemplateArg(active ? 1 : 0), i64TemplateArg(minterOutputIndex), dataTemplateArg((0, abi_js_1.dispatchTagFor)(artifact, "set_public_mint_active")));
8941
8982
  return values;
8942
8983
  }
8943
- function kcc20TransferOrderedArgs(artifact, nextStates) {
8984
+ function profileForArtifact(artifact) {
8985
+ const parts = templateParts(artifact);
8986
+ const hash = (0, sale_common_js_1.bytesToHex)((0, abi_js_1.templateHash)(parts.prefix, parts.suffix));
8987
+ const profile = tokenProfiles.profiles.find((p) => p.templateHash === hash);
8988
+ if (!profile)
8989
+ throw new Error("token artifact has no bundled profile");
8990
+ return profile;
8991
+ }
8992
+ function kcc20TransferOrderedArgs(artifact, nextStates, witness) {
8993
+ const profile = profileForArtifact(artifact);
8994
+ if (nextStates.length > profile.maxTokenOutputs)
8995
+ throw new Error("transfer exceeds profile output bound");
8944
8996
  const fields = (0, abi_js_1.encodeKcc20StateRecordArrays)(nextStates).map(dataTemplateArg);
8945
8997
  return [
8946
8998
  ...fields,
8947
- { type: "signature", prefixHex: "00" },
8948
- dataTemplateArg((0, abi_js_1.dispatchTagFor)(artifact, "transfer")),
8999
+ witness ?? { type: "signature", prefixHex: "00" },
9000
+ dataTemplateArg((0, abi_js_1.dispatchTagFor)(artifact, profileForArtifact(artifact).transferEntrypoint)),
8949
9001
  ];
8950
9002
  }
8951
9003
  function kcc20TransferDelegatorOrderedArgs(artifact) {
8952
9004
  return [
8953
9005
  { type: "signature" },
8954
- dataTemplateArg((0, abi_js_1.dispatchTagFor)(artifact, "transfer_delegator")),
9006
+ dataTemplateArg((0, abi_js_1.dispatchTagFor)(artifact, profileForArtifact(artifact).delegatorEntrypoint)),
8955
9007
  ];
8956
9008
  }
8957
9009
  function kcc20BurnOrderedArgs(artifact, nextStates, burnAmount) {