@dcasegr/amm-client 0.0.0-stage → 0.38.2

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 (121) hide show
  1. package/README.md +107 -2
  2. package/dist/client.d.ts +534 -0
  3. package/dist/client.js +1319 -0
  4. package/dist/errors.d.ts +17 -0
  5. package/dist/errors.js +75 -0
  6. package/dist/index.d.ts +51 -0
  7. package/dist/index.js +53 -0
  8. package/dist/lib/config.d.ts +42 -0
  9. package/dist/lib/config.js +64 -0
  10. package/dist/lib/keys.d.ts +42 -0
  11. package/dist/lib/keys.js +48 -0
  12. package/dist/lib/overlay.d.ts +190 -0
  13. package/dist/lib/overlay.js +302 -0
  14. package/dist/lib/skein.d.ts +82 -0
  15. package/dist/lib/skein.js +142 -0
  16. package/dist/lib/tokenId.d.ts +72 -0
  17. package/dist/lib/tokenId.js +121 -0
  18. package/dist/lp/amounts.d.ts +12 -0
  19. package/dist/lp/amounts.js +38 -0
  20. package/dist/lp/close.d.ts +90 -0
  21. package/dist/lp/close.js +140 -0
  22. package/dist/lp/images.d.ts +11 -0
  23. package/dist/lp/images.js +45 -0
  24. package/dist/lp/inventory.d.ts +68 -0
  25. package/dist/lp/inventory.js +84 -0
  26. package/dist/lp/poolDeploy.d.ts +220 -0
  27. package/dist/lp/poolDeploy.js +291 -0
  28. package/dist/lp/poolRows.d.ts +13 -0
  29. package/dist/lp/poolRows.js +19 -0
  30. package/dist/lp/positions.d.ts +81 -0
  31. package/dist/lp/positions.js +144 -0
  32. package/dist/lp/rebalance.d.ts +101 -0
  33. package/dist/lp/rebalance.js +168 -0
  34. package/dist/lp/wallet.d.ts +12 -0
  35. package/dist/lp/wallet.js +19 -0
  36. package/dist/market/activeSwap.d.ts +158 -0
  37. package/dist/market/activeSwap.js +320 -0
  38. package/dist/market/plan.d.ts +85 -0
  39. package/dist/market/plan.js +149 -0
  40. package/dist/market/prices.d.ts +13 -0
  41. package/dist/market/prices.js +14 -0
  42. package/dist/market/relay.d.ts +84 -0
  43. package/dist/market/relay.js +201 -0
  44. package/dist/market/swapAction.d.ts +306 -0
  45. package/dist/market/swapAction.js +508 -0
  46. package/dist/market/swapFlow.d.ts +58 -0
  47. package/dist/market/swapFlow.js +86 -0
  48. package/dist/market/view.d.ts +58 -0
  49. package/dist/market/view.js +63 -0
  50. package/dist/pool/artifact.d.ts +23 -0
  51. package/dist/pool/artifact.js +38 -0
  52. package/dist/pool/index.d.ts +8 -0
  53. package/dist/pool/index.js +8 -0
  54. package/dist/pool/oneColor.d.ts +19 -0
  55. package/dist/pool/oneColor.js +39 -0
  56. package/dist/pool/pool.artifact.json +5069 -0
  57. package/dist/pool/runar-ir-schema.d.ts +21 -0
  58. package/dist/pool/runar-ir-schema.js +18 -0
  59. package/dist/pool/template.d.ts +295 -0
  60. package/dist/pool/template.js +715 -0
  61. package/dist/vendor/runar/LICENSE +21 -0
  62. package/dist/vendor/runar/NOTICE +15 -0
  63. package/dist/vendor/runar/runar-ir-schema/src/abi-type-encoding.d.ts +42 -0
  64. package/dist/vendor/runar/runar-ir-schema/src/abi-type-encoding.js +53 -0
  65. package/dist/vendor/runar/runar-ir-schema/src/anf-ir.d.ts +221 -0
  66. package/dist/vendor/runar/runar-ir-schema/src/anf-ir.js +33 -0
  67. package/dist/vendor/runar/runar-ir-schema/src/artifact.d.ts +288 -0
  68. package/dist/vendor/runar/runar-ir-schema/src/artifact.js +8 -0
  69. package/dist/vendor/runar/runar-ir-schema/src/canonical-json.d.ts +43 -0
  70. package/dist/vendor/runar/runar-ir-schema/src/canonical-json.js +204 -0
  71. package/dist/vendor/runar/runar-ir-schema/src/input-limits.d.ts +89 -0
  72. package/dist/vendor/runar/runar-ir-schema/src/input-limits.js +100 -0
  73. package/dist/vendor/runar/runar-ir-schema/src/stack-ir.d.ts +118 -0
  74. package/dist/vendor/runar/runar-ir-schema/src/stack-ir.js +8 -0
  75. package/dist/vendor/runar/runar-ir-schema/src/state-layout.d.ts +56 -0
  76. package/dist/vendor/runar/runar-ir-schema/src/state-layout.js +145 -0
  77. package/dist/vendor/runar/runar-ir-schema/src/unknown-anf-kind-error.d.ts +18 -0
  78. package/dist/vendor/runar/runar-ir-schema/src/unknown-anf-kind-error.js +25 -0
  79. package/dist/vendor/runar/runar-sdk/src/anf-interpreter.d.ts +160 -0
  80. package/dist/vendor/runar/runar-sdk/src/anf-interpreter.js +1149 -0
  81. package/dist/vendor/runar/runar-sdk/src/calling.d.ts +98 -0
  82. package/dist/vendor/runar/runar-sdk/src/calling.js +209 -0
  83. package/dist/vendor/runar/runar-sdk/src/contract.d.ts +443 -0
  84. package/dist/vendor/runar/runar-sdk/src/contract.js +2516 -0
  85. package/dist/vendor/runar/runar-sdk/src/deployment.d.ts +36 -0
  86. package/dist/vendor/runar/runar-sdk/src/deployment.js +119 -0
  87. package/dist/vendor/runar/runar-sdk/src/errors.d.ts +46 -0
  88. package/dist/vendor/runar/runar-sdk/src/errors.js +59 -0
  89. package/dist/vendor/runar/runar-sdk/src/oppushtx.d.ts +23 -0
  90. package/dist/vendor/runar/runar-sdk/src/oppushtx.js +95 -0
  91. package/dist/vendor/runar/runar-sdk/src/ordinals/envelope.d.ts +31 -0
  92. package/dist/vendor/runar/runar-sdk/src/ordinals/envelope.js +272 -0
  93. package/dist/vendor/runar/runar-sdk/src/ordinals/types.d.ts +21 -0
  94. package/dist/vendor/runar/runar-sdk/src/ordinals/types.js +4 -0
  95. package/dist/vendor/runar/runar-sdk/src/providers/provider.d.ts +65 -0
  96. package/dist/vendor/runar/runar-sdk/src/providers/provider.js +59 -0
  97. package/dist/vendor/runar/runar-sdk/src/providers/wallet-provider.d.ts +94 -0
  98. package/dist/vendor/runar/runar-sdk/src/providers/wallet-provider.js +297 -0
  99. package/dist/vendor/runar/runar-sdk/src/script-utils.d.ts +54 -0
  100. package/dist/vendor/runar/runar-sdk/src/script-utils.js +252 -0
  101. package/dist/vendor/runar/runar-sdk/src/signers/signer.d.ts +17 -0
  102. package/dist/vendor/runar/runar-sdk/src/signers/signer.js +4 -0
  103. package/dist/vendor/runar/runar-sdk/src/spend-safety.d.ts +31 -0
  104. package/dist/vendor/runar/runar-sdk/src/spend-safety.js +35 -0
  105. package/dist/vendor/runar/runar-sdk/src/state.d.ts +54 -0
  106. package/dist/vendor/runar/runar-sdk/src/state.js +584 -0
  107. package/dist/vendor/runar/runar-sdk/src/types.d.ts +227 -0
  108. package/dist/vendor/runar/runar-sdk/src/types.js +4 -0
  109. package/dist/vendor/runar/runar-sdk/src/unsound-primitives.d.ts +30 -0
  110. package/dist/vendor/runar/runar-sdk/src/unsound-primitives.js +42 -0
  111. package/dist/vendor/runar/runar-sdk.d.ts +9 -0
  112. package/dist/vendor/runar/runar-sdk.js +8 -0
  113. package/dist/wallet/action.d.ts +28 -0
  114. package/dist/wallet/action.js +42 -0
  115. package/dist/wallet/brc29.d.ts +83 -0
  116. package/dist/wallet/brc29.js +80 -0
  117. package/dist/wallet/color.d.ts +110 -0
  118. package/dist/wallet/color.js +134 -0
  119. package/dist/wallet/swapPayouts.d.ts +35 -0
  120. package/dist/wallet/swapPayouts.js +146 -0
  121. package/package.json +39 -4
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Rúnar Artifact — the final compiled output of a Rúnar compiler (Pass 6).
3
+ *
4
+ * This is what gets consumed by wallets, SDKs, and deployment tooling.
5
+ * It bundles the locking script, ABI metadata, optional debug info,
6
+ * and (for stateful contracts) state field descriptors.
7
+ */
8
+ export {};
@@ -0,0 +1,43 @@
1
+ /**
2
+ * RFC 8785 / JCS (JSON Canonicalization Scheme) serializer.
3
+ *
4
+ * Produces a deterministic, byte-identical JSON string for any JSON-compatible
5
+ * value. This is used to guarantee that two Rúnar compilers emitting the same
6
+ * ANF IR will produce identical output when serialised.
7
+ *
8
+ * Key properties:
9
+ * - Object keys are sorted by their UTF-16 code-unit values (per ES spec).
10
+ * - Numbers use ES `JSON.stringify` serialization (IEEE 754, no trailing
11
+ * zeros, no positive sign on exponent, etc.).
12
+ * - No whitespace.
13
+ * - `undefined` values and `undefined` array slots are not allowed (will
14
+ * throw).
15
+ * - `bigint` values are serialised as bare integers (no quotes), matching the
16
+ * JSON Schema `integer` type used in the ANF IR schema.
17
+ *
18
+ * DoS-bound input guards:
19
+ * - Recursion depth is capped at {@link InputLimits.MAX_NESTING}.
20
+ * - Individual string values are capped at {@link InputLimits.MAX_STRING_BYTES}.
21
+ * - Total serialised output is capped at {@link InputLimits.MAX_IR_BYTES}.
22
+ * - Bound violations throw {@link CanonicalJsonError} with `code` / `limit` /
23
+ * `actual` set for typed downstream handling.
24
+ *
25
+ * @see https://www.rfc-editor.org/rfc/rfc8785
26
+ */
27
+ /**
28
+ * Serialise a value to canonical JSON (RFC 8785 / JCS).
29
+ *
30
+ * @throws {TypeError} if the value contains functions or symbols.
31
+ * @throws {CanonicalJsonError} if recursion depth, string byte length, or
32
+ * total output byte length exceeds the documented {@link InputLimits}.
33
+ */
34
+ export declare function canonicalJsonStringify(value: unknown): string;
35
+ /**
36
+ * Parse a JSON string and re-serialise it to canonical form.
37
+ * Useful for normalising IR that was stored with pretty-printing.
38
+ *
39
+ * @throws {CanonicalJsonError} with `code: 'invalid'` if the input is not
40
+ * valid JSON, or with `code: 'bytes'` / `'depth'` / `'string-bytes'` if
41
+ * the canonicalised output would violate an {@link InputLimits} bound.
42
+ */
43
+ export declare function canonicalise(json: string): string;
@@ -0,0 +1,204 @@
1
+ /**
2
+ * RFC 8785 / JCS (JSON Canonicalization Scheme) serializer.
3
+ *
4
+ * Produces a deterministic, byte-identical JSON string for any JSON-compatible
5
+ * value. This is used to guarantee that two Rúnar compilers emitting the same
6
+ * ANF IR will produce identical output when serialised.
7
+ *
8
+ * Key properties:
9
+ * - Object keys are sorted by their UTF-16 code-unit values (per ES spec).
10
+ * - Numbers use ES `JSON.stringify` serialization (IEEE 754, no trailing
11
+ * zeros, no positive sign on exponent, etc.).
12
+ * - No whitespace.
13
+ * - `undefined` values and `undefined` array slots are not allowed (will
14
+ * throw).
15
+ * - `bigint` values are serialised as bare integers (no quotes), matching the
16
+ * JSON Schema `integer` type used in the ANF IR schema.
17
+ *
18
+ * DoS-bound input guards:
19
+ * - Recursion depth is capped at {@link InputLimits.MAX_NESTING}.
20
+ * - Individual string values are capped at {@link InputLimits.MAX_STRING_BYTES}.
21
+ * - Total serialised output is capped at {@link InputLimits.MAX_IR_BYTES}.
22
+ * - Bound violations throw {@link CanonicalJsonError} with `code` / `limit` /
23
+ * `actual` set for typed downstream handling.
24
+ *
25
+ * @see https://www.rfc-editor.org/rfc/rfc8785
26
+ */
27
+ import { InputLimits, CanonicalJsonError } from './input-limits.js';
28
+ // ---------------------------------------------------------------------------
29
+ // Public API
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Serialise a value to canonical JSON (RFC 8785 / JCS).
33
+ *
34
+ * @throws {TypeError} if the value contains functions or symbols.
35
+ * @throws {CanonicalJsonError} if recursion depth, string byte length, or
36
+ * total output byte length exceeds the documented {@link InputLimits}.
37
+ */
38
+ export function canonicalJsonStringify(value) {
39
+ const result = serialise(value, new Set(), 0);
40
+ // Final output-byte-length guard (UTF-8 bytes).
41
+ const byteLen = Buffer.byteLength(result, 'utf8');
42
+ if (byteLen > InputLimits.MAX_IR_BYTES) {
43
+ throw new CanonicalJsonError('bytes', `canonical JSON output exceeds ${InputLimits.MAX_IR_BYTES} bytes (actual ${byteLen})`, { limit: InputLimits.MAX_IR_BYTES, actual: byteLen });
44
+ }
45
+ return result;
46
+ }
47
+ /**
48
+ * Parse a JSON string and re-serialise it to canonical form.
49
+ * Useful for normalising IR that was stored with pretty-printing.
50
+ *
51
+ * @throws {CanonicalJsonError} with `code: 'invalid'` if the input is not
52
+ * valid JSON, or with `code: 'bytes'` / `'depth'` / `'string-bytes'` if
53
+ * the canonicalised output would violate an {@link InputLimits} bound.
54
+ */
55
+ export function canonicalise(json) {
56
+ let parsed;
57
+ try {
58
+ parsed = JSON.parse(json);
59
+ }
60
+ catch (e) {
61
+ throw new CanonicalJsonError('invalid', `canonicalise: input is not valid JSON: ${e.message}`);
62
+ }
63
+ return canonicalJsonStringify(parsed);
64
+ }
65
+ // ---------------------------------------------------------------------------
66
+ // Serialisation engine
67
+ // ---------------------------------------------------------------------------
68
+ function serialise(value, seen, depth) {
69
+ // null
70
+ if (value === null) {
71
+ return 'null';
72
+ }
73
+ // Primitives
74
+ switch (typeof value) {
75
+ case 'boolean':
76
+ return value ? 'true' : 'false';
77
+ case 'number':
78
+ return serialiseNumber(value);
79
+ case 'bigint':
80
+ // Serialise as a bare JSON integer — no quotes.
81
+ return value.toString();
82
+ case 'string':
83
+ return serialiseString(value);
84
+ case 'undefined':
85
+ case 'symbol':
86
+ case 'function':
87
+ throw new TypeError(`canonical JSON does not support ${typeof value}`);
88
+ }
89
+ // Objects and arrays (typeof === 'object' at this point)
90
+ // Depth guard before descending into the container.
91
+ //
92
+ // R-260/R-261: the bound is MAX_WIRE_NESTING (100), not MAX_NESTING (512).
93
+ // canonicalJson's output crosses a tier boundary and its bound has to be the
94
+ // same number verifyEnvelope will PARSE on the far side — if emit allowed
95
+ // more than parse, a tier could produce a legal, correctly-signed envelope
96
+ // another tier is physically unable to read. 512 stays the `--ir` loader's
97
+ // bound, where the input is a trusted local file.
98
+ if (depth >= InputLimits.MAX_WIRE_NESTING) {
99
+ throw new CanonicalJsonError('depth', `canonical JSON nesting exceeds ${InputLimits.MAX_WIRE_NESTING}`, { limit: InputLimits.MAX_WIRE_NESTING, actual: depth + 1 });
100
+ }
101
+ const obj = value;
102
+ // Circular reference detection
103
+ if (seen.has(obj)) {
104
+ throw new TypeError('canonical JSON does not support circular references');
105
+ }
106
+ seen.add(obj);
107
+ // Arrays and objects (including typed arrays, Date, RegExp, etc.) both
108
+ // route through serialiseObject which honours `toJSON` and otherwise
109
+ // walks own enumerable keys.
110
+ const result = Array.isArray(obj)
111
+ ? serialiseArray(obj, seen, depth + 1)
112
+ : serialiseObject(obj, seen, depth + 1);
113
+ seen.delete(obj);
114
+ return result;
115
+ }
116
+ // ---------------------------------------------------------------------------
117
+ // Number serialisation (ES2022 §25.5.2.1)
118
+ // ---------------------------------------------------------------------------
119
+ function serialiseNumber(n) {
120
+ if (!Number.isFinite(n)) {
121
+ throw new TypeError(`canonical JSON does not support ${n} (NaN / Infinity)`);
122
+ }
123
+ if (Object.is(n, -0)) {
124
+ return '0';
125
+ }
126
+ // JSON.stringify for finite numbers matches the ES spec requirement
127
+ // that RFC 8785 mandates.
128
+ return JSON.stringify(n);
129
+ }
130
+ // ---------------------------------------------------------------------------
131
+ // String serialisation (RFC 8785 §3.2.2.2)
132
+ // ---------------------------------------------------------------------------
133
+ function serialiseString(s) {
134
+ // Per-string byte-length guard.
135
+ const byteLen = Buffer.byteLength(s, 'utf8');
136
+ if (byteLen > InputLimits.MAX_STRING_BYTES) {
137
+ throw new CanonicalJsonError('string-bytes', `canonical JSON string field exceeds ${InputLimits.MAX_STRING_BYTES} bytes (actual ${byteLen})`, { limit: InputLimits.MAX_STRING_BYTES, actual: byteLen });
138
+ }
139
+ // RFC 8785 §3.2.2.2 / audit D6: the input MUST be well-formed Unicode.
140
+ // JS strings are UTF-16 code-unit sequences and may legally contain
141
+ // unpaired surrogates; `JSON.stringify` happily emits them, producing
142
+ // bytes that the six other SDK tiers reject. Walk code units, reject any
143
+ // unpaired surrogate, and only then delegate to `JSON.stringify` for the
144
+ // actual escape table (which is correct on well-formed inputs).
145
+ for (let i = 0; i < s.length; i++) {
146
+ const c = s.charCodeAt(i);
147
+ if (c >= 0xD800 && c <= 0xDBFF) {
148
+ const next = i + 1 < s.length ? s.charCodeAt(i + 1) : -1;
149
+ if (next < 0xDC00 || next > 0xDFFF) {
150
+ throw new CanonicalJsonError('lone-surrogate', `canonical JSON: lone high surrogate U+${c.toString(16).toUpperCase().padStart(4, '0')} in string`);
151
+ }
152
+ i++; // skip the valid low surrogate
153
+ }
154
+ else if (c >= 0xDC00 && c <= 0xDFFF) {
155
+ throw new CanonicalJsonError('lone-surrogate', `canonical JSON: lone low surrogate U+${c.toString(16).toUpperCase().padStart(4, '0')} in string`);
156
+ }
157
+ }
158
+ // JSON.stringify already produces correct escaping for most cases.
159
+ // RFC 8785 additionally requires that code-points U+0000–U+001F are
160
+ // \uXXXX-escaped (which JSON.stringify does), and that there is no
161
+ // gratuitous escaping of solidus '/' (JSON.stringify does NOT escape it
162
+ // by default in modern engines, which is correct).
163
+ return JSON.stringify(s);
164
+ }
165
+ // ---------------------------------------------------------------------------
166
+ // Array serialisation
167
+ // ---------------------------------------------------------------------------
168
+ function serialiseArray(arr, seen, depth) {
169
+ const parts = [];
170
+ for (let i = 0; i < arr.length; i++) {
171
+ const element = arr[i];
172
+ if (element === undefined) {
173
+ // JSON.stringify converts undefined array elements to null.
174
+ parts.push('null');
175
+ }
176
+ else {
177
+ parts.push(serialise(element, seen, depth));
178
+ }
179
+ }
180
+ return '[' + parts.join(',') + ']';
181
+ }
182
+ // ---------------------------------------------------------------------------
183
+ // Object serialisation (keys sorted by UTF-16 code-unit value)
184
+ // ---------------------------------------------------------------------------
185
+ function serialiseObject(obj, seen, depth) {
186
+ // If the object has a toJSON method, use it (Date, etc.)
187
+ const asAny = obj;
188
+ if (typeof asAny['toJSON'] === 'function') {
189
+ return serialise(asAny['toJSON'](), seen, depth);
190
+ }
191
+ // Collect own enumerable string keys and sort by UTF-16 code units.
192
+ // In ES, `Array.prototype.sort()` without a comparator uses the
193
+ // default string comparison which is exactly UTF-16 code-unit order.
194
+ const keys = Object.keys(obj).sort();
195
+ const parts = [];
196
+ for (const key of keys) {
197
+ const val = obj[key];
198
+ // JSON.stringify omits keys whose value is undefined.
199
+ if (val === undefined)
200
+ continue;
201
+ parts.push(serialiseString(key) + ':' + serialise(val, seen, depth));
202
+ }
203
+ return '{' + parts.join(',') + '}';
204
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Shared DoS-bound input limits + typed error class used by all public
3
+ * canonical-JSON / IR-loading entry points across the runar-ir-schema
4
+ * package and its downstream consumers.
5
+ *
6
+ * Justifications:
7
+ * - MAX_SCRIPT_BYTES = 4 MiB — the largest legitimate script measured by
8
+ * the script-size benchmark is `p384-wallet` at ~1.87 MB; 4 MiB gives
9
+ * ~2× headroom without enabling pathological 50 MB scripts. An earlier
10
+ * 1 MiB cap incorrectly rejected p384-wallet — calibration bug caught
11
+ * by the script-size baseline (Major-2).
12
+ * - MAX_IR_BYTES = 16 MiB — the largest compiled-IR JSON in the corpus is
13
+ * `conformance/tests/token-ft/expected-ir.json` at 91,018 B (0.087 MiB),
14
+ * so 16 MiB is ~184× headroom. An earlier note put the largest at "~2 MiB
15
+ * (Mode 3 STARK contracts)" and the headroom at 8×; no checked-in
16
+ * `expected-ir.json` has ever come within 24× of that figure. The bound is
17
+ * sized against a pathological producer, not against this corpus, so the
18
+ * real number being far larger is fine — it is the stated one that was
19
+ * wrong, and a wrong one invites the next person to recalibrate downward
20
+ * against a fiction.
21
+ * - MAX_NESTING = 512 — JS engine stack typically tolerates ~10k frames;
22
+ * 512 is well below crash threshold but accommodates legitimate deep
23
+ * covenant ANF. This bound serves the `--ir` loader
24
+ * (runar-compiler/src/index.ts), which reads a TRUSTED local file.
25
+ * - MAX_WIRE_NESTING = 100 — the bound for anything crossing a tier
26
+ * boundary: canonicalJson's emit side and verifyEnvelope's parse side.
27
+ * Different threat model from MAX_NESTING (unauthenticated network input,
28
+ * not a local file), so deliberately a separate constant rather than a
29
+ * shared one. 100 is the largest depth Ruby's `JSON.parse` accepts for
30
+ * EVERY payload shape at its native default — measured on ruby 4.0.2 /
31
+ * json 2.18.0, 100-deep parses for both arrays and objects, a 101-deep
32
+ * OBJECT raises JSON::NestingError, and a 101-deep ARRAY still parses; the
33
+ * gem counts the two shapes one level apart, so an earlier flat "100
34
+ * accepted, 101 rejected" is true of objects and false of arrays. That
35
+ * asymmetry is the whole reason the bound is 100 rather than 101: raising
36
+ * it to the depth Ruby accepts for ARRAYS would keep working on every
37
+ * array payload and start rejecting 101-deep OBJECTS at the Ruby tier
38
+ * only — a shape-dependent, one-tier failure, which is the worst kind to
39
+ * debug on a signed wire. 100 is
40
+ * also 27 below rust serde_json's hard ceiling of 127, so every tier stays
41
+ * inside its own library's default without hand-rolling or reconfiguring a
42
+ * parser, and no tier is anywhere near its stack — at 1024 Python's
43
+ * canonical_json dies of native stack exhaustion and the JVM crashes on a
44
+ * 513-deep object, so a higher bound would trade a clean typed rejection
45
+ * for a crash. Headroom is ample: the deepest of the 165 checked-in
46
+ * conformance artifacts measures depth 15, and
47
+ * conformance/sdk-envelope/fixtures.json tops out at 6.
48
+ * - MAX_STRING_BYTES = 4 MiB — the binding case is a compiled script carried
49
+ * as a hex string, not a verification key. The largest checked-in script is
50
+ * `conformance/tests/p384-wallet/expected-script.hex`: 1,963,362 script
51
+ * bytes = 3,926,724 hex characters, which is 93.6% of this bound. Real
52
+ * headroom is 1.07×. An earlier note claimed "~3× headroom" against "the
53
+ * largest checked-in hex pushdata (witness-assisted Groth16 VK)" — that
54
+ * artifact, `examples/go/SP1Verifier.groth16.vk.json`, is 3,287 bytes in
55
+ * total and was never the worst case; the justification named the wrong
56
+ * artifact and overstated the margin by ~3×.
57
+ *
58
+ * Structural consequence worth stating plainly: MAX_SCRIPT_BYTES admits
59
+ * 4 MiB of SCRIPT, and hex doubles it. So anything that reaches
60
+ * signEnvelope as a hex string through canonicalJson is capped at 2 MiB of
61
+ * script — HALF the advertised script bound — and the largest script in
62
+ * the tree already sits at 93.6% of that. The next script family that
63
+ * clears ~2 MiB needs a coordinated seven-tier bump of this constant, not
64
+ * a local one: raising it in one tier splits the wire.
65
+ */
66
+ export declare const InputLimits: {
67
+ readonly MAX_IR_BYTES: number;
68
+ readonly MAX_SCRIPT_BYTES: number;
69
+ readonly MAX_NESTING: 512;
70
+ readonly MAX_WIRE_NESTING: 100;
71
+ readonly MAX_STRING_BYTES: number;
72
+ readonly MAX_SOURCE_BYTES: number;
73
+ };
74
+ export type InputLimitsKey = keyof typeof InputLimits;
75
+ /**
76
+ * Thrown when a public canonical-JSON / IR-loading entry point detects
77
+ * input that exceeds a documented InputLimits bound. Distinct typed
78
+ * exception so callers can distinguish DoS-bound rejection from generic
79
+ * RangeError / SyntaxError.
80
+ */
81
+ export declare class CanonicalJsonError extends Error {
82
+ readonly code: 'depth' | 'bytes' | 'string-bytes' | 'circular' | 'invalid' | 'lone-surrogate';
83
+ readonly limit?: number;
84
+ readonly actual?: number;
85
+ constructor(code: 'depth' | 'bytes' | 'string-bytes' | 'circular' | 'invalid' | 'lone-surrogate', message: string, info?: {
86
+ limit?: number;
87
+ actual?: number;
88
+ });
89
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Shared DoS-bound input limits + typed error class used by all public
3
+ * canonical-JSON / IR-loading entry points across the runar-ir-schema
4
+ * package and its downstream consumers.
5
+ *
6
+ * Justifications:
7
+ * - MAX_SCRIPT_BYTES = 4 MiB — the largest legitimate script measured by
8
+ * the script-size benchmark is `p384-wallet` at ~1.87 MB; 4 MiB gives
9
+ * ~2× headroom without enabling pathological 50 MB scripts. An earlier
10
+ * 1 MiB cap incorrectly rejected p384-wallet — calibration bug caught
11
+ * by the script-size baseline (Major-2).
12
+ * - MAX_IR_BYTES = 16 MiB — the largest compiled-IR JSON in the corpus is
13
+ * `conformance/tests/token-ft/expected-ir.json` at 91,018 B (0.087 MiB),
14
+ * so 16 MiB is ~184× headroom. An earlier note put the largest at "~2 MiB
15
+ * (Mode 3 STARK contracts)" and the headroom at 8×; no checked-in
16
+ * `expected-ir.json` has ever come within 24× of that figure. The bound is
17
+ * sized against a pathological producer, not against this corpus, so the
18
+ * real number being far larger is fine — it is the stated one that was
19
+ * wrong, and a wrong one invites the next person to recalibrate downward
20
+ * against a fiction.
21
+ * - MAX_NESTING = 512 — JS engine stack typically tolerates ~10k frames;
22
+ * 512 is well below crash threshold but accommodates legitimate deep
23
+ * covenant ANF. This bound serves the `--ir` loader
24
+ * (runar-compiler/src/index.ts), which reads a TRUSTED local file.
25
+ * - MAX_WIRE_NESTING = 100 — the bound for anything crossing a tier
26
+ * boundary: canonicalJson's emit side and verifyEnvelope's parse side.
27
+ * Different threat model from MAX_NESTING (unauthenticated network input,
28
+ * not a local file), so deliberately a separate constant rather than a
29
+ * shared one. 100 is the largest depth Ruby's `JSON.parse` accepts for
30
+ * EVERY payload shape at its native default — measured on ruby 4.0.2 /
31
+ * json 2.18.0, 100-deep parses for both arrays and objects, a 101-deep
32
+ * OBJECT raises JSON::NestingError, and a 101-deep ARRAY still parses; the
33
+ * gem counts the two shapes one level apart, so an earlier flat "100
34
+ * accepted, 101 rejected" is true of objects and false of arrays. That
35
+ * asymmetry is the whole reason the bound is 100 rather than 101: raising
36
+ * it to the depth Ruby accepts for ARRAYS would keep working on every
37
+ * array payload and start rejecting 101-deep OBJECTS at the Ruby tier
38
+ * only — a shape-dependent, one-tier failure, which is the worst kind to
39
+ * debug on a signed wire. 100 is
40
+ * also 27 below rust serde_json's hard ceiling of 127, so every tier stays
41
+ * inside its own library's default without hand-rolling or reconfiguring a
42
+ * parser, and no tier is anywhere near its stack — at 1024 Python's
43
+ * canonical_json dies of native stack exhaustion and the JVM crashes on a
44
+ * 513-deep object, so a higher bound would trade a clean typed rejection
45
+ * for a crash. Headroom is ample: the deepest of the 165 checked-in
46
+ * conformance artifacts measures depth 15, and
47
+ * conformance/sdk-envelope/fixtures.json tops out at 6.
48
+ * - MAX_STRING_BYTES = 4 MiB — the binding case is a compiled script carried
49
+ * as a hex string, not a verification key. The largest checked-in script is
50
+ * `conformance/tests/p384-wallet/expected-script.hex`: 1,963,362 script
51
+ * bytes = 3,926,724 hex characters, which is 93.6% of this bound. Real
52
+ * headroom is 1.07×. An earlier note claimed "~3× headroom" against "the
53
+ * largest checked-in hex pushdata (witness-assisted Groth16 VK)" — that
54
+ * artifact, `examples/go/SP1Verifier.groth16.vk.json`, is 3,287 bytes in
55
+ * total and was never the worst case; the justification named the wrong
56
+ * artifact and overstated the margin by ~3×.
57
+ *
58
+ * Structural consequence worth stating plainly: MAX_SCRIPT_BYTES admits
59
+ * 4 MiB of SCRIPT, and hex doubles it. So anything that reaches
60
+ * signEnvelope as a hex string through canonicalJson is capped at 2 MiB of
61
+ * script — HALF the advertised script bound — and the largest script in
62
+ * the tree already sits at 93.6% of that. The next script family that
63
+ * clears ~2 MiB needs a coordinated seven-tier bump of this constant, not
64
+ * a local one: raising it in one tier splits the wire.
65
+ */
66
+ export const InputLimits = {
67
+ MAX_IR_BYTES: 16 * 1024 * 1024, // 16 MiB — uncompressed ANF IR JSON
68
+ MAX_SCRIPT_BYTES: 4 * 1024 * 1024, // 4 MiB — single compiled Bitcoin Script
69
+ // (p384-wallet hits ~1.87 MB; 2× headroom)
70
+ MAX_NESTING: 512, // recursion depth for JSON / ANF traversal
71
+ // (trusted local --ir input)
72
+ MAX_WIRE_NESTING: 100, // recursion depth for anything crossing a
73
+ // tier boundary (canonicalJson emit,
74
+ // verifyEnvelope parse) — untrusted input
75
+ MAX_STRING_BYTES: 4 * 1024 * 1024, // 4 MiB — single string field inside JSON
76
+ // (hex doubles: an effective 2 MiB script
77
+ // ceiling on the wire; today's largest is
78
+ // at 93.6% of it)
79
+ MAX_SOURCE_BYTES: 4 * 1024 * 1024, // 4 MiB — single Rúnar source file
80
+ // (BUG-008 follow-up: source parser entry guard
81
+ // across all 7 tiers)
82
+ };
83
+ /**
84
+ * Thrown when a public canonical-JSON / IR-loading entry point detects
85
+ * input that exceeds a documented InputLimits bound. Distinct typed
86
+ * exception so callers can distinguish DoS-bound rejection from generic
87
+ * RangeError / SyntaxError.
88
+ */
89
+ export class CanonicalJsonError extends Error {
90
+ code;
91
+ limit;
92
+ actual;
93
+ constructor(code, message, info) {
94
+ super(message);
95
+ this.name = 'CanonicalJsonError';
96
+ this.code = code;
97
+ this.limit = info?.limit;
98
+ this.actual = info?.actual;
99
+ }
100
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Stack IR — the low-level stack-machine representation (Pass 5 output).
3
+ *
4
+ * Each method is lowered to a flat sequence of stack operations that map
5
+ * almost 1-to-1 to Bitcoin Script opcodes. This representation is
6
+ * compiler-specific (not part of the conformance boundary).
7
+ */
8
+ export interface StackProgram {
9
+ contractName: string;
10
+ methods: StackMethod[];
11
+ }
12
+ export interface StackMethod {
13
+ name: string;
14
+ ops: StackOp[];
15
+ maxStackDepth: number;
16
+ }
17
+ /** Optional source location for debug source maps. */
18
+ export interface StackSourceLoc {
19
+ file: string;
20
+ line: number;
21
+ column: number;
22
+ }
23
+ export interface PushOp {
24
+ op: 'push';
25
+ value: Uint8Array | bigint | boolean;
26
+ sourceLoc?: StackSourceLoc;
27
+ }
28
+ export interface DupOp {
29
+ op: 'dup';
30
+ sourceLoc?: StackSourceLoc;
31
+ }
32
+ export interface SwapOp {
33
+ op: 'swap';
34
+ sourceLoc?: StackSourceLoc;
35
+ }
36
+ export interface RollOp {
37
+ op: 'roll';
38
+ depth: number;
39
+ sourceLoc?: StackSourceLoc;
40
+ }
41
+ export interface PickOp {
42
+ op: 'pick';
43
+ depth: number;
44
+ sourceLoc?: StackSourceLoc;
45
+ }
46
+ export interface DropOp {
47
+ op: 'drop';
48
+ sourceLoc?: StackSourceLoc;
49
+ }
50
+ export interface OpcodeOp {
51
+ op: 'opcode';
52
+ code: string;
53
+ sourceLoc?: StackSourceLoc;
54
+ }
55
+ export interface IfOp {
56
+ op: 'if';
57
+ then: StackOp[];
58
+ else?: StackOp[];
59
+ sourceLoc?: StackSourceLoc;
60
+ }
61
+ export interface NipOp {
62
+ op: 'nip';
63
+ sourceLoc?: StackSourceLoc;
64
+ }
65
+ export interface OverOp {
66
+ op: 'over';
67
+ sourceLoc?: StackSourceLoc;
68
+ }
69
+ export interface RotOp {
70
+ op: 'rot';
71
+ sourceLoc?: StackSourceLoc;
72
+ }
73
+ export interface TuckOp {
74
+ op: 'tuck';
75
+ sourceLoc?: StackSourceLoc;
76
+ }
77
+ export interface PlaceholderOp {
78
+ op: 'placeholder';
79
+ paramIndex: number;
80
+ paramName: string;
81
+ sourceLoc?: StackSourceLoc;
82
+ }
83
+ export interface PushCodeSepIndexOp {
84
+ op: 'push_codesep_index';
85
+ sourceLoc?: StackSourceLoc;
86
+ }
87
+ /**
88
+ * R-095 — pin `SIZE(_codePart)` against the code part's own DEPLOYED byte
89
+ * length. See `packages/runar-compiler/src/ir/stack-ir.ts` for the full
90
+ * contract; the emitter reserves a fixed-width 9-byte sequence and
91
+ * back-patches the length plus the comparison opcode after the whole script
92
+ * has been emitted.
93
+ */
94
+ export interface VerifyCodePartLenOp {
95
+ op: 'verify_code_part_len';
96
+ /** Deploy-time byte growth of the template's OP_0 placeholders. */
97
+ delta: number;
98
+ /** true -> exact equality pin; false -> lower-bound pin. */
99
+ exact: boolean;
100
+ sourceLoc?: StackSourceLoc;
101
+ }
102
+ /**
103
+ * Opaque raw byte span produced by lowering a `raw_script` ANF node.
104
+ *
105
+ * Emitted verbatim by the emit pass. Treated as a hard barrier by every
106
+ * windowed optimizer (peephole) — rules must never bridge across an
107
+ * adjacent `raw_bytes`. Stack effect is declared via `in_arity` /
108
+ * `out_arity`; the analyzer reads these to keep depth tracking sound
109
+ * without inspecting the contents.
110
+ */
111
+ export interface RawBytesOp {
112
+ op: 'raw_bytes';
113
+ bytes: Uint8Array;
114
+ in_arity: number;
115
+ out_arity: number;
116
+ sourceLoc?: StackSourceLoc;
117
+ }
118
+ export type StackOp = PushOp | DupOp | SwapOp | RollOp | PickOp | DropOp | OpcodeOp | IfOp | NipOp | OverOp | RotOp | TuckOp | PlaceholderOp | PushCodeSepIndexOp | VerifyCodePartLenOp | RawBytesOp;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Stack IR — the low-level stack-machine representation (Pass 5 output).
3
+ *
4
+ * Each method is lowered to a flat sequence of stack operations that map
5
+ * almost 1-to-1 to Bitcoin Script opcodes. This representation is
6
+ * compiler-specific (not part of the conformance boundary).
7
+ */
8
+ export {};
@@ -0,0 +1,56 @@
1
+ /**
2
+ * State-tail byte layout — the single source of truth for WHERE each
3
+ * serialized state field lives in a stateful contract's locking script.
4
+ *
5
+ * Mirrors the SDK's `serializeState` wire format exactly:
6
+ *
7
+ * <code part> OP_RETURN <field0> <field1> ... <fieldN>
8
+ *
9
+ * - bigint / int : 8 raw bytes, little-endian sign-magnitude (OP_NUM2BIN 8)
10
+ * - bool : 1 raw byte (0x00 / 0x01)
11
+ * - PubKey : 33 raw bytes - Addr / Ripemd160 : 20 raw bytes
12
+ * - Sha256 : 32 raw bytes - Point : 64 raw bytes
13
+ * - P256Point : 64 raw bytes - P384Point : 96 raw bytes
14
+ * - anything else: push-data framed (variable length)
15
+ *
16
+ * The curve-point types are raw and fixed-width because `runar-lang`'s
17
+ * `P256Point` / `P384Point` cast constructors hard-assert 64 / 96 bytes, and
18
+ * all seven COMPILERS emit them as fixed raw slices in the state tail. An SDK
19
+ * that push-data frames them instead deploys a state section one (64 -> 0x40)
20
+ * or two (96 -> OP_PUSHDATA1) bytes longer than the script's own reader
21
+ * expects, and the first spend fails with the funds locked.
22
+ *
23
+ * Fields are concatenated in `StateField.index` order. FixedArray fields
24
+ * serialize as their flattened leaves back-to-back.
25
+ *
26
+ * Lives in runar-ir-schema so the compiler (which annotates `stateFields`
27
+ * in the artifact), the SDK's state codec, and any verifier tooling share
28
+ * ONE width table instead of re-deriving it.
29
+ */
30
+ import type { StateField } from './artifact.js';
31
+ export type StateFieldEncoding = NonNullable<StateField['encoding']>;
32
+ /**
33
+ * Fixed serialized widths (bytes) for scalar state-field types.
34
+ * Types absent from this table serialize as push-data framed variable-length
35
+ * values ('pushdata').
36
+ */
37
+ export declare const STATE_FIELD_WIDTHS: Readonly<Record<string, {
38
+ readonly size: number;
39
+ readonly encoding: StateFieldEncoding;
40
+ }>>;
41
+ /**
42
+ * Annotate state fields with their byte layout (`encoding`, `byteOffset`,
43
+ * `byteLength`, `tailOffset`). Returns NEW field objects (inputs are not
44
+ * mutated), sorted by `index` — the serialization order.
45
+ *
46
+ * `byteOffset` counts from the byte AFTER the OP_RETURN separator and is
47
+ * present only while every preceding field is fixed-length. `tailOffset` is
48
+ * a NEGATIVE offset from the END of the locking script and is present only
49
+ * when the field itself and every following field is fixed-length.
50
+ */
51
+ export declare function annotateStateFieldLayout(fields: StateField[]): StateField[];
52
+ /**
53
+ * Total serialized state length in bytes (after the OP_RETURN byte), or
54
+ * undefined when any field is variable-length.
55
+ */
56
+ export declare function totalStateByteLength(fields: StateField[]): number | undefined;