metered-protocol 1.0.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 (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/contracts/metered.ag +135 -0
  4. package/contracts/metered_ag.tests.json +1226 -0
  5. package/contracts/metered_session.sil +237 -0
  6. package/contracts/metered_session.tests.json +1113 -0
  7. package/dist/contracts/metered.ag +135 -0
  8. package/dist/contracts/metered_ag.tests.json +1226 -0
  9. package/dist/contracts/metered_session.sil +237 -0
  10. package/dist/contracts/metered_session.tests.json +1113 -0
  11. package/dist/src/bias.d.ts +48 -0
  12. package/dist/src/bias.d.ts.map +1 -0
  13. package/dist/src/bias.js +43 -0
  14. package/dist/src/bias.js.map +1 -0
  15. package/dist/src/checkpoint.d.ts +57 -0
  16. package/dist/src/checkpoint.d.ts.map +1 -0
  17. package/dist/src/checkpoint.js +84 -0
  18. package/dist/src/checkpoint.js.map +1 -0
  19. package/dist/src/deadline.d.ts +71 -0
  20. package/dist/src/deadline.d.ts.map +1 -0
  21. package/dist/src/deadline.js +77 -0
  22. package/dist/src/deadline.js.map +1 -0
  23. package/dist/src/encoding.d.ts +72 -0
  24. package/dist/src/encoding.d.ts.map +1 -0
  25. package/dist/src/encoding.js +187 -0
  26. package/dist/src/encoding.js.map +1 -0
  27. package/dist/src/history.d.ts +33 -0
  28. package/dist/src/history.d.ts.map +1 -0
  29. package/dist/src/history.js +38 -0
  30. package/dist/src/history.js.map +1 -0
  31. package/dist/src/http/buyer.d.ts +57 -0
  32. package/dist/src/http/buyer.d.ts.map +1 -0
  33. package/dist/src/http/buyer.js +151 -0
  34. package/dist/src/http/buyer.js.map +1 -0
  35. package/dist/src/http/client.d.ts +55 -0
  36. package/dist/src/http/client.d.ts.map +1 -0
  37. package/dist/src/http/client.js +83 -0
  38. package/dist/src/http/client.js.map +1 -0
  39. package/dist/src/http/harness.d.ts +18 -0
  40. package/dist/src/http/harness.d.ts.map +1 -0
  41. package/dist/src/http/harness.js +16 -0
  42. package/dist/src/http/harness.js.map +1 -0
  43. package/dist/src/http/protocol.d.ts +84 -0
  44. package/dist/src/http/protocol.d.ts.map +1 -0
  45. package/dist/src/http/protocol.js +22 -0
  46. package/dist/src/http/protocol.js.map +1 -0
  47. package/dist/src/http/provider.d.ts +123 -0
  48. package/dist/src/http/provider.d.ts.map +1 -0
  49. package/dist/src/http/provider.js +197 -0
  50. package/dist/src/http/provider.js.map +1 -0
  51. package/dist/src/http/serve.d.ts +34 -0
  52. package/dist/src/http/serve.d.ts.map +1 -0
  53. package/dist/src/http/serve.js +171 -0
  54. package/dist/src/http/serve.js.map +1 -0
  55. package/dist/src/http/service.d.ts +86 -0
  56. package/dist/src/http/service.d.ts.map +1 -0
  57. package/dist/src/http/service.js +161 -0
  58. package/dist/src/http/service.js.map +1 -0
  59. package/dist/src/index.d.ts +68 -0
  60. package/dist/src/index.d.ts.map +1 -0
  61. package/dist/src/index.js +62 -0
  62. package/dist/src/index.js.map +1 -0
  63. package/dist/src/meter.d.ts +39 -0
  64. package/dist/src/meter.d.ts.map +1 -0
  65. package/dist/src/meter.js +100 -0
  66. package/dist/src/meter.js.map +1 -0
  67. package/dist/src/offer.d.ts +6 -0
  68. package/dist/src/offer.d.ts.map +1 -0
  69. package/dist/src/offer.js +92 -0
  70. package/dist/src/offer.js.map +1 -0
  71. package/dist/src/reconcile.d.ts +18 -0
  72. package/dist/src/reconcile.d.ts.map +1 -0
  73. package/dist/src/reconcile.js +101 -0
  74. package/dist/src/reconcile.js.map +1 -0
  75. package/dist/src/reservation.d.ts +51 -0
  76. package/dist/src/reservation.d.ts.map +1 -0
  77. package/dist/src/reservation.js +124 -0
  78. package/dist/src/reservation.js.map +1 -0
  79. package/dist/src/session.d.ts +40 -0
  80. package/dist/src/session.d.ts.map +1 -0
  81. package/dist/src/session.js +92 -0
  82. package/dist/src/session.js.map +1 -0
  83. package/dist/src/signer.d.ts +31 -0
  84. package/dist/src/signer.d.ts.map +1 -0
  85. package/dist/src/signer.js +57 -0
  86. package/dist/src/signer.js.map +1 -0
  87. package/dist/src/store.d.ts +30 -0
  88. package/dist/src/store.d.ts.map +1 -0
  89. package/dist/src/store.js +120 -0
  90. package/dist/src/store.js.map +1 -0
  91. package/dist/src/types.d.ts +80 -0
  92. package/dist/src/types.d.ts.map +1 -0
  93. package/dist/src/types.js +9 -0
  94. package/dist/src/types.js.map +1 -0
  95. package/dist/tools/anchor-cli.d.ts +2 -0
  96. package/dist/tools/anchor-cli.d.ts.map +1 -0
  97. package/dist/tools/anchor-cli.js +101 -0
  98. package/dist/tools/anchor-cli.js.map +1 -0
  99. package/dist/tools/anchor.d.ts +68 -0
  100. package/dist/tools/anchor.d.ts.map +1 -0
  101. package/dist/tools/anchor.js +136 -0
  102. package/dist/tools/anchor.js.map +1 -0
  103. package/dist/tools/chain.d.ts +18 -0
  104. package/dist/tools/chain.d.ts.map +1 -0
  105. package/dist/tools/chain.js +18 -0
  106. package/dist/tools/chain.js.map +1 -0
  107. package/dist/tools/conformance.d.ts +2 -0
  108. package/dist/tools/conformance.d.ts.map +1 -0
  109. package/dist/tools/conformance.js +220 -0
  110. package/dist/tools/conformance.js.map +1 -0
  111. package/dist/tools/contracts.d.ts +2 -0
  112. package/dist/tools/contracts.d.ts.map +1 -0
  113. package/dist/tools/contracts.js +68 -0
  114. package/dist/tools/contracts.js.map +1 -0
  115. package/dist/tools/covenant-binding.d.ts +40 -0
  116. package/dist/tools/covenant-binding.d.ts.map +1 -0
  117. package/dist/tools/covenant-binding.js +60 -0
  118. package/dist/tools/covenant-binding.js.map +1 -0
  119. package/dist/tools/covenant-profile.d.ts +41 -0
  120. package/dist/tools/covenant-profile.d.ts.map +1 -0
  121. package/dist/tools/covenant-profile.js +74 -0
  122. package/dist/tools/covenant-profile.js.map +1 -0
  123. package/dist/tools/covenant.d.ts +30 -0
  124. package/dist/tools/covenant.d.ts.map +1 -0
  125. package/dist/tools/covenant.js +54 -0
  126. package/dist/tools/covenant.js.map +1 -0
  127. package/dist/tools/demo-report.d.ts +24 -0
  128. package/dist/tools/demo-report.d.ts.map +1 -0
  129. package/dist/tools/demo-report.js +40 -0
  130. package/dist/tools/demo-report.js.map +1 -0
  131. package/dist/tools/demo.d.ts +2 -0
  132. package/dist/tools/demo.d.ts.map +1 -0
  133. package/dist/tools/demo.js +204 -0
  134. package/dist/tools/demo.js.map +1 -0
  135. package/dist/tools/dust-map.d.ts +2 -0
  136. package/dist/tools/dust-map.d.ts.map +1 -0
  137. package/dist/tools/dust-map.js +63 -0
  138. package/dist/tools/dust-map.js.map +1 -0
  139. package/dist/tools/expire-cases.d.ts +4 -0
  140. package/dist/tools/expire-cases.d.ts.map +1 -0
  141. package/dist/tools/expire-cases.js +211 -0
  142. package/dist/tools/expire-cases.js.map +1 -0
  143. package/dist/tools/fee-check.d.ts +2 -0
  144. package/dist/tools/fee-check.d.ts.map +1 -0
  145. package/dist/tools/fee-check.js +127 -0
  146. package/dist/tools/fee-check.js.map +1 -0
  147. package/dist/tools/fixtures.d.ts +39 -0
  148. package/dist/tools/fixtures.d.ts.map +1 -0
  149. package/dist/tools/fixtures.js +31 -0
  150. package/dist/tools/fixtures.js.map +1 -0
  151. package/dist/tools/gen-contract-tests.d.ts +2 -0
  152. package/dist/tools/gen-contract-tests.d.ts.map +1 -0
  153. package/dist/tools/gen-contract-tests.js +170 -0
  154. package/dist/tools/gen-contract-tests.js.map +1 -0
  155. package/dist/tools/kaspa.d.ts +13 -0
  156. package/dist/tools/kaspa.d.ts.map +1 -0
  157. package/dist/tools/kaspa.js +76 -0
  158. package/dist/tools/kaspa.js.map +1 -0
  159. package/dist/tools/live-deadline.d.ts +2 -0
  160. package/dist/tools/live-deadline.d.ts.map +1 -0
  161. package/dist/tools/live-deadline.js +122 -0
  162. package/dist/tools/live-deadline.js.map +1 -0
  163. package/dist/tools/live-expire.d.ts +2 -0
  164. package/dist/tools/live-expire.d.ts.map +1 -0
  165. package/dist/tools/live-expire.js +127 -0
  166. package/dist/tools/live-expire.js.map +1 -0
  167. package/dist/tools/live-settle.d.ts +2 -0
  168. package/dist/tools/live-settle.d.ts.map +1 -0
  169. package/dist/tools/live-settle.js +226 -0
  170. package/dist/tools/live-settle.js.map +1 -0
  171. package/dist/tools/live-steps.d.ts +63 -0
  172. package/dist/tools/live-steps.d.ts.map +1 -0
  173. package/dist/tools/live-steps.js +155 -0
  174. package/dist/tools/live-steps.js.map +1 -0
  175. package/dist/tools/model.d.ts +32 -0
  176. package/dist/tools/model.d.ts.map +1 -0
  177. package/dist/tools/model.js +99 -0
  178. package/dist/tools/model.js.map +1 -0
  179. package/dist/tools/send.d.ts +2 -0
  180. package/dist/tools/send.d.ts.map +1 -0
  181. package/dist/tools/send.js +41 -0
  182. package/dist/tools/send.js.map +1 -0
  183. package/dist/tools/session-chain.d.ts +69 -0
  184. package/dist/tools/session-chain.d.ts.map +1 -0
  185. package/dist/tools/session-chain.js +113 -0
  186. package/dist/tools/session-chain.js.map +1 -0
  187. package/dist/tools/sighash.d.ts +9 -0
  188. package/dist/tools/sighash.d.ts.map +1 -0
  189. package/dist/tools/sighash.js +68 -0
  190. package/dist/tools/sighash.js.map +1 -0
  191. package/dist/tools/sigscript-check.d.ts +2 -0
  192. package/dist/tools/sigscript-check.d.ts.map +1 -0
  193. package/dist/tools/sigscript-check.js +113 -0
  194. package/dist/tools/sigscript-check.js.map +1 -0
  195. package/dist/tools/sigscript.d.ts +61 -0
  196. package/dist/tools/sigscript.d.ts.map +1 -0
  197. package/dist/tools/sigscript.js +70 -0
  198. package/dist/tools/sigscript.js.map +1 -0
  199. package/dist/tools/state-layout.d.ts +2 -0
  200. package/dist/tools/state-layout.d.ts.map +1 -0
  201. package/dist/tools/state-layout.js +57 -0
  202. package/dist/tools/state-layout.js.map +1 -0
  203. package/package.json +59 -0
  204. package/spec/CONFORMANCE.md +80 -0
  205. package/spec/SPEC.md +821 -0
  206. package/spec/conformance-vectors.json +677 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The three chain operations a metered session needs, as functions rather than as a script.
3
+ *
4
+ * FUND, SETTLE, CLOSE. Until now this sequence existed only inside `tools/demo.ts`, wound through
5
+ * its console output -- which meant that anything else wanting to settle a session had to copy it.
6
+ * The second program to want that was the first real product built on this protocol, and copying
7
+ * would have produced two versions of the one sequence that moves money.
8
+ *
9
+ * SPEC.md 7. `settle` posts a doubly-signed claim and pays no one; the response window then
10
+ * restarts. `expire` pays out after the window: the claim to the provider, the remainder to the
11
+ * buyer, everything to the buyer if no claim was ever posted. The two-phase shape is not an
12
+ * implementation detail -- it is what makes the claim superseding a later one work as a guard
13
+ * rather than as a branch.
14
+ *
15
+ * WHAT THIS STILL NEEDS: `silverc`, because the redeem script embeds the session's own identity as
16
+ * constructor constants and so must be compiled per session. That is the official released
17
+ * compiler and an ordinary dependency. It no longer needs the patched cli-debugger -- see
18
+ * tools/sigscript.ts, which was the difference between one machine being able to settle and
19
+ * anybody being able to.
20
+ */
21
+ import { compileWithState, covenantAddress } from './covenant.js';
22
+ import { awaitUtxo, withState, buildExpire, awaitWindow, closeOutputs, x } from './live-steps.js';
23
+ import { signatureScript, settleArgs } from './sigscript.js';
24
+ /** Fees are compiled into the covenant's allowance, so they are constants rather than estimates. */
25
+ export const SETTLE_FEE = 360000n;
26
+ export const CLOSE_FEE = 400000n;
27
+ export const FUND_FEE = 250000n;
28
+ /**
29
+ * Compile this session's covenant and derive the address that holds its funds.
30
+ *
31
+ * The constructor constants come from the Offer the provider actually issued, so the address is
32
+ * derived from the agreement rather than the agreement being fitted to an address. A covenant
33
+ * compiled for a different session has a different address and cannot be spent by this one.
34
+ */
35
+ export async function openCovenant(dir, offer, window, network) {
36
+ const built = compileWithState(dir, {
37
+ parties: offer.partiesCommitment, sessionId: offer.sessionId, window, seq: -1, sompi: 0,
38
+ });
39
+ const address = await covenantAddress(built.hex, network);
40
+ return { ...built, address, window };
41
+ }
42
+ /** Pay into the covenant from an ordinary wallet, and wait for the UTXO to appear. */
43
+ export async function fundCovenant(rpc, sdk, opened, funderSk, amount, network) {
44
+ const priv = new sdk.PrivateKey(funderSk);
45
+ const from = priv.toKeypair().toAddress(new sdk.NetworkId(network)).toString();
46
+ const { entries } = await rpc.getUtxosByAddresses([from]);
47
+ if (entries.length === 0)
48
+ throw new Error(`nothing to spend at ${from}`);
49
+ const src = entries.reduce((a, b) => (b.amount > a.amount ? b : a));
50
+ if (src.amount < amount + FUND_FEE)
51
+ throw new Error(`largest UTXO at ${from} cannot cover ${amount}`);
52
+ const fund = sdk.createTransaction([src], [{ address: opened.address, amount }, { address: from, amount: src.amount - amount - FUND_FEE }], 0n, undefined, 0);
53
+ fund.version = 1;
54
+ fund.gas = 0n;
55
+ for (const i of fund.inputs) {
56
+ i.sigOpCount = 0;
57
+ i.computeBudget = 10;
58
+ }
59
+ fund.finalize();
60
+ await rpc.submitTransaction({ transaction: sdk.signTransaction(fund, [priv], true), allowOrphan: false });
61
+ const utxo = await awaitUtxo(rpc, opened.address, amount);
62
+ if (!utxo)
63
+ throw new Error('the covenant UTXO never appeared');
64
+ return utxo;
65
+ }
66
+ /**
67
+ * Post the doubly-signed final State to the covenant.
68
+ *
69
+ * `settle` PAYS NO ONE. The single output hands the balance straight back to the same covenant,
70
+ * now carrying `(seq, cumulativeSompi)` as its state, and the response window restarts. A later
71
+ * State with a strictly higher seq supersedes this one by the same route.
72
+ */
73
+ export async function settleClaim(rpc, sdk, opened, utxo, state, parties, network) {
74
+ const tag = opened.entries.settle?.dispatch_tag;
75
+ if (!tag)
76
+ throw new Error('the compiled covenant has no `settle` entry');
77
+ const redeem = withState(opened.hex, state.seq, state.cumulativeSompi);
78
+ const address = await covenantAddress(redeem, network);
79
+ const amount = utxo.amount - SETTLE_FEE;
80
+ const spend = sdk.createTransaction([utxo], [{ address, amount }], 0n, undefined, 0);
81
+ spend.version = 1;
82
+ spend.gas = 0n;
83
+ spend.inputs[0].sigOpCount = 0;
84
+ // Sized to the COSTLIEST entry, not this one: `expire` does two signature checks. Finding E.
85
+ spend.inputs[0].computeBudget = 21;
86
+ spend.inputs[0].signatureScript = signatureScript(sdk, settleArgs(state, parties.buyerPubkey, parties.providerPubkey, parties.buyerSig, parties.providerSig), tag, opened.hex);
87
+ spend.finalize();
88
+ const txid = (await rpc.submitTransaction({ transaction: spend, allowOrphan: false })).transactionId;
89
+ const posted = await awaitUtxo(rpc, address, amount);
90
+ if (!posted)
91
+ throw new Error('the claim never posted');
92
+ return { txid, posted, redeem, address };
93
+ }
94
+ /**
95
+ * Wait out the response window and pay everyone.
96
+ *
97
+ * The output SHAPE is computed rather than assumed. The covenant accepts exactly three and refuses
98
+ * everything else, and guessing gets "script ran, but verification failed" -- which says nothing
99
+ * about which rule was broken. Below the KIP-9 floor a payout cannot be its own output at all, so
100
+ * it folds into the other party's.
101
+ */
102
+ export async function closeCovenant(rpc, sdk, opened, claim, who, owedSompi) {
103
+ await awaitWindow(rpc, opened.window);
104
+ const outputs = closeOutputs(claim.posted.amount, BigInt(owedSompi), CLOSE_FEE, who.buyerAddress, who.providerAddress);
105
+ const close = buildExpire(sdk, {
106
+ buyerPk: who.buyerPubkey, providerPk: who.providerPubkey, signerSk: who.signerSk,
107
+ redeem: claim.redeem, tag: opened.entries.expire?.dispatch_tag ?? '',
108
+ }, claim.posted, outputs, opened.window);
109
+ const txid = (await rpc.submitTransaction({ transaction: close, allowOrphan: false })).transactionId;
110
+ return { txid, outputs };
111
+ }
112
+ export { x };
113
+ //# sourceMappingURL=session-chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-chain.js","sourceRoot":"","sources":["../../tools/session-chain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare const DEBUGGER: string;
2
+ /**
3
+ * Run one test case and return the sighash the VM computed for the active input. The case is
4
+ * expected to FAIL at the signature check -- that is fine and expected, we only want the hash.
5
+ */
6
+ export declare function sighashFor(contractPath: string, testCase: unknown): string;
7
+ /** BIP340 over the sighash, plus the type byte -- the 65 bytes a Kaspa `sig` parameter wants. */
8
+ export declare function signSighash(sighashHex: string, privateKeyHex: string): string;
9
+ //# sourceMappingURL=sighash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sighash.d.ts","sourceRoot":"","sources":["../../tools/sighash.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,QAAQ,QAE4G,CAAC;AAElI;;;GAGG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAyB1E;AAED,iGAAiG;AACjG,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAM7E"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The signing harness for covenant entries that use `checkSig`.
3
+ *
4
+ * `checkMsgSig` verifies a signature over supplied data, so `settle` can be signed offline -- the
5
+ * message is just the settlement digest. `checkSig` verifies a signature over the SPENDING
6
+ * TRANSACTION, and the sighash depends on the whole transaction the simulator builds: outpoints,
7
+ * amounts, script pubkeys, sequences, sigop counts. There is no way to compute it from outside
8
+ * without reimplementing Kaspa's consensus hashing and matching the simulator byte for byte.
9
+ *
10
+ * So we ask it. `SILVERSCRIPT_PRINT_SIGHASH=1` makes the debugger print the sighash it computed,
11
+ * we sign that, and write the signature back into the test case. Two passes, no reimplementation.
12
+ *
13
+ * WHY THIS IS NOT CIRCULAR. Kaspa's sighash covers the UTXO's script pubkey, not the spending
14
+ * input's signature script -- the signature is not an input to the hash that the signature signs.
15
+ * So a placeholder signature in pass one yields exactly the sighash that the real signature in
16
+ * pass two must cover. If that ever stops being true, every expire test breaks loudly rather than
17
+ * silently, because the VM verifies for real.
18
+ *
19
+ * THE DEBUGGER IS PATCHED LOCALLY to print it, in the v1.0.0 worktree under ~/.metered/. That
20
+ * patch is four lines behind an environment variable and is NOT upstream; a fresh checkout will
21
+ * not have it. `npm run contracts:gen` says so if the sighash never appears.
22
+ */
23
+ import { spawnSync } from 'node:child_process';
24
+ import { writeFileSync, mkdtempSync } from 'node:fs';
25
+ import { tmpdir } from 'node:os';
26
+ import { join } from 'node:path';
27
+ import { schnorr } from '@noble/curves/secp256k1';
28
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
29
+ /** Kaspa's SIG_HASH_ALL. A `sig` is 64 schnorr bytes plus this one type byte -- 65 in total. */
30
+ const SIG_HASH_ALL = 0x01;
31
+ export const DEBUGGER = process.env.SILVERSCRIPT_DEBUGGER ??
32
+ join(process.env.USERPROFILE ?? process.env.HOME ?? '', '.metered', 'silverscript-v1', 'target', 'release', 'cli-debugger.exe');
33
+ /**
34
+ * Run one test case and return the sighash the VM computed for the active input. The case is
35
+ * expected to FAIL at the signature check -- that is fine and expected, we only want the hash.
36
+ */
37
+ export function sighashFor(contractPath, testCase) {
38
+ const dir = mkdtempSync(join(tmpdir(), 'metered-sighash-'));
39
+ const file = join(dir, 'one.tests.json');
40
+ const name = testCase.name;
41
+ writeFileSync(file, JSON.stringify({ tests: [testCase] }));
42
+ // `--run`, not `--run-all`: run-all re-spawns itself per case and swallows the child's stderr
43
+ // when the case passes, which is exactly when we still need the hash.
44
+ const run = spawnSync(DEBUGGER, [contractPath, '--run', '--test-file', file, '--test-name', name], {
45
+ encoding: 'utf8',
46
+ env: { ...process.env, SILVERSCRIPT_PRINT_SIGHASH: '1' },
47
+ });
48
+ const out = `${run.stdout ?? ''}${run.stderr ?? ''}`;
49
+ const found = out.match(/SIGHASH ([0-9a-f]{64})/);
50
+ if (!found) {
51
+ throw new Error('the debugger printed no sighash.\n\n' +
52
+ ` tried: ${DEBUGGER}\n\n` +
53
+ 'That binary must be built from the v1.0.0 worktree WITH the local sighash patch\n' +
54
+ '(four lines in debugger/cli/src/main.rs, behind SILVERSCRIPT_PRINT_SIGHASH).\n' +
55
+ 'A stock silverscript checkout will not print it. See tools/sighash.ts.\n\n' +
56
+ `${out.split('\n').slice(-6).join('\n')}`);
57
+ }
58
+ return found[1];
59
+ }
60
+ /** BIP340 over the sighash, plus the type byte -- the 65 bytes a Kaspa `sig` parameter wants. */
61
+ export function signSighash(sighashHex, privateKeyHex) {
62
+ const raw = schnorr.sign(hexToBytes(sighashHex), hexToBytes(privateKeyHex));
63
+ const withType = new Uint8Array(65);
64
+ withType.set(raw, 0);
65
+ withType[64] = SIG_HASH_ALL;
66
+ return bytesToHex(withType);
67
+ }
68
+ //# sourceMappingURL=sighash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sighash.js","sourceRoot":"","sources":["../../tools/sighash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE7D,gGAAgG;AAChG,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,MAAM,CAAC,MAAM,QAAQ,GACnB,OAAO,CAAC,GAAG,CAAC,qBAAqB;IACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAElI;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,YAAoB,EAAE,QAAiB;IAChE,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IACzC,MAAM,IAAI,GAAI,QAA6B,CAAC,IAAI,CAAC;IACjD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3D,8FAA8F;IAC9F,sEAAsE;IACtE,MAAM,GAAG,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE;QACjG,QAAQ,EAAE,MAAM;QAChB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,0BAA0B,EAAE,GAAG,EAAE;KACzD,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,sCAAsC;YACpC,YAAY,QAAQ,MAAM;YAC1B,mFAAmF;YACnF,gFAAgF;YAChF,4EAA4E;YAC5E,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5C,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,CAAW,CAAC;AAC5B,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,WAAW,CAAC,UAAkB,EAAE,aAAqB;IACnE,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC;IAC5B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sigscript-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sigscript-check.d.ts","sourceRoot":"","sources":["../../tools/sigscript-check.ts"],"names":[],"mappings":""}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * `npx tsx tools/sigscript-check.ts` -- prove the signature script can be built without the simulator.
3
+ *
4
+ * tools/sigscript.ts claims it knows how a SilverScript signature script is laid out. This is
5
+ * where that claim is tested rather than believed: every case below is built BOTH ways -- once by
6
+ * the patched cli-debugger that every live spend has used until now, and once in TypeScript from
7
+ * nothing but the compiled artifact -- and the two byte strings must be identical.
8
+ *
9
+ * If they are, settlement stops requiring a patched debugger and starts requiring only the Kaspa
10
+ * SDK, which is the difference between a protocol one machine can settle and a protocol anyone
11
+ * can. If they are not, the description in sigscript.ts is wrong and belongs nowhere near money.
12
+ */
13
+ import { mkdtempSync } from 'node:fs';
14
+ import { tmpdir } from 'node:os';
15
+ import { join } from 'node:path';
16
+ import { partiesCommitment, publicKeyHex, signState } from '../src/encoding.js';
17
+ import { compileWithState } from './covenant.js';
18
+ import { preflightSigscript, withState, x } from './live-steps.js';
19
+ import { signatureScript, actionScript, encodeNumber, settleArgs } from './sigscript.js';
20
+ import { loadSdk } from './kaspa.js';
21
+ const dir = mkdtempSync(join(tmpdir(), 'metered-sigscript-'));
22
+ const BUYER_SK = '11'.repeat(32);
23
+ const PROVIDER_SK = '22'.repeat(32);
24
+ const SESSION = 'a1'.repeat(16);
25
+ const PARTIES = partiesCommitment(publicKeyHex(BUYER_SK), publicKeyHex(PROVIDER_SK));
26
+ const WINDOW = 2;
27
+ /** Deliberately spread across the number encoding's awkward places, not three happy cases. */
28
+ const CASES = [
29
+ { name: 'seq 0, the first claim', seq: 0, units: 550, sompi: 1996500, prevState: null },
30
+ { name: 'a mid-session claim', seq: 3, units: 2199, sompi: 7982370, prevState: 'b2'.repeat(32) },
31
+ { name: 'values that fill the sign bit', seq: 1, units: 128, sompi: 32768, prevState: 'cd'.repeat(32) },
32
+ { name: 'a large sompi total', seq: 7, units: 1000000, sompi: 47600000, prevState: 'ef'.repeat(32) },
33
+ ];
34
+ function argsFor(c) {
35
+ const state = {
36
+ v: 1, sessionId: SESSION, seq: c.seq, cumulativeUnits: c.units,
37
+ cumulativeSompi: c.sompi, prevState: c.prevState,
38
+ };
39
+ return settleArgs(state, publicKeyHex(BUYER_SK), publicKeyHex(PROVIDER_SK), signState(state, BUYER_SK), signState(state, PROVIDER_SK));
40
+ }
41
+ function numberVectors() {
42
+ // The encoding these scripts hang on, checked against Kaspa script's own rules before anything
43
+ // larger is compared. Zero is the empty push; 0x80 needs a byte added so the sign bit is free.
44
+ const vectors = [
45
+ [0, ''], [1, '01'], [127, '7f'], [128, '8000'], [255, 'ff00'], [256, '0001'],
46
+ [-1, '81'], [-127, 'ff'], [-128, '8080'], [32768, '008000'], [1996500, 'd4761e'],
47
+ ];
48
+ for (const [n, want] of vectors) {
49
+ const got = Buffer.from(encodeNumber(n)).toString('hex');
50
+ if (got !== want)
51
+ throw new Error(`encodeNumber(${n}) = ${got}, expected ${want}`);
52
+ }
53
+ console.log(` number encoding ${vectors.length} vectors agree`);
54
+ }
55
+ async function main() {
56
+ numberVectors();
57
+ const sdk = await loadSdk();
58
+ let checked = 0;
59
+ for (const c of CASES) {
60
+ const ctor = [x(PARTIES), x(SESSION), WINDOW, -1, 0];
61
+ const built = compileWithState(dir, {
62
+ parties: PARTIES, sessionId: SESSION, window: WINDOW, seq: -1, sompi: 0,
63
+ });
64
+ const tag = built.entries.settle?.dispatch_tag;
65
+ if (!tag)
66
+ throw new Error('the compiled covenant has no `settle` entry');
67
+ const args = argsFor(c);
68
+ const outRedeem = withState(built.hex, c.seq, c.sompi);
69
+ // THE REFERENCE: the patched debugger, which is what every live spend has used.
70
+ const fromDebugger = preflightSigscript({
71
+ name: `sigscript ${c.name}`,
72
+ function: 'settle',
73
+ constructor_args: ctor,
74
+ args,
75
+ expect: 'pass',
76
+ tx: {
77
+ active_input_index: 0,
78
+ inputs: [{ utxo_value: 50_000_000, constructor_args: ctor }],
79
+ outputs: [{
80
+ value: 49_640_000, constructor_args: ctor,
81
+ state: { pendingSeq: c.seq, pendingSompi: c.sompi },
82
+ }],
83
+ },
84
+ }, dir);
85
+ // THE CANDIDATE: built here, from the compiled artifact and nothing else. Compared as the
86
+ // WHOLE script -- action half plus redeem -- because that is what gets broadcast; comparing
87
+ // only the half this file constructs would leave the join untested.
88
+ const redeem = new sdk.ScriptBuilder();
89
+ redeem.addData(built.hex);
90
+ const reference = fromDebugger + redeem.toString();
91
+ const mine = signatureScript(sdk, args, tag, built.hex);
92
+ if (actionScript(sdk, args, tag) !== fromDebugger) {
93
+ console.log(`
94
+ ACTION HALF MISMATCH on "${c.name}"`);
95
+ process.exit(1);
96
+ }
97
+ if (mine !== reference) {
98
+ console.log(`\n MISMATCH on "${c.name}"`);
99
+ console.log(` debugger ${reference.slice(0, 120)}... (${reference.length / 2} bytes)`);
100
+ console.log(` built ${mine.slice(0, 120)}... (${mine.length / 2} bytes)`);
101
+ process.exit(1);
102
+ }
103
+ console.log(` ${c.name.padEnd(30)} ${mine.length / 2} bytes, identical`);
104
+ checked += 1;
105
+ void outRedeem;
106
+ }
107
+ console.log(`\n ${checked} signature scripts built without the simulator, byte for byte.\n`);
108
+ }
109
+ main().catch((err) => {
110
+ console.error(`\n ${err instanceof Error ? err.message : String(err)}\n`);
111
+ process.exit(1);
112
+ });
113
+ //# sourceMappingURL=sigscript-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sigscript-check.js","sourceRoot":"","sources":["../../tools/sigscript-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Build a covenant signature script WITHOUT the simulator.
3
+ *
4
+ * THIS FILE EXISTS BECAUSE SETTLEMENT WAS UNDEPLOYABLE. Every live spend this project has ever
5
+ * made obtained its signature script by running the SilverScript cli-debugger and reading the
6
+ * bytes it printed -- behind an environment variable added by a LOCAL, un-upstreamed patch. That
7
+ * worked, and it meant a metered session could be settled on exactly one machine in the world.
8
+ * A protocol whose enforcement half needs a patched debugger is not adoptable, however carefully
9
+ * the rest of it is specified.
10
+ *
11
+ * A SilverScript signature script is not mysterious, which is what makes this fixable. It is:
12
+ *
13
+ * <arg_0> <arg_1> ... <arg_n> <dispatch_tag> <redeem_script>
14
+ *
15
+ * -- the entry's arguments pushed in DECLARATION order, then the tag that selects the entry, then
16
+ * the redeem script itself. The debugger's `combine_action_and_redeem` does the same thing; it was
17
+ * simply the only thing doing it.
18
+ *
19
+ * The order was established by comparison, not by reading: the first attempt pushed the arguments
20
+ * reversed, on the reasoning that the first one should end up on top of the stack. It produced a
21
+ * script of exactly the right length and entirely the wrong bytes, which is a good argument for
22
+ * checking against the reference rather than against one's own reasoning.
23
+ *
24
+ * Nothing here is trusted on the strength of that description. tools/sigscript-check.ts builds
25
+ * every case both ways and compares the bytes, and the two must agree exactly.
26
+ */
27
+ import type { Any } from './live-steps.js';
28
+ /** A covenant argument: a hex blob (`0x...`) or a whole number. */
29
+ export type Arg = string | number;
30
+ export declare class UnencodableArg extends Error {
31
+ }
32
+ /**
33
+ * SilverScript numbers are minimally-encoded, little-endian, sign-and-magnitude -- Kaspa script's
34
+ * own number encoding, not two's complement. Zero is the EMPTY push, which is why it cannot be
35
+ * written as a single 0x00 byte.
36
+ */
37
+ export declare function encodeNumber(n: number): Uint8Array;
38
+ /**
39
+ * The ACTION half: arguments then dispatch tag, with no redeem script appended.
40
+ *
41
+ * Kept separate from the redeem half because the caller appends that itself -- the redeem bytes
42
+ * must physically be present in the input's own signature script, since `validateOutputState`
43
+ * rebuilds the continuation out of them.
44
+ */
45
+ export declare function actionScript(sdk: Any, args: Arg[], dispatchTag: string): string;
46
+ /**
47
+ * The arguments the covenant's `settle` entry takes, in the order it declares them.
48
+ *
49
+ * ONE DEFINITION, because the order is load-bearing and there were three copies of it -- the test
50
+ * generator, the demo and the cross-check each built this list by hand. Three lists that must
51
+ * agree and are maintained separately are three chances to find out on chain.
52
+ */
53
+ export declare function settleArgs(state: {
54
+ seq: number;
55
+ cumulativeUnits: number;
56
+ cumulativeSompi: number;
57
+ prevState: string | null;
58
+ }, buyerPubkey: string, providerPubkey: string, buyerSig: string, providerSig: string): Arg[];
59
+ /** The whole signature script: the action half, then the redeem script it runs against. */
60
+ export declare function signatureScript(sdk: Any, args: Arg[], dispatchTag: string, redeemHex: string): string;
61
+ //# sourceMappingURL=sigscript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sigscript.d.ts","sourceRoot":"","sources":["../../tools/sigscript.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,mEAAmE;AACnE,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC;AAElC,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAE5C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CAiBlD;AAWD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAK/E;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAClG,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GACjF,GAAG,EAAE,CAMP;AAED,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAIrG"}
@@ -0,0 +1,70 @@
1
+ export class UnencodableArg extends Error {
2
+ }
3
+ /**
4
+ * SilverScript numbers are minimally-encoded, little-endian, sign-and-magnitude -- Kaspa script's
5
+ * own number encoding, not two's complement. Zero is the EMPTY push, which is why it cannot be
6
+ * written as a single 0x00 byte.
7
+ */
8
+ export function encodeNumber(n) {
9
+ if (!Number.isSafeInteger(n))
10
+ throw new UnencodableArg(`${n} is not a whole number`);
11
+ if (n === 0)
12
+ return new Uint8Array(0);
13
+ const negative = n < 0;
14
+ let value = Math.abs(n);
15
+ const out = [];
16
+ while (value > 0) {
17
+ out.push(value & 0xff);
18
+ value = Math.floor(value / 256);
19
+ }
20
+ // The top bit doubles as the sign, so a value that already fills it needs one more byte to
21
+ // carry the sign without changing the magnitude.
22
+ const top = out[out.length - 1];
23
+ if (top & 0x80)
24
+ out.push(negative ? 0x80 : 0x00);
25
+ else if (negative)
26
+ out[out.length - 1] = top | 0x80;
27
+ return Uint8Array.from(out);
28
+ }
29
+ const hexToBytes = (hex) => {
30
+ const clean = hex.startsWith('0x') ? hex.slice(2) : hex;
31
+ if (clean.length % 2 !== 0 || /[^0-9a-fA-F]/.test(clean))
32
+ throw new UnencodableArg(`not hex: ${hex}`);
33
+ return Uint8Array.from(clean.match(/../g)?.map((b) => parseInt(b, 16)) ?? []);
34
+ };
35
+ const asBytes = (arg) => (typeof arg === 'number' ? encodeNumber(arg) : hexToBytes(arg));
36
+ /**
37
+ * The ACTION half: arguments then dispatch tag, with no redeem script appended.
38
+ *
39
+ * Kept separate from the redeem half because the caller appends that itself -- the redeem bytes
40
+ * must physically be present in the input's own signature script, since `validateOutputState`
41
+ * rebuilds the continuation out of them.
42
+ */
43
+ export function actionScript(sdk, args, dispatchTag) {
44
+ const builder = new sdk.ScriptBuilder();
45
+ for (const arg of args)
46
+ builder.addData(asBytes(arg));
47
+ builder.addData(hexToBytes(dispatchTag));
48
+ return builder.toString();
49
+ }
50
+ /**
51
+ * The arguments the covenant's `settle` entry takes, in the order it declares them.
52
+ *
53
+ * ONE DEFINITION, because the order is load-bearing and there were three copies of it -- the test
54
+ * generator, the demo and the cross-check each built this list by hand. Three lists that must
55
+ * agree and are maintained separately are three chances to find out on chain.
56
+ */
57
+ export function settleArgs(state, buyerPubkey, providerPubkey, buyerSig, providerSig) {
58
+ return [
59
+ `0x${buyerPubkey}`, `0x${providerPubkey}`, `0x${buyerSig}`, `0x${providerSig}`,
60
+ state.seq, state.cumulativeUnits, state.cumulativeSompi,
61
+ `0x${state.prevState ?? '00'.repeat(32)}`,
62
+ ];
63
+ }
64
+ /** The whole signature script: the action half, then the redeem script it runs against. */
65
+ export function signatureScript(sdk, args, dispatchTag, redeemHex) {
66
+ const redeem = new sdk.ScriptBuilder();
67
+ redeem.addData(hexToBytes(redeemHex));
68
+ return actionScript(sdk, args, dispatchTag) + redeem.toString();
69
+ }
70
+ //# sourceMappingURL=sigscript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sigscript.js","sourceRoot":"","sources":["../../tools/sigscript.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-layout.d.ts","sourceRoot":"","sources":["../../tools/state-layout.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Where does contract state actually live in the bytecode?
3
+ *
4
+ * `settle` hands the funds back to the SAME covenant with `(pendingSeq, pendingSompi)` updated,
5
+ * so a real spend has to derive the OUTPUT address -- which means knowing exactly which bytes
6
+ * change and how they are encoded. The artifact reports a `state_span`, but a span is a claim.
7
+ * This compiles the contract twice with different state and diffs the result, which is the same
8
+ * measure-do-not-reason discipline every parameter in SPEC.md 0.1 came from.
9
+ */
10
+ import { execFileSync } from 'node:child_process';
11
+ import { writeFileSync, readFileSync, mkdtempSync } from 'node:fs';
12
+ import { tmpdir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ import { SILVERC, compileWithState } from './covenant.js';
15
+ import { profileFromArgv } from './covenant-profile.js';
16
+ import { withState } from './live-steps.js';
17
+ // `npm run state-layout -- --profile ag` measures the Argent port instead. Its span is larger
18
+ // because Argent has no per-instance immutable parameter: parties, session_id and window are
19
+ // state there, so a continuation re-emits all five fields rather than two.
20
+ const PROFILE = profileFromArgv();
21
+ const dir = mkdtempSync(join(tmpdir(), 'metered-layout-'));
22
+ function bytecodeFor(seq, sompi) {
23
+ const out = compileWithState(dir, { parties: '11'.repeat(32), sessionId: '22'.repeat(16), window: 10, seq, sompi }, PROFILE.contract);
24
+ return out;
25
+ }
26
+ const a = bytecodeFor(-1, 0);
27
+ const b = bytecodeFor(7, 123456);
28
+ console.log(`profile ${PROFILE.key} ${PROFILE.contract}`);
29
+ console.log(`silverc ${SILVERC}`);
30
+ console.log(`length ${a.hex.length / 2} vs ${b.hex.length / 2} bytes`);
31
+ console.log(`state_span offset ${a.span.offset}, len ${a.span.len}`);
32
+ console.log('\ndiffering bytes:');
33
+ for (let i = 0; i < Math.min(a.hex.length, b.hex.length); i += 2) {
34
+ const x = a.hex.slice(i, i + 2);
35
+ const y = b.hex.slice(i, i + 2);
36
+ if (x !== y)
37
+ console.log(` byte ${String(i / 2).padStart(4)} ${x} -> ${y}`);
38
+ }
39
+ console.log(`\nspan bytes A ${a.hex.slice(a.span.offset * 2, (a.span.offset + a.span.len) * 2)}`);
40
+ console.log(`span bytes B ${b.hex.slice(b.span.offset * 2, (b.span.offset + b.span.len) * 2)}`);
41
+ console.log(`\nhead A ${a.hex.slice(0, 48)}`);
42
+ console.log(`head B ${b.hex.slice(0, 48)}`);
43
+ // THE SPAN IS A CLAIM THE COMPILER MAKES. This is the check that it is true: splice B's state
44
+ // into A by hand and demand the result equal a real compile of B, byte for byte. If the layout
45
+ // were anything but "the mutable pair sits at the END of the span", it fails here rather than on
46
+ // chain, where the symptom is a session nobody can spend.
47
+ const spliced = withState(a.hex, 7, 123456, a.span.offset + a.span.len);
48
+ console.log(`\nsplice check ${spliced === b.hex ? 'IDENTICAL to a real compile' : 'DIFFERS from a real compile'}`);
49
+ if (spliced !== b.hex) {
50
+ console.log(` spliced ${spliced}`);
51
+ console.log(` compiled ${b.hex}`);
52
+ process.exit(1);
53
+ }
54
+ void execFileSync;
55
+ void writeFileSync;
56
+ void readFileSync;
57
+ //# sourceMappingURL=state-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-layout.js","sourceRoot":"","sources":["../../tools/state-layout.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "metered-protocol",
3
+ "version": "1.0.0",
4
+ "description": "A chunked, two-sided payment scheme for metered work, settled on Kaspa.",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/src/index.d.ts",
9
+ "import": "./dist/src/index.js"
10
+ },
11
+ "./chain": {
12
+ "types": "./dist/tools/chain.d.ts",
13
+ "import": "./dist/tools/chain.js"
14
+ }
15
+ },
16
+ "types": "./dist/src/index.d.ts",
17
+ "files": [
18
+ "dist",
19
+ "contracts",
20
+ "spec/SPEC.md",
21
+ "spec/CONFORMANCE.md",
22
+ "spec/conformance-vectors.json",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "license": "MIT",
27
+ "engines": {
28
+ "node": ">=20"
29
+ },
30
+ "scripts": {
31
+ "build": "node build.mjs",
32
+ "prepublishOnly": "npm run build && npm test",
33
+ "test": "node --import tsx --test \"src/**/*.test.ts\"",
34
+ "conformance": "tsx tools/conformance.ts",
35
+ "conformance:py": "python impl-py/conformance.py",
36
+ "vectors": "tsx spec/vectors.ts > spec/worked-example.txt",
37
+ "contracts": "tsx tools/contracts.ts",
38
+ "contracts:ag": "tsx tools/contracts.ts --profile ag",
39
+ "state-layout": "tsx tools/state-layout.ts",
40
+ "dust-map": "tsx tools/dust-map.ts",
41
+ "fee-check": "tsx tools/fee-check.ts",
42
+ "anchor": "tsx tools/anchor-cli.ts",
43
+ "demo": "tsx tools/demo.ts",
44
+ "live:settle": "tsx tools/live-settle.ts",
45
+ "live:expire": "tsx tools/live-expire.ts",
46
+ "live:deadline": "tsx tools/live-deadline.ts",
47
+ "sigscript": "tsx tools/sigscript-check.ts"
48
+ },
49
+ "dependencies": {
50
+ "@noble/curves": "^1.9.7",
51
+ "@noble/hashes": "^1.8.0",
52
+ "gpt-tokenizer": "^4.0.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^22.20.2",
56
+ "tsx": "^4.19.2",
57
+ "typescript": "^5.7.2"
58
+ }
59
+ }