@artblocks/abx-sdk 0.1.0-alpha.4 → 0.1.0-alpha.40

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 (159) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +130 -0
  3. package/dist/abi/generated.d.ts +8502 -129
  4. package/dist/abi/generated.d.ts.map +1 -1
  5. package/dist/abi/generated.js +40 -22
  6. package/dist/abi/generated.js.map +1 -1
  7. package/dist/abi/index.d.ts +2645 -168
  8. package/dist/abi/index.d.ts.map +1 -1
  9. package/dist/abi/index.js +34 -7
  10. package/dist/abi/index.js.map +1 -1
  11. package/dist/anchors.d.ts +325 -0
  12. package/dist/anchors.d.ts.map +1 -0
  13. package/dist/anchors.js +740 -0
  14. package/dist/anchors.js.map +1 -0
  15. package/dist/chain-support.d.ts +28 -0
  16. package/dist/chain-support.d.ts.map +1 -0
  17. package/dist/chain-support.js +65 -0
  18. package/dist/chain-support.js.map +1 -0
  19. package/dist/chain-support.json +60 -0
  20. package/dist/chains.d.ts +24 -10
  21. package/dist/chains.d.ts.map +1 -1
  22. package/dist/chains.js +51 -17
  23. package/dist/chains.js.map +1 -1
  24. package/dist/chunks.d.ts +162 -31
  25. package/dist/chunks.d.ts.map +1 -1
  26. package/dist/chunks.js +179 -14
  27. package/dist/chunks.js.map +1 -1
  28. package/dist/clients.d.ts +23 -11
  29. package/dist/clients.d.ts.map +1 -1
  30. package/dist/clients.js +17 -18
  31. package/dist/clients.js.map +1 -1
  32. package/dist/contract-generations.d.ts +58 -0
  33. package/dist/contract-generations.d.ts.map +1 -0
  34. package/dist/contract-generations.js +109 -0
  35. package/dist/contract-generations.js.map +1 -0
  36. package/dist/contract-generations.json +48 -0
  37. package/dist/create2.d.ts +84 -1
  38. package/dist/create2.d.ts.map +1 -1
  39. package/dist/create2.js +158 -2
  40. package/dist/create2.js.map +1 -1
  41. package/dist/creator-token.d.ts +132 -0
  42. package/dist/creator-token.d.ts.map +1 -0
  43. package/dist/creator-token.js +183 -0
  44. package/dist/creator-token.js.map +1 -0
  45. package/dist/deploy.d.ts +234 -14
  46. package/dist/deploy.d.ts.map +1 -1
  47. package/dist/deploy.js +289 -111
  48. package/dist/deploy.js.map +1 -1
  49. package/dist/deployments.d.ts +38 -5
  50. package/dist/deployments.d.ts.map +1 -1
  51. package/dist/deployments.js +156 -30
  52. package/dist/deployments.js.map +1 -1
  53. package/dist/deps.d.ts +123 -6
  54. package/dist/deps.d.ts.map +1 -1
  55. package/dist/deps.js +249 -7
  56. package/dist/deps.js.map +1 -1
  57. package/dist/env.d.ts +5 -4
  58. package/dist/env.d.ts.map +1 -1
  59. package/dist/env.js +20 -5
  60. package/dist/env.js.map +1 -1
  61. package/dist/errors.d.ts +109 -0
  62. package/dist/errors.d.ts.map +1 -0
  63. package/dist/errors.js +148 -0
  64. package/dist/errors.js.map +1 -0
  65. package/dist/execute.d.ts +118 -0
  66. package/dist/execute.d.ts.map +1 -0
  67. package/dist/execute.js +159 -0
  68. package/dist/execute.js.map +1 -0
  69. package/dist/gateways.d.ts +79 -0
  70. package/dist/gateways.d.ts.map +1 -0
  71. package/dist/gateways.js +156 -0
  72. package/dist/gateways.js.map +1 -0
  73. package/dist/generator-document.d.ts +57 -0
  74. package/dist/generator-document.d.ts.map +1 -0
  75. package/dist/generator-document.js +123 -0
  76. package/dist/generator-document.js.map +1 -0
  77. package/dist/generator.d.ts +44 -2
  78. package/dist/generator.d.ts.map +1 -1
  79. package/dist/generator.js +29 -0
  80. package/dist/generator.js.map +1 -1
  81. package/dist/index.d.ts +19 -3
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +19 -3
  84. package/dist/index.js.map +1 -1
  85. package/dist/inspect.d.ts +48 -0
  86. package/dist/inspect.d.ts.map +1 -0
  87. package/dist/inspect.js +295 -0
  88. package/dist/inspect.js.map +1 -0
  89. package/dist/migrate.d.ts +41 -0
  90. package/dist/migrate.d.ts.map +1 -0
  91. package/dist/migrate.js +142 -0
  92. package/dist/migrate.js.map +1 -0
  93. package/dist/mime.d.ts +11 -0
  94. package/dist/mime.d.ts.map +1 -0
  95. package/dist/mime.js +40 -0
  96. package/dist/mime.js.map +1 -0
  97. package/dist/node.d.ts +69 -0
  98. package/dist/node.d.ts.map +1 -0
  99. package/dist/node.js +92 -0
  100. package/dist/node.js.map +1 -0
  101. package/dist/onchain-uri.d.ts +110 -0
  102. package/dist/onchain-uri.d.ts.map +1 -0
  103. package/dist/onchain-uri.js +276 -0
  104. package/dist/onchain-uri.js.map +1 -0
  105. package/dist/ops.d.ts +507 -14
  106. package/dist/ops.d.ts.map +1 -1
  107. package/dist/ops.js +850 -34
  108. package/dist/ops.js.map +1 -1
  109. package/dist/policy.d.ts +57 -0
  110. package/dist/policy.d.ts.map +1 -0
  111. package/dist/policy.js +35 -0
  112. package/dist/policy.js.map +1 -0
  113. package/dist/probe.d.ts +58 -0
  114. package/dist/probe.d.ts.map +1 -1
  115. package/dist/probe.js +190 -9
  116. package/dist/probe.js.map +1 -1
  117. package/dist/reconstruct.d.ts +141 -3
  118. package/dist/reconstruct.d.ts.map +1 -1
  119. package/dist/reconstruct.js +479 -100
  120. package/dist/reconstruct.js.map +1 -1
  121. package/dist/resume.d.ts +147 -0
  122. package/dist/resume.d.ts.map +1 -0
  123. package/dist/resume.js +146 -0
  124. package/dist/resume.js.map +1 -0
  125. package/dist/script-chunks.d.ts +105 -0
  126. package/dist/script-chunks.d.ts.map +1 -0
  127. package/dist/script-chunks.js +158 -0
  128. package/dist/script-chunks.js.map +1 -0
  129. package/dist/service.d.ts +155 -9
  130. package/dist/service.d.ts.map +1 -1
  131. package/dist/service.js +103 -11
  132. package/dist/service.js.map +1 -1
  133. package/dist/spine.d.ts +47 -4
  134. package/dist/spine.d.ts.map +1 -1
  135. package/dist/spine.js +0 -0
  136. package/dist/spine.js.map +1 -1
  137. package/dist/staging.d.ts +139 -0
  138. package/dist/staging.d.ts.map +1 -0
  139. package/dist/staging.js +139 -0
  140. package/dist/staging.js.map +1 -0
  141. package/dist/token.d.ts +11 -1
  142. package/dist/token.d.ts.map +1 -1
  143. package/dist/token.js +32 -1
  144. package/dist/token.js.map +1 -1
  145. package/dist/tokendata.d.ts +63 -3
  146. package/dist/tokendata.d.ts.map +1 -1
  147. package/dist/tokendata.js +81 -19
  148. package/dist/tokendata.js.map +1 -1
  149. package/dist/tokens.d.ts +119 -0
  150. package/dist/tokens.d.ts.map +1 -0
  151. package/dist/tokens.js +317 -0
  152. package/dist/tokens.js.map +1 -0
  153. package/dist/types.d.ts +107 -5
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/util.d.ts +74 -0
  156. package/dist/util.d.ts.map +1 -0
  157. package/dist/util.js +106 -0
  158. package/dist/util.js.map +1 -0
  159. package/package.json +15 -6
package/dist/create2.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { concat, getContractAddress, keccak256, toBytes } from 'viem';
2
- import { abxChunkStoreBytecode, abxFixedPriceMinterBytecode, abxMetadataRendererBytecode, abxSeedSourceBytecode, } from './abi/index.js';
2
+ import { abxChunkStoreBytecode, abxCodeLibBytecode, abxEditionLibBytecode, abxMetadataLibBytecode, abxFixedPriceMinterBytecode, abxFixedPriceMinter1155Bytecode, abxMetadataRendererBytecode, abxParamsLibBytecode, abxSeedSourceBytecode, editionCodeFactoryBytecode, editionImageFactoryBytecode, oneOfOneEditionFactoryBytecode, oneOfOneImageFactoryBytecode, seriesCodeFactoryBytecode, seriesImageFactoryBytecode, } from './abi/index.js';
3
3
  /**
4
4
  * Keyless CREATE2 deployment — the TS twin of `contracts/script/AbxSalts.sol`.
5
5
  *
@@ -12,7 +12,9 @@ import { abxChunkStoreBytecode, abxFixedPriceMinterBytecode, abxMetadataRenderer
12
12
  /** The keyless CREATE2 proxy (Arachnid deterministic-deployment-proxy). Same address on every chain. */
13
13
  export const CREATE2_PROXY = '0x4e59b44847b379578588920cA78FbF26c0B4956C';
14
14
  /** Canonical salt strings — MUST stay byte-identical to `contracts/script/AbxSalts.sol`, since the
15
- * deterministic address is `keccak256(0xff ++ proxy ++ keccak256(salt) ++ keccak256(initcode))`. */
15
+ * deterministic address is `keccak256(0xff ++ proxy ++ keccak256(salt) ++ keccak256(initcode))`.
16
+ * `test/create2-salts.test.ts` diffs this table against that file, both ways, so drift can't be
17
+ * quiet: the two halves have to be one fact. */
16
18
  export const ABX_SALT = {
17
19
  oneOfOneFactory: 'abx.factory.one-of-one.v1',
18
20
  seriesFactory: 'abx.factory.series.v1',
@@ -22,6 +24,17 @@ export const ABX_SALT = {
22
24
  fixedPriceMinter: 'abx.minter.fixed-price.v1',
23
25
  seedSource: 'abx.seed-source.v1',
24
26
  generator: 'abx.generator.v1',
27
+ // ERC-1155 editions (twins of the above; naming follows the parity plan verbatim).
28
+ oneOfOneEditionFactory: 'abx.one-of-one-edition-factory.v1',
29
+ editionFactory: 'abx.edition-factory.v1',
30
+ editionCodeFactory: 'abx.edition-code-factory.v1',
31
+ fixedPriceMinter1155: 'abx.fixed-price-minter-1155.v1',
32
+ // Delegatecalled write-path libraries — CREATE2 like everything else here (see the
33
+ // "delegatecalled write-path libraries" note below, and `DeployLibraries.s.sol`).
34
+ paramsLib: 'abx.lib.params.v1',
35
+ codeLib: 'abx.lib.code.v1',
36
+ editionLib: 'abx.lib.edition.v1',
37
+ metadataLib: 'abx.lib.metadata.v1',
25
38
  };
26
39
  /** The 32-byte salt a CREATE2 deploy uses (`keccak256` of the canonical string). */
27
40
  export const saltHash = (salt) => keccak256(toBytes(salt));
@@ -44,4 +57,147 @@ export const predictFixedPriceMinter = () => predictCreate2Address(ABX_SALT.fixe
44
57
  * (`DeploySeedSource.s.sol`) so it compiles at the default profile — bundling it with the
45
58
  * SeriesCode factory's `clone-impl` unit yields a different, non-canonical bytecode + address. */
46
59
  export const predictSeedSource = () => predictCreate2Address(ABX_SALT.seedSource, abxSeedSourceBytecode);
60
+ // ── ERC-1155 editions ──────────────────────────────────────────────────────────
61
+ //
62
+ // `DeployOneOfOneEdition.s.sol` / `DeployEdition.s.sol` / `DeployMinter1155.s.sol` each deploy
63
+ // their contract with a fixed `AbxSalts` salt and NO constructor args, so the salt + this build's
64
+ // bytecode fix the address before any deploy. `AbxFixedPriceMinter1155` is a plain singleton and is
65
+ // predicted right below; the two edition IMAGE factories are not — `OneOfOneEdition`/`EditionImage`
66
+ // both delegate bodies into `AbxEditionLib`, so their factories carry a link placeholder and their
67
+ // predictions live with the library-linked factories in the write-path-library section below
68
+ // (`predictOneOfOneEditionFactory`/`predictEditionFactory`), next to the two code factories.
69
+ /** The canonical (cross-chain-identical) `OneOfOneImageFactory` address for the current bytecode —
70
+ * the 721 1/1 trust anchor. */
71
+ export const predictFactory = () => predictCreate2Address(ABX_SALT.oneOfOneFactory, linkFactory());
72
+ /** The canonical (cross-chain-identical) `SeriesImageFactory` address for the current bytecode —
73
+ * the 721 multi-token trust anchor. */
74
+ export const predictSeriesFactory = () => predictCreate2Address(ABX_SALT.seriesFactory, linkSeriesFactory());
75
+ /** The canonical (cross-chain-identical) `AbxFixedPriceMinter1155` address for the current
76
+ * bytecode — the shared, ownerless edition sale singleton. */
77
+ export const predictFixedPriceMinter1155 = () => predictCreate2Address(ABX_SALT.fixedPriceMinter1155, abxFixedPriceMinter1155Bytecode);
78
+ // ── delegatecalled write-path libraries ────────────────────────────────────────
79
+ //
80
+ // A `public` library function is compiled as a `delegatecall` to a SEPARATELY deployed copy of the
81
+ // library, and solc leaves a `__$<id>$__` placeholder in the caller's bytecode where that copy's
82
+ // address goes. Linking is the substitution of an address into that placeholder.
83
+ //
84
+ // **Linking does not cost determinism.** These libraries are deployed through the same keyless
85
+ // CREATE2 proxy at the canonical salts above (`DeployLibraries.s.sol` is the forge twin), so a
86
+ // library's address is `f(proxy, salt, creation bytecode)` and nothing else — the deployer's nonce
87
+ // is not an input to a CREATE2 address (it is an input to plain `CREATE`, which is where the
88
+ // confusion came from). Predict the libraries, substitute them, and the linked factory's initcode
89
+ // is fixed too — hence the FOUR `predict*Factory` helpers at the bottom of this section.
90
+ //
91
+ // Worth stating plainly, because the opposite belief was load-bearing: two ERC-1155 token types
92
+ // (`OneOfOneEdition`/`EditionImage`) were held library-free and an EIP-170 size floor was relaxed to
93
+ // avoid "losing" a factory's deterministic address. What was actually true was narrower and
94
+ // self-inflicted — the SDK deployed its libraries with a plain EOA `CREATE` (`to: null`) by its own
95
+ // choice, so *it* could not predict them, and that local limitation was written up as a property of
96
+ // libraries in general. It isn't one. The broadcast artifacts always said so: every recorded library
97
+ // deploy went through the keyless proxy, and `AbxParamsLib` landed at ONE address on Sepolia and
98
+ // Base Sepolia from deployer nonces 215 apart. Both of those token types now delegate into
99
+ // `AbxEditionLib` exactly as `EditionCode` does, so FOUR factories here are library-linked, not two.
100
+ //
101
+ // **Losing track of that is a bug class, not a footnote.** Three separate times a contract became
102
+ // library-linked and this file went on hashing its UNLINKED bytecode, and the failure is silent:
103
+ // viem does not reject a `__$…$__` placeholder, it UTF-8-encodes it — so the prediction is a
104
+ // real-looking address that is the hash of ASCII garbage, for the addresses platforms allowlist, and
105
+ // the same bytes would go out as initcode. `link.test.ts`'s "nothing deployable carries a
106
+ // placeholder" guard derives its subject set from the exported bytecodes rather than a list of
107
+ // names, precisely so the next contract to become library-linked cannot escape the same way.
108
+ //
109
+ // **The real trap is compile-time linking, not linking.** Substituting into the placeholder happens
110
+ // AFTER compilation, so it cannot change the library's own creation bytecode. Handing solc the
111
+ // addresses at build time instead (`forge build/script --libraries src/…:Lib:0x…`) writes the
112
+ // library map into `settings.libraries` in every artifact's metadata, and the metadata hash is
113
+ // appended to the creation bytecode — so the library's own address moves, and so does the linked
114
+ // factory's. Optimizer settings do the same (the code tokens compile at `optimizer_runs = 200`,
115
+ // everything else at 1,000,000). One canonical bytecode per library, therefore: the one
116
+ // `sync-abis` reads from a plain `forge build`, which is what these predictions use.
117
+ /** Fully-qualified library names (solc's link keys — path-sensitive, so they must match how the
118
+ * contracts are compiled: `src/libraries/…` as `foundry.toml` sees them). */
119
+ export const LIB_FQN = {
120
+ paramsLib: 'src/libraries/AbxParamsLib.sol:AbxParamsLib',
121
+ codeLib: 'src/libraries/AbxCodeLib.sol:AbxCodeLib',
122
+ editionLib: 'src/libraries/AbxEditionLib.sol:AbxEditionLib',
123
+ metadataLib: 'src/libraries/AbxMetadataLib.sol:AbxMetadataLib',
124
+ };
125
+ /** The solc link placeholder for a fully-qualified library name: `__$<keccak(fqn)[0:34]>$__`. */
126
+ export const libPlaceholder = (fullyQualified) => `__$${keccak256(toBytes(fullyQualified)).slice(2, 36)}$__`;
127
+ /**
128
+ * Link `bytecode` against deployed libraries — the post-compile placeholder substitution `forge`
129
+ * does at build time, done here so a sandbox / fresh chain needs no forge. Throws if any
130
+ * placeholder is left over, since an unlinked `__$…$__` is not valid hex and the RPC would reject
131
+ * the transaction with an opaque `Invalid byte sequence`.
132
+ */
133
+ export function linkLibraries(bytecode, links) {
134
+ let out = bytecode;
135
+ for (const [fqn, address] of links)
136
+ out = out.split(libPlaceholder(fqn)).join(address.slice(2).toLowerCase());
137
+ if (out.includes('__$'))
138
+ throw new Error(`unlinked library placeholder remains: ${/__\$[0-9a-f]{34}\$__/.exec(out)?.[0]}`);
139
+ return out;
140
+ }
141
+ /** The canonical (cross-chain-identical) `AbxParamsLib` address — the params write path both code
142
+ * token types delegatecall. */
143
+ export const predictParamsLib = () => predictCreate2Address(ABX_SALT.paramsLib, abxParamsLibBytecode);
144
+ /** The canonical (cross-chain-identical) `AbxCodeLib` address — the script/code write path. */
145
+ export const predictCodeLib = () => predictCreate2Address(ABX_SALT.codeLib, abxCodeLibBytecode);
146
+ /** The canonical (cross-chain-identical) `AbxEditionLib` address — the 1155 uri / creator-token /
147
+ * edition-supply write path that **all three** edition token types (`OneOfOneEdition`,
148
+ * `EditionImage`, `EditionCode`) delegatecall.
149
+ * `AbxEditionLib` itself delegatecalls `AbxParamsLib`, so it is linked before it is deployed: the
150
+ * one library here whose own initcode depends on another library's address. */
151
+ export const predictEditionLib = () => predictCreate2Address(ABX_SALT.editionLib, linkEditionLib());
152
+ /** The canonical `AbxMetadataLib` address. Linked by ALL SIX token types to preserve EIP-170
153
+ * headroom; externalizing the metadata field store makes even the plainest 721 factory
154
+ * library-linked. It links nothing itself, so it is deployed first. */
155
+ export const predictMetadataLib = () => predictCreate2Address(ABX_SALT.metadataLib, abxMetadataLibBytecode);
156
+ /** `AbxEditionLib`'s canonical initcode: its shipped bytecode linked against `AbxParamsLib`. */
157
+ export const linkEditionLib = () => linkLibraries(abxEditionLibBytecode, [[LIB_FQN.paramsLib, predictParamsLib()]]);
158
+ /** `OneOfOneEditionFactory`'s canonical initcode: linked against `AbxEditionLib` (the only library
159
+ * its embedded `OneOfOneEdition` implementation delegates into). `AbxEditionLib`'s own address
160
+ * already accounts for its `AbxParamsLib` link — see {@link predictEditionLib}. */
161
+ export const linkOneOfOneEditionFactory = () => linkLibraries(oneOfOneEditionFactoryBytecode, [
162
+ [LIB_FQN.editionLib, predictEditionLib()],
163
+ [LIB_FQN.metadataLib, predictMetadataLib()],
164
+ ]);
165
+ /** `EditionImageFactory`'s canonical initcode: linked against `AbxEditionLib`, the sibling of
166
+ * {@link linkOneOfOneEditionFactory}. */
167
+ export const linkEditionFactory = () => linkLibraries(editionImageFactoryBytecode, [
168
+ [LIB_FQN.editionLib, predictEditionLib()],
169
+ [LIB_FQN.metadataLib, predictMetadataLib()],
170
+ ]);
171
+ /** `SeriesCodeFactory`'s canonical initcode: linked against the two write-path libraries. */
172
+ export const linkSeriesCodeFactory = () => linkLibraries(seriesCodeFactoryBytecode, [
173
+ [LIB_FQN.paramsLib, predictParamsLib()],
174
+ [LIB_FQN.codeLib, predictCodeLib()],
175
+ [LIB_FQN.metadataLib, predictMetadataLib()],
176
+ ]);
177
+ /** `EditionCodeFactory`'s canonical initcode: linked against all three write-path libraries. */
178
+ export const linkEditionCodeFactory = () => linkLibraries(editionCodeFactoryBytecode, [
179
+ [LIB_FQN.paramsLib, predictParamsLib()],
180
+ [LIB_FQN.codeLib, predictCodeLib()],
181
+ [LIB_FQN.editionLib, predictEditionLib()],
182
+ [LIB_FQN.metadataLib, predictMetadataLib()],
183
+ ]);
184
+ /** The two ERC-721 image factories' canonical initcode. They linked NOTHING until the metadata
185
+ * field store was externalized; now every token type is library-linked. */
186
+ export const linkFactory = () => linkLibraries(oneOfOneImageFactoryBytecode, [[LIB_FQN.metadataLib, predictMetadataLib()]]);
187
+ export const linkSeriesFactory = () => linkLibraries(seriesImageFactoryBytecode, [[LIB_FQN.metadataLib, predictMetadataLib()]]);
188
+ /** The canonical (cross-chain-identical) `SeriesCodeFactory` address — the code-project trust
189
+ * anchor. Predictable because its libraries are (see the section note above). */
190
+ export const predictSeriesCodeFactory = () => predictCreate2Address(ABX_SALT.seriesCodeFactory, linkSeriesCodeFactory());
191
+ /** The canonical (cross-chain-identical) `EditionCodeFactory` address — the code-project EDITION
192
+ * trust anchor. */
193
+ export const predictEditionCodeFactory = () => predictCreate2Address(ABX_SALT.editionCodeFactory, linkEditionCodeFactory());
194
+ /** The canonical (cross-chain-identical) `OneOfOneEditionFactory` address — the 1/1-edition trust
195
+ * anchor. Predicted from LINKED initcode: `OneOfOneEdition` delegates its uri / creator-token /
196
+ * edition-supply bodies into `AbxEditionLib`, so the shipped factory bytecode carries a link
197
+ * placeholder (hashing it unlinked yields a plausible-looking address for a trust anchor that
198
+ * nothing can ever be deployed to — see the section note). */
199
+ export const predictOneOfOneEditionFactory = () => predictCreate2Address(ABX_SALT.oneOfOneEditionFactory, linkOneOfOneEditionFactory());
200
+ /** The canonical (cross-chain-identical) `EditionImageFactory` address — the multi-work edition
201
+ * trust anchor, the sibling of {@link predictOneOfOneEditionFactory} (same single library link). */
202
+ export const predictEditionFactory = () => predictCreate2Address(ABX_SALT.editionFactory, linkEditionFactory());
47
203
  //# sourceMappingURL=create2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create2.js","sourceRoot":"","sources":["../src/create2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,OAAO,EAAyB,MAAM,MAAM,CAAC;AAC5F,OAAO,EACL,qBAAqB,EACrB,2BAA2B,EAC3B,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;GAQG;AAEH,wGAAwG;AACxG,MAAM,CAAC,MAAM,aAAa,GAAY,4CAA4C,CAAC;AAEnF;qGACqG;AACrG,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,eAAe,EAAE,2BAA2B;IAC5C,aAAa,EAAE,uBAAuB;IACtC,iBAAiB,EAAE,4BAA4B;IAC/C,QAAQ,EAAE,iBAAiB;IAC3B,UAAU,EAAE,oBAAoB;IAChC,gBAAgB,EAAE,2BAA2B;IAC7C,UAAU,EAAE,oBAAoB;IAChC,SAAS,EAAE,kBAAkB;CACrB,CAAC;AAEX,oFAAoF;AACpF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAO,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAExE;6CAC6C;AAC7C,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,QAAa;IAC/D,OAAO,kBAAkB,CAAC,EAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAC,CAAC,CAAC;AACtG,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAa;IACzD,OAAO,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,4FAA4F;AAC5F,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAY,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC;AAElH,kGAAkG;AAClG,MAAM,CAAC,MAAM,eAAe,GAAG,GAAY,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAC;AAEpH,kGAAkG;AAClG,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAY,EAAE,CACnD,qBAAqB,CAAC,QAAQ,CAAC,gBAAgB,EAAE,2BAA2B,CAAC,CAAC;AAEhF;;mGAEmG;AACnG,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAY,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC,CAAC"}
1
+ {"version":3,"file":"create2.js","sourceRoot":"","sources":["../src/create2.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * ERC-721C creator-token support — the opt-in transfer-validation surface.
3
+ *
4
+ * An ABX token enrolls at deploy, permanently, by passing a non-zero `transferValidator` in
5
+ * its InitParams (see `deploy.ts`); zero leaves a plain ERC-721 forever, indistinguishable
6
+ * from a pre-721C token (ERC-165 and the extension beacon both branch on enrollment). Within
7
+ * an enrolled token the owner re-points the validator freely or suspends enforcement with
8
+ * zero — never un-enrolls. Every transfer that isn't a mint/burn (or the validator's own)
9
+ * staticcalls `validateTransfer(caller, from, to, tokenId)` on the validator; a policy
10
+ * violation reverts and bubbles.
11
+ *
12
+ * **`setTransferValidator` is owner-only only while the collection has an owner.** Once
13
+ * `owner() == address(0)` the contract opens one asymmetric door: **anyone** may suspend
14
+ * enforcement by passing `zeroAddress`, and nobody — including that caller — may ever arm a
15
+ * validator again. That is the dead-man release for the worst reachable state (a validator that
16
+ * reverts every transfer on a collection with nobody left to re-point it, which would otherwise
17
+ * strand every collector's token forever). An integrator building for collectors should expose
18
+ * that suspension path on a renounced collection rather than gating it behind an owner check that
19
+ * can no longer be satisfied — see {@link prepareSetTransferValidator}.
20
+ */
21
+ import { type Address, type PublicClient } from 'viem';
22
+ import type { PreparedTx } from './ops.js';
23
+ /** ERC-165 id of `ICreatorToken` — advertised (with the legacy id) only when enrolled. */
24
+ export declare const CREATOR_TOKEN_INTERFACE_ID: "0xad0d7f6c";
25
+ /** ERC-165 id of `ICreatorTokenLegacy` — the subset older marketplaces probe for. */
26
+ export declare const CREATOR_TOKEN_LEGACY_INTERFACE_ID: "0xa07d229a";
27
+ /** keccak256("abx.extension.creator-token") — `extensionVersion(id)` is 1 only when enrolled. */
28
+ export declare const CREATOR_TOKEN_EXTENSION_ID: "0x0839e7ed7fc1f5db3f253851d61b10f852045c5520c2936138b121b73e7e27c0";
29
+ /**
30
+ * The recommended transfer validator per chain — OpenSea's
31
+ * **StrictAuthorizedTransferSecurityRegistry**, the validator their creator-fee-enforcement
32
+ * doc recommends for enforcement eligibility (docs.opensea.io "Creator Fee Enforcement"; the named
33
+ * alternative is Limit Break's CreatorTokenTransferValidator
34
+ * 0x721C0078c2328597Ca70F5451ffF5A7B38D4E947). Verified empirically against the live contracts with
35
+ * `cast call --from <collection>` on the 4-arg
36
+ * `validateTransfer(address,address,address,uint256)` overload, both chains):
37
+ * an owner-initiated (OTC) transfer succeeds; an unauthorized operator reverts
38
+ * `StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer()`.
39
+ *
40
+ * CREATE2-style vanity address, identical on both shipped chains — kept per-chain anyway
41
+ * (keyed like `deployments.ts`) because presence-on-chain is the fact that matters, and a
42
+ * future chain may recommend a different validator.
43
+ */
44
+ export declare const RECOMMENDED_TRANSFER_VALIDATOR: Record<number, Address>;
45
+ /** The recommended validator for a chain (undefined if none is known — never guess one). */
46
+ export declare function resolveRecommendedTransferValidator(chainId: number): Address | undefined;
47
+ /** A token's creator-token (ERC-721C) status, read from chain. */
48
+ export interface CreatorTokenStatus {
49
+ /** True iff the token enrolled at deploy (permanent). False = plain ERC-721, forever. */
50
+ enrolled: boolean;
51
+ /** The active validator (`zeroAddress` when unenrolled, or enrolled-but-suspended). */
52
+ validator: Address;
53
+ }
54
+ /**
55
+ * Read whether `contract` is an enrolled ERC-721C creator token, and its active validator.
56
+ * Enrollment comes from ERC-165 (`ICreatorToken`, which the token advertises only when
57
+ * enrolled); the validator from `getTransferValidator()`. Both reads are defensive — a
58
+ * pre-721C ABX token has neither branch (no `getTransferValidator` selector at all), and
59
+ * must read as `{enrolled: false, validator: zeroAddress}`, not as an error.
60
+ */
61
+ export declare function readCreatorTokenStatus(client: PublicClient, contract: Address): Promise<CreatorTokenStatus>;
62
+ /** What {@link probeTransferValidator} found. Only `ok` may be written to a live collection.
63
+ *
64
+ * - `ok` — the address has code and refuses a selector no validator implements,
65
+ * which is what every live validator does (see the probe's doc).
66
+ * - `no-code` — nothing deployed at this address on this chain. Enforcement would read
67
+ * as ON everywhere and check nothing.
68
+ * - `permissive-fallback` — it has code, but it answers an unknown selector *successfully*. A
69
+ * Safe, an uninitialised proxy, or a 7702-delegated EOA does this, and
70
+ * because `validateTransfer` returns nothing there is no ABI decode to
71
+ * fail — so every transfer would silently pass validation.
72
+ * - `unreachable` — the RPC didn't answer. Says nothing about the address; retry.
73
+ */
74
+ export type TransferValidatorVerdict = 'ok' | 'no-code' | 'permissive-fallback' | 'unreachable';
75
+ /** The result of {@link probeTransferValidator} — verdict plus what was observed, for a message. */
76
+ export interface TransferValidatorProbe {
77
+ verdict: TransferValidatorVerdict;
78
+ address: Address;
79
+ /** First line of the revert/transport error, when there was one. */
80
+ error?: string;
81
+ }
82
+ /**
83
+ * Ask a candidate transfer validator a question no validator can answer, and require it to FAIL.
84
+ *
85
+ * **`code.length > 0` is not enough**, which is why this exists and why the on-chain guard was
86
+ * rewritten to match. Two shapes enforce nothing while every read surface — ERC-165,
87
+ * `getTransferValidator()`, the extension beacon — reports enforcement as on: no code at all, and a
88
+ * *permissive fallback* that succeeds for any selector. `validateTransfer` returns nothing, so
89
+ * there is no ABI decode to fail; a Safe (its `FallbackManager.fallback()` returns empty when no
90
+ * handler is set), an uninitialised proxy, and an EIP-7702-delegated EOA all pass a has-code check
91
+ * and then wave every transfer through. A creator pasting their own Safe is the likely real case.
92
+ *
93
+ * So the probe inverts the question: a real validator **reverts** here (verified against OpenSea's
94
+ * SATSR and three Limit Break deployments on mainnet and Sepolia), and a permissive one returns
95
+ * empty success. This mirrors the contract exactly — the same selector, the same "must fail" rule —
96
+ * so an address that passes here is an address the token will accept, and the CLI stops reporting
97
+ * "no code on this chain" for an address that plainly has code.
98
+ *
99
+ * An ERC-165 gate was measured and rejected: none of those four live validators advertises
100
+ * `ITransferValidator`/`ITransferValidator1155`, so requiring an id would refuse the entire
101
+ * ecosystem, including the validator ABX itself recommends.
102
+ *
103
+ * **A misconfiguration guard, not a security boundary** — a contract can always be written to pass
104
+ * this and enforce nothing. It catches the honest mistake. Never throws for an on-chain reason:
105
+ * every failure is a verdict (mirrors `probeSeedSource`).
106
+ */
107
+ export declare function probeTransferValidator(client: PublicClient, validator: Address,
108
+ /** The enrolling/enrolled token, when known — the probe is made as the token, because that is
109
+ * the `msg.sender` the contract's own staticcall presents. */
110
+ opts?: {
111
+ as?: Address;
112
+ }): Promise<TransferValidatorProbe>;
113
+ /**
114
+ * Re-point an enrolled token's transfer validator, or suspend enforcement with
115
+ * `zeroAddress` (the token stays enrolled). Reverts `NotCreatorToken()` on a token that didn't
116
+ * enroll at deploy — enrollment can never be added later — and `InvalidTransferValidator()` on a
117
+ * validator the chain's own probe refuses (no code on this chain, **or** a permissive fallback that
118
+ * would enforce nothing); call {@link probeTransferValidator} first and refuse those before gas.
119
+ *
120
+ * **Who may sign:** the owner, while there is one. On a collection whose `owner()` is
121
+ * `address(0)`, **any** signer may send this with `validator = zeroAddress` to suspend enforcement
122
+ * permanently — the dead-man release described in this module's header. Arming a validator is still
123
+ * owner-only, so an ownerless collection can only move toward transferability, never back. A UX for
124
+ * collectors should offer that suspension when it sees a renounced, enforcing collection; gating it
125
+ * on `owner()` would hide the one recovery a stranded holder has.
126
+ */
127
+ export declare function prepareSetTransferValidator(args: {
128
+ contract: Address;
129
+ validator: Address;
130
+ chainId: number;
131
+ }): PreparedTx;
132
+ //# sourceMappingURL=creator-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"creator-token.d.ts","sourceRoot":"","sources":["../src/creator-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAkC,KAAK,OAAO,EAAY,KAAK,YAAY,EAAC,MAAM,MAAM,CAAC;AAEhG,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AAEzC,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,EAAG,YAAqB,CAAC;AAChE,qFAAqF;AACrF,eAAO,MAAM,iCAAiC,EAAG,YAAqB,CAAC;AACvE,iGAAiG;AACjG,eAAO,MAAM,0BAA0B,EACrC,oEAA6E,CAAC;AAEhF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAKlE,CAAC;AAEF,4FAA4F;AAC5F,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAExF;AAED,kEAAkE;AAClE,MAAM,WAAW,kBAAkB;IACjC,yFAAyF;IACzF,QAAQ,EAAE,OAAO,CAAC;IAClB,uFAAuF;IACvF,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAe7B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,wBAAwB,GAAG,IAAI,GAAG,SAAS,GAAG,qBAAqB,GAAG,aAAa,CAAC;AAEhG,oGAAoG;AACpG,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,wBAAwB,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAQD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,OAAO;AAClB;+DAC+D;AAC/D,IAAI,GAAE;IAAC,EAAE,CAAC,EAAE,OAAO,CAAA;CAAM,GACxB,OAAO,CAAC,sBAAsB,CAAC,CAsBjC;AAoBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,UAAU,CAiBb"}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * ERC-721C creator-token support — the opt-in transfer-validation surface.
3
+ *
4
+ * An ABX token enrolls at deploy, permanently, by passing a non-zero `transferValidator` in
5
+ * its InitParams (see `deploy.ts`); zero leaves a plain ERC-721 forever, indistinguishable
6
+ * from a pre-721C token (ERC-165 and the extension beacon both branch on enrollment). Within
7
+ * an enrolled token the owner re-points the validator freely or suspends enforcement with
8
+ * zero — never un-enrolls. Every transfer that isn't a mint/burn (or the validator's own)
9
+ * staticcalls `validateTransfer(caller, from, to, tokenId)` on the validator; a policy
10
+ * violation reverts and bubbles.
11
+ *
12
+ * **`setTransferValidator` is owner-only only while the collection has an owner.** Once
13
+ * `owner() == address(0)` the contract opens one asymmetric door: **anyone** may suspend
14
+ * enforcement by passing `zeroAddress`, and nobody — including that caller — may ever arm a
15
+ * validator again. That is the dead-man release for the worst reachable state (a validator that
16
+ * reverts every transfer on a collection with nobody left to re-point it, which would otherwise
17
+ * strand every collector's token forever). An integrator building for collectors should expose
18
+ * that suspension path on a renounced collection rather than gating it behind an owner check that
19
+ * can no longer be satisfied — see {@link prepareSetTransferValidator}.
20
+ */
21
+ import { encodeFunctionData, zeroAddress } from 'viem';
22
+ import { oneOfOneImageAbi } from './abi/index.js';
23
+ /** ERC-165 id of `ICreatorToken` — advertised (with the legacy id) only when enrolled. */
24
+ export const CREATOR_TOKEN_INTERFACE_ID = '0xad0d7f6c';
25
+ /** ERC-165 id of `ICreatorTokenLegacy` — the subset older marketplaces probe for. */
26
+ export const CREATOR_TOKEN_LEGACY_INTERFACE_ID = '0xa07d229a';
27
+ /** keccak256("abx.extension.creator-token") — `extensionVersion(id)` is 1 only when enrolled. */
28
+ export const CREATOR_TOKEN_EXTENSION_ID = '0x0839e7ed7fc1f5db3f253851d61b10f852045c5520c2936138b121b73e7e27c0';
29
+ /**
30
+ * The recommended transfer validator per chain — OpenSea's
31
+ * **StrictAuthorizedTransferSecurityRegistry**, the validator their creator-fee-enforcement
32
+ * doc recommends for enforcement eligibility (docs.opensea.io "Creator Fee Enforcement"; the named
33
+ * alternative is Limit Break's CreatorTokenTransferValidator
34
+ * 0x721C0078c2328597Ca70F5451ffF5A7B38D4E947). Verified empirically against the live contracts with
35
+ * `cast call --from <collection>` on the 4-arg
36
+ * `validateTransfer(address,address,address,uint256)` overload, both chains):
37
+ * an owner-initiated (OTC) transfer succeeds; an unauthorized operator reverts
38
+ * `StrictAuthorizedTransferSecurityRegistry__UnauthorizedTransfer()`.
39
+ *
40
+ * CREATE2-style vanity address, identical on both shipped chains — kept per-chain anyway
41
+ * (keyed like `deployments.ts`) because presence-on-chain is the fact that matters, and a
42
+ * future chain may recommend a different validator.
43
+ */
44
+ export const RECOMMENDED_TRANSFER_VALIDATOR = {
45
+ // Sepolia (testnet)
46
+ 11155111: '0xA000027A9B2802E1ddf7000061001e5c005A0000',
47
+ // Base Sepolia (testnet)
48
+ 84532: '0xA000027A9B2802E1ddf7000061001e5c005A0000',
49
+ };
50
+ /** The recommended validator for a chain (undefined if none is known — never guess one). */
51
+ export function resolveRecommendedTransferValidator(chainId) {
52
+ return RECOMMENDED_TRANSFER_VALIDATOR[chainId];
53
+ }
54
+ /**
55
+ * Read whether `contract` is an enrolled ERC-721C creator token, and its active validator.
56
+ * Enrollment comes from ERC-165 (`ICreatorToken`, which the token advertises only when
57
+ * enrolled); the validator from `getTransferValidator()`. Both reads are defensive — a
58
+ * pre-721C ABX token has neither branch (no `getTransferValidator` selector at all), and
59
+ * must read as `{enrolled: false, validator: zeroAddress}`, not as an error.
60
+ */
61
+ export async function readCreatorTokenStatus(client, contract) {
62
+ const [enrolled, validator] = await Promise.all([
63
+ client
64
+ .readContract({
65
+ address: contract,
66
+ abi: oneOfOneImageAbi,
67
+ functionName: 'supportsInterface',
68
+ args: [CREATOR_TOKEN_INTERFACE_ID],
69
+ })
70
+ .catch(() => false),
71
+ client
72
+ .readContract({ address: contract, abi: oneOfOneImageAbi, functionName: 'getTransferValidator' })
73
+ .catch(() => zeroAddress),
74
+ ]);
75
+ return { enrolled, validator };
76
+ }
77
+ /**
78
+ * A selector no transfer validator implements — the probe question. Same constant the contract's
79
+ * own `_requireHasCode` uses, so the SDK and the chain agree about which addresses are refused.
80
+ */
81
+ const NOT_A_VALIDATOR_SELECTOR = '0xa9b1c2d3';
82
+ /**
83
+ * Ask a candidate transfer validator a question no validator can answer, and require it to FAIL.
84
+ *
85
+ * **`code.length > 0` is not enough**, which is why this exists and why the on-chain guard was
86
+ * rewritten to match. Two shapes enforce nothing while every read surface — ERC-165,
87
+ * `getTransferValidator()`, the extension beacon — reports enforcement as on: no code at all, and a
88
+ * *permissive fallback* that succeeds for any selector. `validateTransfer` returns nothing, so
89
+ * there is no ABI decode to fail; a Safe (its `FallbackManager.fallback()` returns empty when no
90
+ * handler is set), an uninitialised proxy, and an EIP-7702-delegated EOA all pass a has-code check
91
+ * and then wave every transfer through. A creator pasting their own Safe is the likely real case.
92
+ *
93
+ * So the probe inverts the question: a real validator **reverts** here (verified against OpenSea's
94
+ * SATSR and three Limit Break deployments on mainnet and Sepolia), and a permissive one returns
95
+ * empty success. This mirrors the contract exactly — the same selector, the same "must fail" rule —
96
+ * so an address that passes here is an address the token will accept, and the CLI stops reporting
97
+ * "no code on this chain" for an address that plainly has code.
98
+ *
99
+ * An ERC-165 gate was measured and rejected: none of those four live validators advertises
100
+ * `ITransferValidator`/`ITransferValidator1155`, so requiring an id would refuse the entire
101
+ * ecosystem, including the validator ABX itself recommends.
102
+ *
103
+ * **A misconfiguration guard, not a security boundary** — a contract can always be written to pass
104
+ * this and enforce nothing. It catches the honest mistake. Never throws for an on-chain reason:
105
+ * every failure is a verdict (mirrors `probeSeedSource`).
106
+ */
107
+ export async function probeTransferValidator(client, validator,
108
+ /** The enrolling/enrolled token, when known — the probe is made as the token, because that is
109
+ * the `msg.sender` the contract's own staticcall presents. */
110
+ opts = {}) {
111
+ let code;
112
+ try {
113
+ code = await client.getCode({ address: validator });
114
+ }
115
+ catch (err) {
116
+ return { verdict: 'unreachable', address: validator, error: firstLine(err) };
117
+ }
118
+ if (!code || code === '0x')
119
+ return { verdict: 'no-code', address: validator };
120
+ try {
121
+ await client.call({
122
+ to: validator,
123
+ data: NOT_A_VALIDATOR_SELECTOR,
124
+ ...(opts.as ? { account: opts.as } : {}),
125
+ });
126
+ }
127
+ catch (err) {
128
+ // A revert is the PASS: this is what a real validator does with an unknown selector. A
129
+ // transport failure lands here too, so classify it rather than calling a broken RPC "ok".
130
+ return isTransportFailure(err)
131
+ ? { verdict: 'unreachable', address: validator, error: firstLine(err) }
132
+ : { verdict: 'ok', address: validator };
133
+ }
134
+ return { verdict: 'permissive-fallback', address: validator };
135
+ }
136
+ /** First line of an error message — a revert reason is readable; viem's full dump is not. */
137
+ function firstLine(err) {
138
+ return String(err?.message ?? err).split('\n')[0].trim();
139
+ }
140
+ /** Distinguish "the node said this call reverted" (a verdict) from "the node didn't answer" (retry).
141
+ * viem reports a revert as an execution error carrying revert data or the word itself; anything
142
+ * that never reached execution (timeout, socket, HTTP status, rate limit) must not read as a pass. */
143
+ function isTransportFailure(err) {
144
+ const name = err?.name ?? '';
145
+ const msg = String(err?.message ?? err);
146
+ if (/execution reverted|reverted with|revert reason|InvalidTransferValidator/i.test(msg))
147
+ return false;
148
+ return (/Timeout|Socket|Network|HttpRequest|Connection|RateLimit|InternalRpc|LimitExceeded/i.test(name) ||
149
+ /timed? out|timeout|socket hang up|ECONN|fetch failed|status code|too many requests|rate limit/i.test(msg));
150
+ }
151
+ /**
152
+ * Re-point an enrolled token's transfer validator, or suspend enforcement with
153
+ * `zeroAddress` (the token stays enrolled). Reverts `NotCreatorToken()` on a token that didn't
154
+ * enroll at deploy — enrollment can never be added later — and `InvalidTransferValidator()` on a
155
+ * validator the chain's own probe refuses (no code on this chain, **or** a permissive fallback that
156
+ * would enforce nothing); call {@link probeTransferValidator} first and refuse those before gas.
157
+ *
158
+ * **Who may sign:** the owner, while there is one. On a collection whose `owner()` is
159
+ * `address(0)`, **any** signer may send this with `validator = zeroAddress` to suspend enforcement
160
+ * permanently — the dead-man release described in this module's header. Arming a validator is still
161
+ * owner-only, so an ownerless collection can only move toward transferability, never back. A UX for
162
+ * collectors should offer that suspension when it sees a renounced, enforcing collection; gating it
163
+ * on `owner()` would hide the one recovery a stranded holder has.
164
+ */
165
+ export function prepareSetTransferValidator(args) {
166
+ const suspending = args.validator === zeroAddress;
167
+ return {
168
+ op: 'set-transfer-validator',
169
+ to: args.contract,
170
+ data: encodeFunctionData({
171
+ abi: oneOfOneImageAbi,
172
+ functionName: 'setTransferValidator',
173
+ args: [args.validator],
174
+ }),
175
+ value: '0x0',
176
+ chainId: args.chainId,
177
+ summary: suspending
178
+ ? 'Suspend ERC-721C transfer enforcement (validator → 0x0; the token stays enrolled)'
179
+ : `Set ERC-721C transfer validator → ${args.validator}`,
180
+ fields: { contract: args.contract, validator: args.validator },
181
+ };
182
+ }
183
+ //# sourceMappingURL=creator-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"creator-token.js","sourceRoot":"","sources":["../src/creator-token.ts"],"names":[],"mappings":"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"}