@artblocks/abx-sdk 0.1.0-alpha.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.
- package/LICENSE +21 -0
- package/dist/abi/generated.d.ts +6185 -0
- package/dist/abi/generated.d.ts.map +1 -0
- package/dist/abi/generated.js +28 -0
- package/dist/abi/generated.js.map +1 -0
- package/dist/abi/index.d.ts +3227 -0
- package/dist/abi/index.d.ts.map +1 -0
- package/dist/abi/index.js +38 -0
- package/dist/abi/index.js.map +1 -0
- package/dist/chains.d.ts +27 -0
- package/dist/chains.d.ts.map +1 -0
- package/dist/chains.js +71 -0
- package/dist/chains.js.map +1 -0
- package/dist/chunks.d.ts +168 -0
- package/dist/chunks.d.ts.map +1 -0
- package/dist/chunks.js +232 -0
- package/dist/chunks.js.map +1 -0
- package/dist/clients.d.ts +42 -0
- package/dist/clients.d.ts.map +1 -0
- package/dist/clients.js +90 -0
- package/dist/clients.js.map +1 -0
- package/dist/create2.d.ts +42 -0
- package/dist/create2.d.ts.map +1 -0
- package/dist/create2.js +47 -0
- package/dist/create2.js.map +1 -0
- package/dist/deploy.d.ts +192 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +231 -0
- package/dist/deploy.js.map +1 -0
- package/dist/deployments.d.ts +60 -0
- package/dist/deployments.d.ts.map +1 -0
- package/dist/deployments.js +81 -0
- package/dist/deployments.js.map +1 -0
- package/dist/deps.d.ts +109 -0
- package/dist/deps.d.ts.map +1 -0
- package/dist/deps.js +103 -0
- package/dist/deps.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +45 -0
- package/dist/env.js.map +1 -0
- package/dist/fastlz.d.ts +20 -0
- package/dist/fastlz.d.ts.map +1 -0
- package/dist/fastlz.js +123 -0
- package/dist/fastlz.js.map +1 -0
- package/dist/generator.d.ts +129 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +81 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/ops.d.ts +379 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +811 -0
- package/dist/ops.js.map +1 -0
- package/dist/probe.d.ts +30 -0
- package/dist/probe.d.ts.map +1 -0
- package/dist/probe.js +74 -0
- package/dist/probe.js.map +1 -0
- package/dist/reconstruct.d.ts +97 -0
- package/dist/reconstruct.d.ts.map +1 -0
- package/dist/reconstruct.js +597 -0
- package/dist/reconstruct.js.map +1 -0
- package/dist/spine.d.ts +110 -0
- package/dist/spine.d.ts.map +1 -0
- package/dist/spine.js +0 -0
- package/dist/spine.js.map +1 -0
- package/dist/token.d.ts +33 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +66 -0
- package/dist/token.js.map +1 -0
- package/dist/tokendata.d.ts +50 -0
- package/dist/tokendata.d.ts.map +1 -0
- package/dist/tokendata.js +178 -0
- package/dist/tokendata.js.map +1 -0
- package/dist/traits.d.ts +38 -0
- package/dist/traits.d.ts.map +1 -0
- package/dist/traits.js +92 -0
- package/dist/traits.js.map +1 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +53 -0
package/dist/ops.js
ADDED
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
import { encodeFunctionData, toHex, zeroAddress } from 'viem';
|
|
2
|
+
import { oneOfOneImageAbi, oneOfOneImageFactoryAbi, oneOfOneImageFactoryBytecode, seriesImageAbi, seriesImageFactoryAbi, seriesImageFactoryBytecode, abxMetadataRendererBytecode, abxFixedPriceMinterAbi, abxFixedPriceMinterBytecode, seriesCodeAbi, seriesCodeFactoryAbi, } from './abi/index.js';
|
|
3
|
+
import { encodeTag } from './spine.js';
|
|
4
|
+
const ZERO_VALUE = '0x0';
|
|
5
|
+
function short(addr) {
|
|
6
|
+
return addr.length > 12 ? `${addr.slice(0, 6)}…${addr.slice(-4)}` : addr;
|
|
7
|
+
}
|
|
8
|
+
/** The `Multicallable.multicall` fragment — identical on every ABX contract (the token
|
|
9
|
+
* and the chunk store both inherit Solady's `Multicallable`), so one fragment batches
|
|
10
|
+
* for any target. */
|
|
11
|
+
const MULTICALL_ABI = [
|
|
12
|
+
{
|
|
13
|
+
type: 'function',
|
|
14
|
+
name: 'multicall',
|
|
15
|
+
stateMutability: 'payable',
|
|
16
|
+
inputs: [{ name: 'data', type: 'bytes[]' }],
|
|
17
|
+
outputs: [{ name: 'results', type: 'bytes[]' }],
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Batch several ops into ONE atomic transaction via the target's
|
|
22
|
+
* `Multicallable.multicall`. This is how a human applies many owner ops — set several
|
|
23
|
+
* fields, point a renderer, lock — in a single signature instead of N transactions.
|
|
24
|
+
*
|
|
25
|
+
* Security: a multicall is *exactly* equivalent to sending each op individually from
|
|
26
|
+
* the same signer — it grants no extra authority (each subcall re-runs its own
|
|
27
|
+
* `onlyOwner`/lock checks under the preserved `msg.sender`) and it's all-or-nothing
|
|
28
|
+
* (any revert bubbles, so nothing partially applies). Enforced here:
|
|
29
|
+
* - every op MUST target the same contract — `multicall` `delegatecall`s into the
|
|
30
|
+
* contract itself, so it can only batch that contract's own functions (it is NOT a
|
|
31
|
+
* cross-contract call primitive; spanning contracts is the *account's* job — an
|
|
32
|
+
* EIP-7702 EOA, ERC-4337 account, or Safe);
|
|
33
|
+
* - every op MUST be value-free — `multicall` reverts on non-zero `msg.value` (the
|
|
34
|
+
* classic multicall double-spend guard), and no ABX op carries value anyway.
|
|
35
|
+
*/
|
|
36
|
+
export function prepareMulticall(args) {
|
|
37
|
+
const { ops } = args;
|
|
38
|
+
if (ops.length === 0)
|
|
39
|
+
throw new Error('prepareMulticall: no ops to batch');
|
|
40
|
+
const to = ops[0].to;
|
|
41
|
+
if (to === null)
|
|
42
|
+
throw new Error('prepareMulticall: cannot batch a contract-creation tx');
|
|
43
|
+
for (const o of ops) {
|
|
44
|
+
if (o.to !== to) {
|
|
45
|
+
throw new Error('prepareMulticall: all ops must target the same contract (multicall is delegatecall-to-self, not a cross-contract call)');
|
|
46
|
+
}
|
|
47
|
+
if (o.value !== ZERO_VALUE) {
|
|
48
|
+
throw new Error(`prepareMulticall: op "${o.op}" carries value; multicall must be value-free`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
op: 'multicall',
|
|
53
|
+
to,
|
|
54
|
+
data: encodeFunctionData({
|
|
55
|
+
abi: MULTICALL_ABI,
|
|
56
|
+
functionName: 'multicall',
|
|
57
|
+
args: [ops.map((o) => o.data)],
|
|
58
|
+
}),
|
|
59
|
+
value: ZERO_VALUE,
|
|
60
|
+
chainId: args.chainId ?? ops[0].chainId,
|
|
61
|
+
summary: args.summary ?? `Batch ${ops.length} ops in one tx (${ops.map((o) => o.op).join(', ')})`,
|
|
62
|
+
fields: { contract: to, batched: String(ops.length), ops: ops.map((o) => o.op).join(',') },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Collapse a list of ops into the minimal transaction set: same-target runs of ≥2 ops
|
|
67
|
+
* become one `multicall`, lone ops pass through untouched, and contract-creation txs
|
|
68
|
+
* (`to === null`, e.g. a factory/renderer/store deploy) are never folded. Order is
|
|
69
|
+
* preserved — important when a later op depends on an earlier one's effect — so a run is
|
|
70
|
+
* only merged while the target stays the same. This is what turns "6 owner edits" into
|
|
71
|
+
* "1 transaction" for the UX, while staying honest about what genuinely needs its own tx.
|
|
72
|
+
*/
|
|
73
|
+
export function batchOps(ops) {
|
|
74
|
+
const out = [];
|
|
75
|
+
let run = [];
|
|
76
|
+
const flush = () => {
|
|
77
|
+
if (run.length === 1)
|
|
78
|
+
out.push(run[0]);
|
|
79
|
+
else if (run.length > 1)
|
|
80
|
+
out.push(prepareMulticall({ ops: run }));
|
|
81
|
+
run = [];
|
|
82
|
+
};
|
|
83
|
+
for (const op of ops) {
|
|
84
|
+
const mergeable = op.to !== null && op.value === ZERO_VALUE;
|
|
85
|
+
if (mergeable && run.length > 0 && run[0].to === op.to) {
|
|
86
|
+
run.push(op);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
flush();
|
|
90
|
+
run = mergeable ? [op] : [];
|
|
91
|
+
if (!mergeable)
|
|
92
|
+
out.push(op); // standalone (creation or value-bearing)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
flush();
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
/** Transfer a token to a new holder (a sale/gift settlement). Signer must be `from`. */
|
|
99
|
+
export function prepareTransfer(args) {
|
|
100
|
+
const id = BigInt(args.tokenId);
|
|
101
|
+
return {
|
|
102
|
+
op: 'transfer',
|
|
103
|
+
to: args.contract,
|
|
104
|
+
data: encodeFunctionData({
|
|
105
|
+
abi: oneOfOneImageAbi,
|
|
106
|
+
functionName: 'safeTransferFrom',
|
|
107
|
+
args: [args.from, args.to, id],
|
|
108
|
+
}),
|
|
109
|
+
value: ZERO_VALUE,
|
|
110
|
+
chainId: args.chainId,
|
|
111
|
+
summary: `Transfer token #${id} → ${short(args.to)}`,
|
|
112
|
+
fields: { contract: args.contract, from: args.from, to: args.to, tokenId: id.toString() },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Mint the single token (id 0) to `to`. Owner-only and one-shot — for deferred
|
|
117
|
+
* issuance: deploy first (warm the resolver at the known address), then mint, or
|
|
118
|
+
* mint straight to a buyer on a primary sale. Signer must be the owner.
|
|
119
|
+
*/
|
|
120
|
+
export function prepareMint(args) {
|
|
121
|
+
return {
|
|
122
|
+
op: 'mint',
|
|
123
|
+
to: args.contract,
|
|
124
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'mint', args: [args.to] }),
|
|
125
|
+
value: ZERO_VALUE,
|
|
126
|
+
chainId: args.chainId,
|
|
127
|
+
// `mint(address)` issues the NEXT sequential token — id #0 for a 1/1, but the next unminted id
|
|
128
|
+
// for a Series (chain-determined at mint time). Don't hardcode "#0" (misleads on a Series where
|
|
129
|
+
// #0 is already minted); say "next" — correct for both.
|
|
130
|
+
summary: `Mint the next token → ${short(args.to)}`,
|
|
131
|
+
fields: { contract: args.contract, to: args.to, token: 'next in order' },
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Re-point a token's resolver BASE (move the resolver). The per-token pointer is derived
|
|
135
|
+
* on-chain as `{base}/{chainId}/{address}/{tokenId}`. Affects every token without an
|
|
136
|
+
* override. Signer must be the owner. */
|
|
137
|
+
export function prepareSetTokenURIBase(args) {
|
|
138
|
+
return {
|
|
139
|
+
op: 'set-token-uri-base',
|
|
140
|
+
to: args.contract,
|
|
141
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'setTokenURIBase', args: [args.base] }),
|
|
142
|
+
value: ZERO_VALUE,
|
|
143
|
+
chainId: args.chainId,
|
|
144
|
+
summary: `Set tokenURI base → ${args.base}`,
|
|
145
|
+
fields: { contract: args.contract, tokenURIBase: args.base },
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/** Set (or clear, with "") a per-token full-URI override — a fixed locator (e.g. `ipfs://`)
|
|
149
|
+
* that wins over the derived base path for one token. Signer must be the owner. */
|
|
150
|
+
export function prepareSetTokenURIOverride(args) {
|
|
151
|
+
return {
|
|
152
|
+
op: 'set-token-uri-override',
|
|
153
|
+
to: args.contract,
|
|
154
|
+
data: encodeFunctionData({
|
|
155
|
+
abi: oneOfOneImageAbi,
|
|
156
|
+
functionName: 'setTokenURIOverride',
|
|
157
|
+
args: [BigInt(args.tokenId), args.uri],
|
|
158
|
+
}),
|
|
159
|
+
value: ZERO_VALUE,
|
|
160
|
+
chainId: args.chainId,
|
|
161
|
+
summary: args.uri
|
|
162
|
+
? `Set tokenURI override #${args.tokenId} → ${args.uri}`
|
|
163
|
+
: `Clear tokenURI override #${args.tokenId}`,
|
|
164
|
+
fields: { contract: args.contract, tokenId: String(args.tokenId), tokenURIOverride: args.uri },
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** Re-point the collection (ERC-7572) resolver BASE; derived on-chain as
|
|
168
|
+
* `{base}/{chainId}/{address}`. Signer must be the owner. */
|
|
169
|
+
export function prepareSetContractURIBase(args) {
|
|
170
|
+
return {
|
|
171
|
+
op: 'set-contract-uri-base',
|
|
172
|
+
to: args.contract,
|
|
173
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'setContractURIBase', args: [args.base] }),
|
|
174
|
+
value: ZERO_VALUE,
|
|
175
|
+
chainId: args.chainId,
|
|
176
|
+
summary: `Set contractURI base → ${args.base}`,
|
|
177
|
+
fields: { contract: args.contract, contractURIBase: args.base },
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/** Set (or clear, with "") the collection's full-URI override — a fixed locator that wins
|
|
181
|
+
* over the derived base. Signer must be the owner. */
|
|
182
|
+
export function prepareSetContractURIOverride(args) {
|
|
183
|
+
return {
|
|
184
|
+
op: 'set-contract-uri-override',
|
|
185
|
+
to: args.contract,
|
|
186
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'setContractURIOverride', args: [args.uri] }),
|
|
187
|
+
value: ZERO_VALUE,
|
|
188
|
+
chainId: args.chainId,
|
|
189
|
+
summary: args.uri ? `Set contractURI override → ${args.uri}` : 'Clear contractURI override',
|
|
190
|
+
fields: { contract: args.contract, contractURIOverride: args.uri },
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Set (or clear) the token's on-chain URI renderer — the toggle between off-chain
|
|
195
|
+
* resolution (`renderer == 0x0`, use the stored `tokenURI`) and on-chain resolution
|
|
196
|
+
* (a non-zero `IAbxMetadataRenderer` that assembles the JSON from on-chain fields).
|
|
197
|
+
* Signer must be the owner; reverts if the URI config is locked.
|
|
198
|
+
*/
|
|
199
|
+
export function prepareSetTokenURIRenderer(args) {
|
|
200
|
+
const onChain = args.renderer !== zeroAddress;
|
|
201
|
+
return {
|
|
202
|
+
op: 'set-token-uri-renderer',
|
|
203
|
+
to: args.contract,
|
|
204
|
+
data: encodeFunctionData({
|
|
205
|
+
abi: oneOfOneImageAbi,
|
|
206
|
+
functionName: 'setTokenURIRenderer',
|
|
207
|
+
args: [args.renderer],
|
|
208
|
+
}),
|
|
209
|
+
value: ZERO_VALUE,
|
|
210
|
+
chainId: args.chainId,
|
|
211
|
+
summary: onChain ? `Resolve tokenURI on-chain via ${short(args.renderer)}` : 'Resolve tokenURI off-chain (clear renderer)',
|
|
212
|
+
fields: { contract: args.contract, renderer: args.renderer },
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/** Set (or clear) the collection's on-chain URI renderer. Signer must be the owner. */
|
|
216
|
+
export function prepareSetContractURIRenderer(args) {
|
|
217
|
+
const onChain = args.renderer !== zeroAddress;
|
|
218
|
+
return {
|
|
219
|
+
op: 'set-contract-uri-renderer',
|
|
220
|
+
to: args.contract,
|
|
221
|
+
data: encodeFunctionData({
|
|
222
|
+
abi: oneOfOneImageAbi,
|
|
223
|
+
functionName: 'setContractURIRenderer',
|
|
224
|
+
args: [args.renderer],
|
|
225
|
+
}),
|
|
226
|
+
value: ZERO_VALUE,
|
|
227
|
+
chainId: args.chainId,
|
|
228
|
+
summary: onChain ? `Resolve contractURI on-chain via ${short(args.renderer)}` : 'Resolve contractURI off-chain (clear renderer)',
|
|
229
|
+
fields: { contract: args.contract, renderer: args.renderer },
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/** Freeze the token-URI config (pointer + renderer) forever. Irreversible. Signer = owner. */
|
|
233
|
+
export function prepareLockTokenURI(args) {
|
|
234
|
+
return {
|
|
235
|
+
op: 'lock-token-uri',
|
|
236
|
+
to: args.contract,
|
|
237
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'lockTokenURI', args: [] }),
|
|
238
|
+
value: ZERO_VALUE,
|
|
239
|
+
chainId: args.chainId,
|
|
240
|
+
summary: 'Freeze the tokenURI config (pointer + renderer) — permanent',
|
|
241
|
+
fields: { contract: args.contract },
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/** Freeze the collection-URI config forever. Irreversible. Signer = owner. */
|
|
245
|
+
export function prepareLockContractURI(args) {
|
|
246
|
+
return {
|
|
247
|
+
op: 'lock-contract-uri',
|
|
248
|
+
to: args.contract,
|
|
249
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'lockContractURI', args: [] }),
|
|
250
|
+
value: ZERO_VALUE,
|
|
251
|
+
chainId: args.chainId,
|
|
252
|
+
summary: 'Freeze the contractURI config (pointer + renderer) — permanent',
|
|
253
|
+
fields: { contract: args.contract },
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/** Set the contract-wide default royalty. Signer must be the owner. */
|
|
257
|
+
export function prepareSetRoyalty(args) {
|
|
258
|
+
if (args.bps < 0 || args.bps > 10000)
|
|
259
|
+
throw new Error(`royalty bps out of range (0–10000): ${args.bps}`);
|
|
260
|
+
return {
|
|
261
|
+
op: 'set-royalty',
|
|
262
|
+
to: args.contract,
|
|
263
|
+
data: encodeFunctionData({
|
|
264
|
+
abi: oneOfOneImageAbi,
|
|
265
|
+
functionName: 'setDefaultRoyalty',
|
|
266
|
+
args: [args.receiver, args.bps],
|
|
267
|
+
}),
|
|
268
|
+
value: ZERO_VALUE,
|
|
269
|
+
chainId: args.chainId,
|
|
270
|
+
summary: `Set royalty → ${(args.bps / 100).toFixed(2)}% to ${short(args.receiver)}`,
|
|
271
|
+
fields: { contract: args.contract, receiver: args.receiver, bps: String(args.bps) },
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Set/replace an on-chain metadata field for a token. `field` is what (e.g. "image",
|
|
276
|
+
* "description"), `representation` is how it's carried (e.g. "inline", "keccak256",
|
|
277
|
+
* "arweave"), `value` is the bytes. Reverts once the field is locked. Signer = owner.
|
|
278
|
+
*/
|
|
279
|
+
export function prepareSetTokenField(args) {
|
|
280
|
+
const id = BigInt(args.tokenId);
|
|
281
|
+
return {
|
|
282
|
+
op: 'set-field',
|
|
283
|
+
to: args.contract,
|
|
284
|
+
data: encodeFunctionData({
|
|
285
|
+
abi: oneOfOneImageAbi,
|
|
286
|
+
functionName: 'setTokenField',
|
|
287
|
+
args: [id, encodeTag(args.field), encodeTag(args.representation), args.value],
|
|
288
|
+
}),
|
|
289
|
+
value: ZERO_VALUE,
|
|
290
|
+
chainId: args.chainId,
|
|
291
|
+
summary: `Set on-chain ${args.field} (${args.representation}) for token #${id}`,
|
|
292
|
+
fields: { contract: args.contract, tokenId: id.toString(), field: args.field, representation: args.representation, value: args.value },
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/** Freeze a token field forever, across all its representations (irreversible). Signer = owner. */
|
|
296
|
+
export function prepareLockTokenField(args) {
|
|
297
|
+
const id = BigInt(args.tokenId);
|
|
298
|
+
return {
|
|
299
|
+
op: 'lock-field',
|
|
300
|
+
to: args.contract,
|
|
301
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'lockTokenField', args: [id, encodeTag(args.field)] }),
|
|
302
|
+
value: ZERO_VALUE,
|
|
303
|
+
chainId: args.chainId,
|
|
304
|
+
summary: `Lock token #${id} field "${args.field}" — permanent`,
|
|
305
|
+
fields: { contract: args.contract, tokenId: id.toString(), field: args.field },
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
/** Set/replace a collection (contract-wide) on-chain metadata field. Signer = owner. */
|
|
309
|
+
export function prepareSetContractField(args) {
|
|
310
|
+
return {
|
|
311
|
+
op: 'set-collection-field',
|
|
312
|
+
to: args.contract,
|
|
313
|
+
data: encodeFunctionData({
|
|
314
|
+
abi: oneOfOneImageAbi,
|
|
315
|
+
functionName: 'setContractField',
|
|
316
|
+
args: [encodeTag(args.field), encodeTag(args.representation), args.value],
|
|
317
|
+
}),
|
|
318
|
+
value: ZERO_VALUE,
|
|
319
|
+
chainId: args.chainId,
|
|
320
|
+
summary: `Set on-chain collection ${args.field} (${args.representation})`,
|
|
321
|
+
fields: { contract: args.contract, field: args.field, representation: args.representation, value: args.value },
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/** Freeze a collection field forever (irreversible). Signer = owner. */
|
|
325
|
+
export function prepareLockContractField(args) {
|
|
326
|
+
return {
|
|
327
|
+
op: 'lock-collection-field',
|
|
328
|
+
to: args.contract,
|
|
329
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'lockContractField', args: [encodeTag(args.field)] }),
|
|
330
|
+
value: ZERO_VALUE,
|
|
331
|
+
chainId: args.chainId,
|
|
332
|
+
summary: `Lock collection field "${args.field}" — permanent`,
|
|
333
|
+
fields: { contract: args.contract, field: args.field },
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/** Transfer contract ownership (admin). Signer must be the current owner. */
|
|
337
|
+
export function prepareTransferOwnership(args) {
|
|
338
|
+
return {
|
|
339
|
+
op: 'set-admin',
|
|
340
|
+
to: args.contract,
|
|
341
|
+
data: encodeFunctionData({ abi: oneOfOneImageAbi, functionName: 'transferOwnership', args: [args.newOwner] }),
|
|
342
|
+
value: ZERO_VALUE,
|
|
343
|
+
chainId: args.chainId,
|
|
344
|
+
summary: `Transfer contract ownership → ${short(args.newOwner)}`,
|
|
345
|
+
fields: { contract: args.contract, newOwner: args.newOwner },
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* The unsigned form of the genesis deploy: a `deployDeterministic(params, salt)`
|
|
350
|
+
* call on the factory. The clone address is deterministic in (factory, salt) — a
|
|
351
|
+
* pure function of the salt, independent of the signer — so the URIs in `params`
|
|
352
|
+
* can be baked to point at the predicted address before anyone connects (see
|
|
353
|
+
* `predictClone`). `params.mintTo` decides whether the token mints in this tx or
|
|
354
|
+
* is deferred to a later `mint`. Building the URIs is the caller's job.
|
|
355
|
+
*/
|
|
356
|
+
export function prepareDeployOneOfOne(args) {
|
|
357
|
+
return {
|
|
358
|
+
op: 'deploy',
|
|
359
|
+
to: args.factory,
|
|
360
|
+
data: encodeFunctionData({
|
|
361
|
+
abi: oneOfOneImageFactoryAbi,
|
|
362
|
+
functionName: 'deployDeterministic',
|
|
363
|
+
args: [args.params, args.salt],
|
|
364
|
+
}),
|
|
365
|
+
value: ZERO_VALUE,
|
|
366
|
+
chainId: args.chainId,
|
|
367
|
+
summary: `Deploy "${args.params.name}" → ${args.clone}`,
|
|
368
|
+
fields: {
|
|
369
|
+
factory: args.factory,
|
|
370
|
+
clone: args.clone,
|
|
371
|
+
name: args.params.name,
|
|
372
|
+
symbol: args.params.symbol,
|
|
373
|
+
owner: args.params.owner,
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/** The unsigned form of the factory (trust-anchor) deploy — a contract creation. */
|
|
378
|
+
export function prepareDeployFactory(args) {
|
|
379
|
+
return {
|
|
380
|
+
op: 'deploy-factory',
|
|
381
|
+
to: null,
|
|
382
|
+
data: oneOfOneImageFactoryBytecode,
|
|
383
|
+
value: ZERO_VALUE,
|
|
384
|
+
chainId: args.chainId,
|
|
385
|
+
summary: 'Deploy the canonical clone factory (trust anchor)',
|
|
386
|
+
fields: {},
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
/** The unsigned form of the canonical metadata-renderer deploy — a contract creation. */
|
|
390
|
+
export function prepareDeployRenderer(args) {
|
|
391
|
+
return {
|
|
392
|
+
op: 'deploy-renderer',
|
|
393
|
+
to: null,
|
|
394
|
+
data: abxMetadataRendererBytecode,
|
|
395
|
+
value: ZERO_VALUE,
|
|
396
|
+
chainId: args.chainId,
|
|
397
|
+
summary: 'Deploy the canonical on-chain metadata renderer',
|
|
398
|
+
fields: {},
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
// ── Series (multi-token) ops ──────────────────────────────────────────────────
|
|
402
|
+
// Token ids are sequential and a token's metadata is its token id (no decoupling). Signer
|
|
403
|
+
// must be the owner or an authorized minter for the mint ops; owner-only for the config ops.
|
|
404
|
+
/**
|
|
405
|
+
* Mint the next sequential token on a Series (its metadata is its token id). Reverts when
|
|
406
|
+
* sold out.
|
|
407
|
+
*/
|
|
408
|
+
export function prepareSeriesMint(args) {
|
|
409
|
+
return {
|
|
410
|
+
op: 'mint',
|
|
411
|
+
to: args.contract,
|
|
412
|
+
data: encodeFunctionData({ abi: seriesImageAbi, functionName: 'mint', args: [args.to] }),
|
|
413
|
+
value: ZERO_VALUE,
|
|
414
|
+
chainId: args.chainId,
|
|
415
|
+
summary: `Mint next token (in order) → ${short(args.to)}`,
|
|
416
|
+
fields: { contract: args.contract, to: args.to },
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/** Mint `count` Series tokens in order in one tx — N individual `Transfer`s. */
|
|
420
|
+
export function prepareSeriesMintMany(args) {
|
|
421
|
+
const n = Number(args.count);
|
|
422
|
+
return {
|
|
423
|
+
op: 'mint-many',
|
|
424
|
+
to: args.contract,
|
|
425
|
+
data: encodeFunctionData({
|
|
426
|
+
abi: seriesImageAbi,
|
|
427
|
+
functionName: 'mintMany',
|
|
428
|
+
args: [args.to, BigInt(args.count)],
|
|
429
|
+
}),
|
|
430
|
+
value: ZERO_VALUE,
|
|
431
|
+
chainId: args.chainId,
|
|
432
|
+
summary: `Mint ${n} tokens (in order) → ${short(args.to)}`,
|
|
433
|
+
fields: { contract: args.contract, to: args.to, count: String(n) },
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Set (or clear, with `0x0`) the single authorized minter. Setting a new minter atomically
|
|
438
|
+
* replaces any previous one; `0x0` clears it (back to owner-only). Signer must be the owner.
|
|
439
|
+
*/
|
|
440
|
+
export function prepareSetMinter(args) {
|
|
441
|
+
const clearing = args.minter === zeroAddress;
|
|
442
|
+
return {
|
|
443
|
+
op: 'set-minter',
|
|
444
|
+
to: args.contract,
|
|
445
|
+
data: encodeFunctionData({ abi: seriesImageAbi, functionName: 'setMinter', args: [args.minter] }),
|
|
446
|
+
value: ZERO_VALUE,
|
|
447
|
+
chainId: args.chainId,
|
|
448
|
+
summary: clearing ? 'Clear the authorized minter (owner-only)' : `Set authorized minter → ${short(args.minter)}`,
|
|
449
|
+
fields: { contract: args.contract, minter: args.minter },
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
/** Lower the supply cap (monotonic — never raises, never below the minted count). Signer = owner. */
|
|
453
|
+
export function prepareSetMaxInvocations(args) {
|
|
454
|
+
const max = BigInt(args.maxInvocations);
|
|
455
|
+
return {
|
|
456
|
+
op: 'set-max-invocations',
|
|
457
|
+
to: args.contract,
|
|
458
|
+
data: encodeFunctionData({ abi: seriesImageAbi, functionName: 'setMaxInvocations', args: [max] }),
|
|
459
|
+
value: ZERO_VALUE,
|
|
460
|
+
chainId: args.chainId,
|
|
461
|
+
summary: `Set max invocations → ${max}`,
|
|
462
|
+
fields: { contract: args.contract, maxInvocations: max.toString() },
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
/** Pause or unpause minting. While paused only the owner may mint (reserves/config); unpausing
|
|
466
|
+
* opens it to the authorized minter. Signer must be the owner. */
|
|
467
|
+
export function prepareSetPaused(args) {
|
|
468
|
+
return {
|
|
469
|
+
op: 'set-paused',
|
|
470
|
+
to: args.contract,
|
|
471
|
+
data: encodeFunctionData({ abi: seriesImageAbi, functionName: 'setPaused', args: [args.paused] }),
|
|
472
|
+
value: ZERO_VALUE,
|
|
473
|
+
chainId: args.chainId,
|
|
474
|
+
summary: args.paused ? 'Pause minting (owner-only until unpaused)' : 'Unpause minting (open to the minter)',
|
|
475
|
+
fields: { contract: args.contract, paused: String(args.paused) },
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
/** Set (or clear, with `0x0`) the primary-sale payout destination. Signer = owner. */
|
|
479
|
+
export function prepareSetPrimaryPayee(args) {
|
|
480
|
+
return {
|
|
481
|
+
op: 'set-primary-payee',
|
|
482
|
+
to: args.contract,
|
|
483
|
+
data: encodeFunctionData({ abi: seriesImageAbi, functionName: 'setPrimaryPayee', args: [args.payee] }),
|
|
484
|
+
value: ZERO_VALUE,
|
|
485
|
+
chainId: args.chainId,
|
|
486
|
+
summary: args.payee !== zeroAddress ? `Set primary payee → ${short(args.payee)}` : 'Clear primary payee',
|
|
487
|
+
fields: { contract: args.contract, primaryPayee: args.payee },
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
/** The unsigned form of a Series genesis deploy — `deployDeterministic(params, salt)` on the Series factory. */
|
|
491
|
+
export function prepareDeploySeries(args) {
|
|
492
|
+
return {
|
|
493
|
+
op: 'deploy-series',
|
|
494
|
+
to: args.factory,
|
|
495
|
+
data: encodeFunctionData({
|
|
496
|
+
abi: seriesImageFactoryAbi,
|
|
497
|
+
functionName: 'deployDeterministic',
|
|
498
|
+
args: [args.params, args.salt],
|
|
499
|
+
}),
|
|
500
|
+
value: ZERO_VALUE,
|
|
501
|
+
chainId: args.chainId,
|
|
502
|
+
summary: `Deploy Series "${args.params.name}" (${String(args.params.maxInvocations)} max) → ${args.clone}`,
|
|
503
|
+
fields: {
|
|
504
|
+
factory: args.factory,
|
|
505
|
+
clone: args.clone,
|
|
506
|
+
name: args.params.name,
|
|
507
|
+
symbol: args.params.symbol,
|
|
508
|
+
owner: args.params.owner,
|
|
509
|
+
maxInvocations: String(args.params.maxInvocations),
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
/** The unsigned form of the Series factory (trust-anchor) deploy — a contract creation. */
|
|
514
|
+
export function prepareDeploySeriesFactory(args) {
|
|
515
|
+
return {
|
|
516
|
+
op: 'deploy-series-factory',
|
|
517
|
+
to: null,
|
|
518
|
+
data: seriesImageFactoryBytecode,
|
|
519
|
+
value: ZERO_VALUE,
|
|
520
|
+
chainId: args.chainId,
|
|
521
|
+
summary: 'Deploy the canonical Series clone factory (trust anchor)',
|
|
522
|
+
fields: {},
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
// ── Fixed-price minter (the Minter spine) ─────────────────────────────────────
|
|
526
|
+
// The minter is a shared, ownerless, multi-tenant singleton. `configure` defers to the
|
|
527
|
+
// token owner; `purchase`/`purchaseTo` are public. See specs/protocol/minter-spine.md.
|
|
528
|
+
/**
|
|
529
|
+
* Set/update a project's fixed-price sale on the shared minter. Signer must be the ABX
|
|
530
|
+
* token's owner. `paymentToken == 0x0` prices the sale in ETH; otherwise it's that ERC-20.
|
|
531
|
+
* `price` is raw units per token; `allocation` is the max this minter may sell (its budget,
|
|
532
|
+
* distinct from the token's own `maxInvocations` cap). Enabling the sale is separate from
|
|
533
|
+
* granting mint rights — also `prepareSetMinter(token, minter)`.
|
|
534
|
+
*/
|
|
535
|
+
export function prepareConfigureSale(args) {
|
|
536
|
+
const paymentToken = args.paymentToken ?? zeroAddress;
|
|
537
|
+
const price = BigInt(args.price);
|
|
538
|
+
const allocation = BigInt(args.allocation);
|
|
539
|
+
const isEth = paymentToken === zeroAddress;
|
|
540
|
+
return {
|
|
541
|
+
op: 'configure-sale',
|
|
542
|
+
to: args.minter,
|
|
543
|
+
data: encodeFunctionData({
|
|
544
|
+
abi: abxFixedPriceMinterAbi,
|
|
545
|
+
functionName: 'configure',
|
|
546
|
+
args: [args.token, paymentToken, price, allocation],
|
|
547
|
+
}),
|
|
548
|
+
value: ZERO_VALUE,
|
|
549
|
+
chainId: args.chainId,
|
|
550
|
+
summary: `Configure sale: ${price} ${isEth ? 'wei' : `of ${short(paymentToken)}`}/token, allocation ${allocation}`,
|
|
551
|
+
fields: {
|
|
552
|
+
minter: args.minter,
|
|
553
|
+
token: args.token,
|
|
554
|
+
paymentToken,
|
|
555
|
+
price: price.toString(),
|
|
556
|
+
allocation: allocation.toString(),
|
|
557
|
+
},
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Buy one token from the shared minter. `to` omitted → minted to the signer (`purchase`);
|
|
562
|
+
* `to` set → minted to that address (`purchaseTo`). `value` is the ETH to attach (equal to
|
|
563
|
+
* the sale price for an ETH sale; `0` for an ERC-20 sale, where the buyer must have approved
|
|
564
|
+
* the minter to pull `price` beforehand). Public — no owner rights needed.
|
|
565
|
+
*/
|
|
566
|
+
export function preparePurchase(args) {
|
|
567
|
+
const value = BigInt(args.value ?? 0n);
|
|
568
|
+
const toRecipient = args.to && args.to !== zeroAddress;
|
|
569
|
+
return {
|
|
570
|
+
op: 'purchase',
|
|
571
|
+
to: args.minter,
|
|
572
|
+
data: toRecipient
|
|
573
|
+
? encodeFunctionData({ abi: abxFixedPriceMinterAbi, functionName: 'purchaseTo', args: [args.token, args.to] })
|
|
574
|
+
: encodeFunctionData({ abi: abxFixedPriceMinterAbi, functionName: 'purchase', args: [args.token] }),
|
|
575
|
+
value: value > 0n ? toHex(value) : ZERO_VALUE,
|
|
576
|
+
chainId: args.chainId,
|
|
577
|
+
summary: toRecipient
|
|
578
|
+
? `Buy 1 token → ${short(args.to)}${value > 0n ? ` for ${value} wei` : ''}`
|
|
579
|
+
: `Buy 1 token${value > 0n ? ` for ${value} wei` : ''}`,
|
|
580
|
+
fields: { minter: args.minter, token: args.token, to: args.to ?? '(sender)', value: value.toString() },
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
/** The unsigned form of the shared fixed-price minter deploy — a contract creation. */
|
|
584
|
+
export function prepareDeployFixedPriceMinter(args) {
|
|
585
|
+
return {
|
|
586
|
+
op: 'deploy-fixed-price-minter',
|
|
587
|
+
to: null,
|
|
588
|
+
data: abxFixedPriceMinterBytecode,
|
|
589
|
+
value: ZERO_VALUE,
|
|
590
|
+
chainId: args.chainId,
|
|
591
|
+
summary: 'Deploy the canonical fixed-price minter (shared, ownerless)',
|
|
592
|
+
fields: {},
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
/** Deterministic deploy of a {SeriesCode} clone — the code-project factory op. */
|
|
596
|
+
export function prepareDeploySeriesCode(args) {
|
|
597
|
+
return {
|
|
598
|
+
op: 'deploy-code',
|
|
599
|
+
to: args.factory,
|
|
600
|
+
data: encodeFunctionData({
|
|
601
|
+
abi: seriesCodeFactoryAbi,
|
|
602
|
+
functionName: 'deployDeterministic',
|
|
603
|
+
args: [args.params, args.salt],
|
|
604
|
+
}),
|
|
605
|
+
value: ZERO_VALUE,
|
|
606
|
+
chainId: args.chainId,
|
|
607
|
+
summary: `Deploy code project "${args.params.name}" (${String(args.params.maxInvocations)} max) → ${args.clone}`,
|
|
608
|
+
fields: {
|
|
609
|
+
factory: args.factory,
|
|
610
|
+
clone: args.clone,
|
|
611
|
+
name: args.params.name,
|
|
612
|
+
symbol: args.params.symbol,
|
|
613
|
+
owner: args.params.owner,
|
|
614
|
+
seedSource: args.params.seedSource,
|
|
615
|
+
maxInvocations: String(args.params.maxInvocations),
|
|
616
|
+
},
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
/** The code project's post-deploy setup: script chunks + PostParam schemas (+ dependency
|
|
620
|
+
* declarations, when the project has any; + the on-chain-URI legs under `--onchain-uri`),
|
|
621
|
+
* one atomic multicall. */
|
|
622
|
+
export function prepareCodeSetup(args) {
|
|
623
|
+
const deps = args.deps ?? [];
|
|
624
|
+
return {
|
|
625
|
+
op: 'code-setup',
|
|
626
|
+
to: args.contract,
|
|
627
|
+
data: encodeFunctionData({ abi: seriesCodeAbi, functionName: 'multicall', args: [args.calls] }),
|
|
628
|
+
value: ZERO_VALUE,
|
|
629
|
+
chainId: args.chainId,
|
|
630
|
+
// Human, and ACCURATE to what THIS multicall actually contains — a creator signs it in their
|
|
631
|
+
// wallet. (The old label was protocol jargon AND wrong for the renderer-only lane: it always
|
|
632
|
+
// claimed a "generator animation field" even when no generator/animation was in the tx.)
|
|
633
|
+
summary: (() => {
|
|
634
|
+
const parts = [];
|
|
635
|
+
if (args.chunkCount)
|
|
636
|
+
parts.push(`store your program (${args.chunkCount} on-chain chunk${args.chunkCount === 1 ? '' : 's'})`);
|
|
637
|
+
if (args.schemaKeys.length)
|
|
638
|
+
parts.push(`enable collector-set parameter${args.schemaKeys.length === 1 ? '' : 's'}: ${args.schemaKeys.join(', ')}`);
|
|
639
|
+
if (deps.length)
|
|
640
|
+
parts.push(`declare ${deps.length} dependenc${deps.length === 1 ? 'y' : 'ies'}: ${deps.join(', ')}`);
|
|
641
|
+
if (args.onchainUri)
|
|
642
|
+
parts.push('wire on-chain metadata resolution (the animation + URI renderers)');
|
|
643
|
+
return parts.length ? `Finish setup — ${parts.join('; ')}` : 'Finish setup';
|
|
644
|
+
})(),
|
|
645
|
+
fields: {
|
|
646
|
+
contract: args.contract,
|
|
647
|
+
scriptChunks: String(args.chunkCount),
|
|
648
|
+
schemas: args.schemaKeys.join(',') || '—',
|
|
649
|
+
...(deps.length ? { dependencies: deps.join(',') } : {}),
|
|
650
|
+
...(args.onchainUri ? { onchainUri: 'yes' } : {}),
|
|
651
|
+
},
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
// ── dependencies (Dependencies extension — code projects) ─────────────────────
|
|
655
|
+
// The ordered library declarations of a template-mode code project (index 0 = the runtime,
|
|
656
|
+
// by convention). Owner-only; the list stays dense (set at index ≤ count, remove only the
|
|
657
|
+
// last). See specs/protocol/dependency-registry.md + src/deps.ts for the ref encoding.
|
|
658
|
+
/** Set/replace the dependency at `index` — `resolution` 0 = Registry (`ref` = readable
|
|
659
|
+
* `name@version` bytes32), 1 = OnChain (`ref` = a data-contract address, left-aligned).
|
|
660
|
+
* Encode the pair with `parseDependencyRef`. Signer must be the owner. */
|
|
661
|
+
export function prepareSetDependency(args) {
|
|
662
|
+
const index = BigInt(args.index);
|
|
663
|
+
const kind = args.resolution === 1 ? 'on-chain' : 'registry';
|
|
664
|
+
const shown = args.display ?? args.ref;
|
|
665
|
+
return {
|
|
666
|
+
op: 'set-dependency',
|
|
667
|
+
to: args.contract,
|
|
668
|
+
data: encodeFunctionData({
|
|
669
|
+
abi: seriesCodeAbi,
|
|
670
|
+
functionName: 'setDependency',
|
|
671
|
+
args: [index, args.resolution, args.ref],
|
|
672
|
+
}),
|
|
673
|
+
value: ZERO_VALUE,
|
|
674
|
+
chainId: args.chainId,
|
|
675
|
+
summary: `Set dependency [${index}] → ${shown} (${kind})${index === 0n ? ' — index 0 = the runtime' : ''}`,
|
|
676
|
+
fields: { contract: args.contract, index: index.toString(), resolution: kind, ref: shown },
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
/** Remove the LAST dependency (the list stays dense — order is load-bearing). Signer = owner. */
|
|
680
|
+
export function prepareRemoveLastDependency(args) {
|
|
681
|
+
return {
|
|
682
|
+
op: 'remove-last-dependency',
|
|
683
|
+
to: args.contract,
|
|
684
|
+
data: encodeFunctionData({ abi: seriesCodeAbi, functionName: 'removeLastDependency', args: [] }),
|
|
685
|
+
value: ZERO_VALUE,
|
|
686
|
+
chainId: args.chainId,
|
|
687
|
+
summary: 'Remove the last dependency (the list stays dense)',
|
|
688
|
+
fields: { contract: args.contract },
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
/** Set (or clear, with `0x0`) the soft, non-validating dependency registry pointer —
|
|
692
|
+
* what `name@version` refs resolve through. Signer must be the owner. */
|
|
693
|
+
export function prepareSetDependencyRegistry(args) {
|
|
694
|
+
const clearing = args.registry === zeroAddress;
|
|
695
|
+
return {
|
|
696
|
+
op: 'set-dependency-registry',
|
|
697
|
+
to: args.contract,
|
|
698
|
+
data: encodeFunctionData({ abi: seriesCodeAbi, functionName: 'setDependencyRegistry', args: [args.registry] }),
|
|
699
|
+
value: ZERO_VALUE,
|
|
700
|
+
chainId: args.chainId,
|
|
701
|
+
summary: clearing
|
|
702
|
+
? 'Clear the dependency registry pointer (soft — refs stay declared)'
|
|
703
|
+
: `Set dependency registry → ${short(args.registry)} (soft, non-validating)`,
|
|
704
|
+
fields: { contract: args.contract, registry: args.registry },
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
/** Freeze the dependency set (list + registry pointer) forever. Irreversible. Signer = owner. */
|
|
708
|
+
export function prepareLockDependencies(args) {
|
|
709
|
+
return {
|
|
710
|
+
op: 'lock-dependencies',
|
|
711
|
+
to: args.contract,
|
|
712
|
+
data: encodeFunctionData({ abi: seriesCodeAbi, functionName: 'lockDependencies', args: [] }),
|
|
713
|
+
value: ZERO_VALUE,
|
|
714
|
+
chainId: args.chainId,
|
|
715
|
+
summary: 'Freeze the dependency set (list + registry pointer) — permanent',
|
|
716
|
+
fields: { contract: args.contract },
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
/** Set a CONTRACT-scope param to a literal `bytes32` (the raw owner setter — Params base).
|
|
720
|
+
* Only for schema-less keys (a schema'd key closes the raw path: `SchemaGoverned`). This is
|
|
721
|
+
* the write behind well-known contract params like `params.keys` / `display.gateway`.
|
|
722
|
+
* Signer must be the owner. */
|
|
723
|
+
export function prepareSetContractParam(args) {
|
|
724
|
+
return {
|
|
725
|
+
op: 'set-contract-param',
|
|
726
|
+
to: args.contract,
|
|
727
|
+
data: encodeFunctionData({
|
|
728
|
+
abi: seriesCodeAbi,
|
|
729
|
+
functionName: 'setContractParam',
|
|
730
|
+
args: [encodeTag(args.key), args.value],
|
|
731
|
+
}),
|
|
732
|
+
value: ZERO_VALUE,
|
|
733
|
+
chainId: args.chainId,
|
|
734
|
+
summary: `Set contract param ${args.key} = ${args.display ?? args.value}`,
|
|
735
|
+
fields: { contract: args.contract, key: args.key, value: args.display ?? args.value },
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
/** Set a CONTRACT-scope param via the data path (one blob; the evented value is its keccak256).
|
|
739
|
+
* The raw owner setter for schema-less keys — the long-form twin of {@link prepareSetContractParam}. */
|
|
740
|
+
export function prepareSetContractParamData(args) {
|
|
741
|
+
return {
|
|
742
|
+
op: 'set-contract-param-data',
|
|
743
|
+
to: args.contract,
|
|
744
|
+
data: encodeFunctionData({
|
|
745
|
+
abi: seriesCodeAbi,
|
|
746
|
+
functionName: 'setContractParamData',
|
|
747
|
+
args: [encodeTag(args.key), args.data],
|
|
748
|
+
}),
|
|
749
|
+
value: ZERO_VALUE,
|
|
750
|
+
chainId: args.chainId,
|
|
751
|
+
summary: `Set contract param ${args.key} (data, ${(args.data.length - 2) / 2} bytes)`,
|
|
752
|
+
fields: { contract: args.contract, key: args.key },
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
/** Wire the three param-lifecycle hook addresses (configure/augment/transfer) in ONE owner call.
|
|
756
|
+
* The contract has no per-hook setter — `setParamHooks` writes all three at once — so a caller
|
|
757
|
+
* changing one hook must pass the CURRENT values for the other two (read them via `paramHooks()`),
|
|
758
|
+
* else it silently clears them. `zeroAddress` for any role means "no hook". SeriesCode only. */
|
|
759
|
+
export function prepareSetParamHooks(args) {
|
|
760
|
+
return {
|
|
761
|
+
op: 'set-param-hooks',
|
|
762
|
+
to: args.contract,
|
|
763
|
+
data: encodeFunctionData({
|
|
764
|
+
abi: seriesCodeAbi,
|
|
765
|
+
functionName: 'setParamHooks',
|
|
766
|
+
args: [args.configureHook, args.augmentHook, args.transferHook],
|
|
767
|
+
}),
|
|
768
|
+
value: ZERO_VALUE,
|
|
769
|
+
chainId: args.chainId,
|
|
770
|
+
summary: `Set param hooks — configure ${args.configureHook}, augment ${args.augmentHook}, transfer ${args.transferHook}`,
|
|
771
|
+
fields: {
|
|
772
|
+
contract: args.contract,
|
|
773
|
+
configureHook: args.configureHook,
|
|
774
|
+
augmentHook: args.augmentHook,
|
|
775
|
+
transferHook: args.transferHook,
|
|
776
|
+
},
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
/** Set a schema-governed PostParam (literal scalar) — signer must satisfy the schema's auth. */
|
|
780
|
+
export function prepareConfigureTokenParam(args) {
|
|
781
|
+
return {
|
|
782
|
+
op: 'configure-param',
|
|
783
|
+
to: args.contract,
|
|
784
|
+
data: encodeFunctionData({
|
|
785
|
+
abi: seriesCodeAbi,
|
|
786
|
+
functionName: 'configureTokenParam',
|
|
787
|
+
args: [args.tokenId, encodeTag(args.key), args.value],
|
|
788
|
+
}),
|
|
789
|
+
value: ZERO_VALUE,
|
|
790
|
+
chainId: args.chainId,
|
|
791
|
+
summary: `Configure ${args.key} = ${args.display} on token ${args.tokenId}`,
|
|
792
|
+
fields: { contract: args.contract, tokenId: String(args.tokenId), key: args.key, value: args.display },
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
/** Set a schema-governed `String`/`Bytes` PostParam (the data path — one blob, hash evented). */
|
|
796
|
+
export function prepareConfigureTokenParamData(args) {
|
|
797
|
+
return {
|
|
798
|
+
op: 'configure-param-data',
|
|
799
|
+
to: args.contract,
|
|
800
|
+
data: encodeFunctionData({
|
|
801
|
+
abi: seriesCodeAbi,
|
|
802
|
+
functionName: 'configureTokenParamData',
|
|
803
|
+
args: [args.tokenId, encodeTag(args.key), args.data],
|
|
804
|
+
}),
|
|
805
|
+
value: ZERO_VALUE,
|
|
806
|
+
chainId: args.chainId,
|
|
807
|
+
summary: `Configure ${args.key} (data, ${(args.data.length - 2) / 2} bytes) on token ${args.tokenId}`,
|
|
808
|
+
fields: { contract: args.contract, tokenId: String(args.tokenId), key: args.key },
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
//# sourceMappingURL=ops.js.map
|