@artblocks/abx-sdk 0.1.0-alpha.30 → 0.1.0-alpha.31

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.
@@ -7,7 +7,18 @@
7
7
  * never parses the reassembled program. Splitting AT an existing newline (and dropping it, because
8
8
  * the join puts it back) makes `chunks.join('\n') === source`. A 22 kB+ span with no newline is
9
9
  * refused: there is no honest split that matches the on-chain join.
10
+ *
11
+ * This module also carries the write-side counterpart to that split (`prepareSetScriptChunk` /
12
+ * `prepareRemoveLastScriptChunk`, wrapping `OnChainScript.sol`'s `setScriptChunk`/
13
+ * `removeLastScriptChunk` — contracts/src/extensions/onchain-script/OnChainScript.sol) and the
14
+ * SAFE-REPLACEMENT planning + verification pair (`planScriptReplace` / `verifyScriptReplace`) that
15
+ * `abx replace-script` is built on (packages/cli/src/ownerops.ts). Both take a small reader
16
+ * interface rather than a viem client — the same shape `resume.ts` uses — so the diff and the
17
+ * post-write verification are testable with a fake chain, no RPC, no signer.
10
18
  */
19
+ import { encodeFunctionData, hexToBytes } from 'viem';
20
+ import { seriesCodeAbi } from './abi/index.js';
21
+ const ZERO_VALUE = '0x0';
11
22
  /** SSTORE2 data-contract code limit is 24576 bytes (EIP-170) minus STOP; stay conservative. */
12
23
  export const DEFAULT_SCRIPT_CHUNK_SIZE = 22_000;
13
24
  /** The byte the on-chain generator inserts between script chunks. Must stay in lockstep with
@@ -60,4 +71,88 @@ export function joinScriptChunks(chunks) {
60
71
  const dec = new TextDecoder();
61
72
  return chunks.map((c) => dec.decode(c)).join(SCRIPT_CHUNK_JOIN);
62
73
  }
74
+ // ── writes: OnChainScript.sol's setScriptChunk / removeLastScriptChunk ────────
75
+ // No `prepare*` wrapper existed for either before this — every caller (deploy-code's setup
76
+ // multicall, its --resume leg) hand-encoded `encodeFunctionData` inline. These mirror
77
+ // `prepareSetDependency`/`prepareRemoveLastDependency` (ops.ts) exactly: same `PreparedTx` shape,
78
+ // same "one index-addressed setter + one pop-the-tail remover" split.
79
+ /** Owner writes/replaces the on-chain program chunk at `index` (`index === count` appends) —
80
+ * `OnChainScript.setScriptChunk`. Content should come from {@link splitScriptChunks} so the
81
+ * generator's newline-join reassembles the exact source. Signer must be the owner. */
82
+ export function prepareSetScriptChunk(args) {
83
+ const index = BigInt(args.index);
84
+ const bytes = (args.chunk.length - 2) / 2;
85
+ // EVM code deposit is 200 gas/byte — the same physics-backed floor the code-setup multicall
86
+ // computes for its script-chunk legs (ops.ts). Restated per-chunk here so a caller that assembles
87
+ // its own multicall (`replace-script`) can sum an honest `gasFloor` instead of trusting
88
+ // `eth_estimateGas` against a target too fresh for the estimator to see (see PreparedTx.gasFloor's
89
+ // own doc for why a wrong estimate must be DETECTED, not silently replaced).
90
+ const gasFloor = bytes > 0 ? `0x${(bytes * 200).toString(16)}` : undefined;
91
+ return {
92
+ op: 'set-script-chunk',
93
+ to: args.contract,
94
+ data: encodeFunctionData({ abi: seriesCodeAbi, functionName: 'setScriptChunk', args: [index, args.chunk] }),
95
+ value: ZERO_VALUE,
96
+ chainId: args.chainId,
97
+ summary: `Set script chunk [${index}] (${bytes} byte${bytes === 1 ? '' : 's'})`,
98
+ fields: { contract: args.contract, index: index.toString(), bytes: String(bytes) },
99
+ ...(gasFloor === undefined ? {} : { gasFloor }),
100
+ };
101
+ }
102
+ /** Remove the LAST on-chain program chunk (the list stays dense; order is load-bearing) —
103
+ * `OnChainScript.removeLastScriptChunk`. There is no "remove N": shrinking by more than one chunk
104
+ * is this call, repeated. Signer must be the owner. */
105
+ export function prepareRemoveLastScriptChunk(args) {
106
+ return {
107
+ op: 'remove-last-script-chunk',
108
+ to: args.contract,
109
+ data: encodeFunctionData({ abi: seriesCodeAbi, functionName: 'removeLastScriptChunk', args: [] }),
110
+ value: ZERO_VALUE,
111
+ chainId: args.chainId,
112
+ summary: 'Remove the last script chunk (the list stays dense)',
113
+ fields: { contract: args.contract },
114
+ };
115
+ }
116
+ /**
117
+ * Diff a replacement program's chunks against what a contract holds NOW, so `replace-script` sends
118
+ * only what actually changed. Mirrors `resume.ts`'s script-chunk leg (`planCoreLegs`) exactly —
119
+ * content, not count, decides "present" — the difference being that a resume leg is checked
120
+ * present/absent as a GROUP (the setup multicall is atomic, so partial-content-mismatch never
121
+ * legitimately happens), while a replacement is expected to change SOME indices and not others, so
122
+ * each index is diffed and reported independently.
123
+ */
124
+ export async function planScriptReplace(read, next) {
125
+ const currentCount = await read.scriptChunkCount();
126
+ const toWrite = [];
127
+ for (let i = 0; i < next.length; i++) {
128
+ const stored = i < currentCount ? await read.scriptChunk(i) : null;
129
+ if (stored !== null && stored.toLowerCase() === next[i].toLowerCase())
130
+ continue;
131
+ toWrite.push({ index: i, hex: next[i] });
132
+ }
133
+ const toRemove = Math.max(0, currentCount - next.length);
134
+ return { toWrite, toRemove, currentCount, targetCount: next.length, noop: toWrite.length === 0 && toRemove === 0 };
135
+ }
136
+ /**
137
+ * Read the completed script back from chain and confirm it reassembles EXACTLY to `expectedSource`
138
+ * — the safety property that justifies `replace-script` existing at all. A transaction not
139
+ * reverting is proof the EVM accepted each call; it is NOT proof the final program is what was
140
+ * intended (a stale RPC view, a concurrent write racing the same contract, or a bug in the ordering
141
+ * of writes-vs-removes could all leave a script that "sent fine" and reassembles to garbage). This
142
+ * is the check that turns "the multicall didn't revert" into "the program is provably correct" —
143
+ * run it BEFORE reporting success, never after.
144
+ */
145
+ export async function verifyScriptReplace(read, expectedSource) {
146
+ const chunkCount = await read.scriptChunkCount();
147
+ const chunks = [];
148
+ for (let i = 0; i < chunkCount; i++) {
149
+ const hex = await read.scriptChunk(i);
150
+ // `scriptChunkCount()` and `scriptChunk(i)` are two separate reads against (hopefully) the same
151
+ // block; a `null` here means they disagree, which is itself the failure this function exists to
152
+ // catch — report it as a verification miss rather than silently reassembling a gap.
153
+ chunks.push(hex === null ? new Uint8Array(0) : hexToBytes(hex));
154
+ }
155
+ const reassembled = joinScriptChunks(chunks);
156
+ return { ok: reassembled === expectedSource, reassembled, chunkCount };
157
+ }
63
158
  //# sourceMappingURL=script-chunks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"script-chunks.js","sourceRoot":"","sources":["../src/script-chunks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,+FAA+F;AAC/F,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD;sEACsE;AACtE,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAEtC,MAAM,EAAE,GAAG,IAAI,CAAC;AAEhB;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,YAAoB,yBAAyB;IAE7C,IAAI,SAAS,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAE9C,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACnC,IAAI,SAAS,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM;QACR,CAAC;QACD,8FAA8F;QAC9F,mCAAmC;QACnC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;gBACpB,KAAK,GAAG,CAAC,CAAC;gBACV,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,gBAAgB,SAAS,6DAA6D;gBACpF,uFAAuF;gBACvF,+EAA+E;gBAC/E,0CAA0C,CAC7C,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,gBAAgB,CAAC,MAA6B;IAC5D,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;IAC9B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAClE,CAAC"}
1
+ {"version":3,"file":"script-chunks.js","sourceRoot":"","sources":["../src/script-chunks.ts"],"names":[],"mappings":"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"}
package/dist/token.d.ts CHANGED
@@ -15,6 +15,16 @@ export declare function verifyAgainstHash(bytes: Uint8Array | string, field: Met
15
15
  * Decode a `reader` field value → `(reader, pointer)` addresses. Content is then
16
16
  * obtained on-chain by `IAbxOnChainReader(reader).read(pointer)` (an `eth_call`). The
17
17
  * reader encapsulates storage + on-chain decoding; this just unpacks the two addresses.
18
+ *
19
+ * Requires the CANONICAL `abi.encode(address reader, address pointer)` shape: exactly two
20
+ * 32-byte words, each zero-padded in its leading 12 bytes. `decodeAbiParameters` alone is
21
+ * too permissive to use as the only gate here — it happily reads an `address` out of a word
22
+ * with non-zero padding, and it ignores any bytes beyond the words a type list needs, so a
23
+ * truncated-then-repadded, trailing-garbage, or double-encoded (e.g. `abi.encode(bytes)`
24
+ * wrapping a reader pair) value can decode into a plausible but wrong address pair instead
25
+ * of failing. Because the decoded `reader` address is then `eth_call`'d directly (see
26
+ * `resolveFieldBytes` in token-api), a silent mis-decode here is a wrong-contract call, not
27
+ * a cosmetic bug — so this checks shape and padding itself before trusting the ABI decode.
18
28
  */
19
29
  export declare function decodeReader(value: Hex): {
20
30
  reader: Address;
@@ -1 +1 @@
1
- {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AAEd,OAAO,KAAK,EAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAC,MAAM,YAAY,CAAC;AAExE,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAG1F;AAED,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAExF;AAED,wBAAgB,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAEzD;AAID,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAMvD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,CAE5D;AAED,8GAA8G;AAC9G,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,GAAG,IAAI,CAKlG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAG5E;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,GAAG,CAInE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,OAAO,GAAG,GAAG,CAE/D;AAED,+FAA+F;AAC/F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAGvD"}
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AAEd,OAAO,KAAK,EAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAC,MAAM,YAAY,CAAC;AAExE,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAG1F;AAED,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAExF;AAED,wBAAgB,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAEzD;AAID,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAMvD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,CAE5D;AAED,8GAA8G;AAC9G,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,GAAG,IAAI,CAKlG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CA4B5E;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,GAAG,CAInE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,OAAO,GAAG,GAAG,CAE/D;AAED,+FAA+F;AAC/F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAGvD"}
package/dist/token.js CHANGED
@@ -39,8 +39,39 @@ export function verifyAgainstHash(bytes, field) {
39
39
  * Decode a `reader` field value → `(reader, pointer)` addresses. Content is then
40
40
  * obtained on-chain by `IAbxOnChainReader(reader).read(pointer)` (an `eth_call`). The
41
41
  * reader encapsulates storage + on-chain decoding; this just unpacks the two addresses.
42
+ *
43
+ * Requires the CANONICAL `abi.encode(address reader, address pointer)` shape: exactly two
44
+ * 32-byte words, each zero-padded in its leading 12 bytes. `decodeAbiParameters` alone is
45
+ * too permissive to use as the only gate here — it happily reads an `address` out of a word
46
+ * with non-zero padding, and it ignores any bytes beyond the words a type list needs, so a
47
+ * truncated-then-repadded, trailing-garbage, or double-encoded (e.g. `abi.encode(bytes)`
48
+ * wrapping a reader pair) value can decode into a plausible but wrong address pair instead
49
+ * of failing. Because the decoded `reader` address is then `eth_call`'d directly (see
50
+ * `resolveFieldBytes` in token-api), a silent mis-decode here is a wrong-contract call, not
51
+ * a cosmetic bug — so this checks shape and padding itself before trusting the ABI decode.
42
52
  */
43
53
  export function decodeReader(value) {
54
+ const hex = value.slice(2);
55
+ const WORD_HEX_LEN = 64; // one 32-byte ABI word, as hex chars
56
+ const EXPECTED_HEX_LEN = WORD_HEX_LEN * 2; // exactly two words: (address reader, address pointer)
57
+ if (hex.length !== EXPECTED_HEX_LEN) {
58
+ throw new Error(`decodeReader: expected exactly two 32-byte ABI words (abi.encode(address reader, address ` +
59
+ `pointer) — ${EXPECTED_HEX_LEN / 2} bytes), received ${hex.length / 2} bytes (${value}). This ` +
60
+ `looks like a truncated, trailing-byte, or double-encoded value; only output from ` +
61
+ `encodeReader() is accepted.`);
62
+ }
63
+ const ZERO_PAD = '0'.repeat(24); // the 12 zero bytes a canonical address word pads with
64
+ const words = [
65
+ ['reader', hex.slice(0, WORD_HEX_LEN)],
66
+ ['pointer', hex.slice(WORD_HEX_LEN, WORD_HEX_LEN * 2)],
67
+ ];
68
+ for (const [name, word] of words) {
69
+ if (!word.startsWith(ZERO_PAD)) {
70
+ throw new Error(`decodeReader: ${name} word is not canonically zero-padded — expected its leading 12 bytes ` +
71
+ `to be zero, received 0x${word}. A non-zero-padded address word is not produced by ` +
72
+ `encodeReader() and is rejected as a non-canonical encoding.`);
73
+ }
74
+ }
44
75
  const [reader, pointer] = decodeAbiParameters([{ type: 'address' }, { type: 'address' }], value);
45
76
  return { reader, pointer };
46
77
  }
package/dist/token.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@artblocks/abx-sdk",
3
- "version": "0.1.0-alpha.30",
3
+ "version": "0.1.0-alpha.31",
4
4
  "license": "MIT",
5
5
  "description": "Typed SDK for ABX protocol reads, deployments, operations, reconstruction, and verification.",
6
6
  "type": "module",