@easy1staking/cip113-sdk-ts 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +152 -0
  2. package/blueprints/standard/v0.5.0-alpha.5/UPSTREAM_PIN.json +36 -0
  3. package/blueprints/standard/v0.5.0-alpha.5/plutus.json +1434 -0
  4. package/dist/core/evo-utils.d.ts +6 -1
  5. package/dist/core/evo-utils.d.ts.map +1 -1
  6. package/dist/core/evo-utils.js.map +1 -1
  7. package/dist/index.d.ts +15 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +81 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/standard/blueprint.d.ts +27 -3
  12. package/dist/standard/blueprint.d.ts.map +1 -1
  13. package/dist/standard/blueprint.js +27 -3
  14. package/dist/standard/blueprint.js.map +1 -1
  15. package/dist/standard/bootstrap.d.ts +662 -0
  16. package/dist/standard/bootstrap.d.ts.map +1 -0
  17. package/dist/standard/bootstrap.js +1221 -0
  18. package/dist/standard/bootstrap.js.map +1 -0
  19. package/dist/standard/scripts.d.ts +13 -2
  20. package/dist/standard/scripts.d.ts.map +1 -1
  21. package/dist/standard/scripts.js +13 -2
  22. package/dist/standard/scripts.js.map +1 -1
  23. package/dist/substandards/address-guard.d.ts +60 -0
  24. package/dist/substandards/address-guard.d.ts.map +1 -0
  25. package/dist/substandards/address-guard.js +159 -0
  26. package/dist/substandards/address-guard.js.map +1 -0
  27. package/dist/substandards/dummy/index.d.ts.map +1 -1
  28. package/dist/substandards/dummy/index.js +32 -5
  29. package/dist/substandards/dummy/index.js.map +1 -1
  30. package/dist/substandards/freeze-and-seize/index.d.ts.map +1 -1
  31. package/dist/substandards/freeze-and-seize/index.js +45 -9
  32. package/dist/substandards/freeze-and-seize/index.js.map +1 -1
  33. package/dist/substandards/interface.d.ts +20 -2
  34. package/dist/substandards/interface.d.ts.map +1 -1
  35. package/package.json +1 -1
package/README.md CHANGED
@@ -58,6 +58,158 @@ await client.awaitTx(txHash);
58
58
  | `@easy1staking/cip113-sdk-ts/freeze-and-seize` | Freeze-and-Seize substandard |
59
59
  | `@easy1staking/cip113-sdk-ts/dummy` | Dummy substandard |
60
60
 
61
+ ## Migrating to 0.12.0 (CIP-113 0.5.0-alpha.5 — the upgrade authority activates itself)
62
+
63
+ ⛔ **EVERY SCRIPT HASH DOWNSTREAM OF THE PARAMS POLICY CHANGES — EIGHT OF TWELVE.** An alpha.4
64
+ instance **cannot be upgraded; it must be REDEPLOYED.** The four that survive (`always_fail`,
65
+ `issuance_cbor_hex_mint`, `registry`, `upgrade_multisig`) hang off seeds and nonces rather than the
66
+ params policy — and a redeployment uses fresh seeds, so they cannot collide with the old instance in
67
+ practice.
68
+
69
+ There is no migration path for a running deployment, and nothing in this SDK will pretend otherwise:
70
+ `validateStandardBlueprint` is a version-**equality** gate, so 0.12.0 refuses an alpha.4 blueprint as
71
+ firmly as it refuses an alpha.3 one. Stay on 0.11.x for as long as you need to keep operating an
72
+ alpha.4 instance.
73
+
74
+ ⚠ **An earlier draft of this note said "every script hash changes". That was FALSE and it is
75
+ recorded here rather than quietly corrected**, because the false version is *checkable*: one
76
+ operator deriving `registry` at their old seeds finds it identical, and the credibility of the whole
77
+ migration note goes with it. The eight/four split is measured in `test/hash-cascade.test.mjs`. The
78
+ operational conclusion did not change.
79
+
80
+ ### What upstream changed — one line
81
+
82
+ `protocol_params.mint` gained a single check:
83
+
84
+ ```aiken
85
+ pairs.has_key(self.withdrawals, genesis_params.upgrade_cred)?
86
+ ```
87
+
88
+ The transaction that mints the protocol-params NFT must now carry a **withdraw-0 from the
89
+ credential its own datum names as the upgrade authority**. The authority has to *run* — through
90
+ the same trampoline every later upgrade uses — before it becomes canonical, so a typo or the hash
91
+ of a script nobody deployed can never take the protocol's upgrade seat. Measured against alpha.4:
92
+ 34 validators either side, **31 byte-identical**, and the only compiled code that moved is
93
+ `protocol_params`'s.
94
+
95
+ ### Why one line relocates eight of the twelve
96
+
97
+ `protocol_params`'s hash **is** the params-NFT policy id, and that policy id is the parameter at the
98
+ root of the parameterisation graph. It feeds `programmable_logic_base`, and through it `transfer`,
99
+ `third_party`, `unfracking` and `programmable_logic_global`; it feeds `issuance_logic` and
100
+ `issuance_mint` directly. Only the four scripts that hang off seeds and nonces instead —
101
+ `always_fail`, `issuance_cbor_hex_mint`, `registry`, `upgrade_multisig` — keep their alpha.4 hashes
102
+ for the same inputs. This is measured in `test/hash-cascade.test.mjs` against a live alpha.4
103
+ deployment record, not asserted.
104
+
105
+ ### What moved in this package's API
106
+
107
+ **`buildProtocolGenesisTx` takes two new REQUIRED fields.**
108
+
109
+ ```diff
110
+ await buildProtocolGenesisTx({
111
+ client, changeAddress, availableUtxos, evaluator, plan,
112
+ protocolParamsSeedUtxo, issuanceSeedUtxo,
113
+ + upgradeMultisigConfigUtxo, // REQUIRED — the config UTxO, as a reference input
114
+ + upgradeAuthoritySigners, // REQUIRED — key hashes for `extra_signatories`; may be []
115
+ });
116
+ ```
117
+
118
+ `upgradeMultisigConfigUtxo` is the UTxO `assertMultisigConfigUtxo()` already returns: read it back
119
+ off the chain rather than reconstructing it from a record, because a signer rotation spends and
120
+ recreates it. `upgrade_multisig.withdraw` finds its authority tree among the transaction's
121
+ **reference inputs**, so without it the withdrawal cannot be decided.
122
+
123
+ `upgradeAuthoritySigners` **cannot be defaulted or inferred, and that is structural.** A
124
+ `MultisigScript` tree has seven node kinds; only `Signature` names a key hash. `Script` names
125
+ another withdraw-0, `Before`/`After` name a validity bound, and `AnyOf`/`AtLeast` leave a genuine
126
+ choice of *which branch* to satisfy. Picking a branch is the caller's decision. Pass `[]` if your
127
+ tree needs no signature — but pass it.
128
+
129
+ ⚠ **What this builder does not do for you.** It adds signers, the withdrawal, the reference input
130
+ and the script witness. A tree whose satisfying branch needs a `Script` leaf (a second withdraw-0)
131
+ or a `Before`/`After` leaf (a validity interval) is **not** served by this step; such a deployment
132
+ must build its own genesis, or this builder must grow those inputs first. Left out deliberately
133
+ rather than guessed at.
134
+
135
+ **`BOOTSTRAP_STEPS` reordered, and the strings did not change.** `stake-registrations` moved from
136
+ last to **third**, ahead of `protocol-genesis`:
137
+
138
+ ```diff
139
+ - seed → multisig-genesis → protocol-genesis → reference-scripts → stake-registrations
140
+ + seed → multisig-genesis → stake-registrations → protocol-genesis → reference-scripts
141
+ ```
142
+
143
+ This is a ledger rule, not a preference: a reward account cannot be withdrawn from in the same
144
+ transaction that registers it, because withdrawals are applied against the state **before**
145
+ certificates. A caller that drives the sequence off `BOOTSTRAP_STEPS` follows automatically. One
146
+ that hard-coded the old order gets ledger code **3141**, *"rewards withdrawals must consume rewards
147
+ in full"* — a message that names a balance problem and not a missing certificate.
148
+
149
+ ### The blueprint
150
+
151
+ `blueprints/standard/v0.5.0-alpha.5/` ships alongside the older directories, pinned to upstream
152
+ `b83a041eaa053625c502f8ee64b607a787cf5f79` and **reproduced from source** (Aiken v1.1.23+8949565,
153
+ sha256 `ca53475332b5932f021fa134f823b932b05433ccd335bbf6251f18167826da66`, 164120 bytes). ⚠ That
154
+ commit is a **PR branch head** (`refs/pull/143/head`), not a commit on `main`; see
155
+ `blueprints/standard/v0.5.0-alpha.5/UPSTREAM_PIN.json` for why the pull ref is recorded alongside
156
+ the branch name.
157
+
158
+ ## Migrating to 0.11.0 (a wrong network label, and the bootstrap becomes public API)
159
+
160
+ Two changes. The first is breaking for plugin authors and silent in one shape the compiler will
161
+ not catch. The second is purely additive.
162
+
163
+ ### `SubstandardContext.network` was wrong, and its type hid it
164
+
165
+ It was declared `string` and computed from `chain.id` — which is the **address** network id, `1`
166
+ for mainnet and `0` for *every* testnet. **A preview client was therefore labelled `"preprod"`,
167
+ and so was a devnet.** It is now `network?: Network`, derived from the chain's **network magic**,
168
+ and a chain that is none of the three public networks yields **`undefined`** rather than a wrong
169
+ name.
170
+
171
+ ```diff
172
+ - network: string // "preprod" on preview, and on a devnet
173
+ + network?: Network // "preview" on preview; undefined on a devnet
174
+ ```
175
+
176
+ ⛔ **The shape the compiler will NOT catch.** At 0.10.0 the field was declared `string` while the
177
+ package exported a `Network` union, so a plugin that wanted the union **had no choice but to
178
+ cast**:
179
+
180
+ ```ts
181
+ switch (ctx.network as Network) { case "mainnet": … case "preprod": … case "preview": … }
182
+ ```
183
+
184
+ **That cast still compiles and now yields `undefined` at runtime** — the exhaustive switch falls
185
+ off the end and returns `undefined`, with no diagnostic anywhere. **Remove the cast.** Untyped
186
+ JavaScript has the same exposure: `` `https://${ctx.network}.…` `` becomes `https://undefined.…`,
187
+ `ctx.network.toUpperCase()` throws, and `JSON.stringify(ctx)` drops the key on a devnet.
188
+
189
+ ⚠ **The label is derived from the magic alone**, so a private network reusing a public magic is
190
+ labelled as that network — a mainnet-fork devnet reports `"mainnet"`. If you gate a destructive
191
+ path on `network !== "mainnet"`, that gate does not distinguish a fork from the real thing.
192
+ `networkFromChain(chain)` is exported if you want the same mapping yourself, and
193
+ `ctx.client.chain.networkMagic` / `.name` are on the same context object when you need more.
194
+
195
+ ### The protocol bootstrap is now exported
196
+
197
+ `planBootstrap()`, five step builders and `assembleDeploymentParams()` build the transactions that
198
+ stand up a protocol instance. **The SDK returns unsigned transactions and does not sign, submit or
199
+ await** — orchestration, key handling and confirmation stay with the caller, which is also what
200
+ lets a caller keep its own UTxO reservation and resume at a step rather than restart.
201
+
202
+ The sequence is **stepwise, not a batch**: the one-shot minting policies are parameterised by
203
+ output references of an earlier transaction, so step N+1 cannot be built until step N has been
204
+ submitted and observed.
205
+
206
+ ⚠ **Values a caller must decide are required inputs, not defaults** — `maxInlineDatumBytes` (a
207
+ security parameter), the one-shot nonces, the seed and reference-script lovelace, and
208
+ `availableUtxos`. There are no devnet defaults in the published path: no mnemonic, no endpoint, no
209
+ fixture values. `availableUtxos` is required on every step precisely so a caller can reserve its
210
+ seed UTxOs from coin selection — a wallet-wide selection can otherwise spend a seed a later step
211
+ names, or spend live reference scripts.
212
+
61
213
  ## Migrating to 0.10.0 (a required field on `DeploymentParams`)
62
214
 
63
215
  **0.10.0 adds one REQUIRED field and breaks every consumer that builds a `DeploymentParams`
@@ -0,0 +1,36 @@
1
+ {
2
+ "artifact": "plutus.json",
3
+ "sha256": "ca53475332b5932f021fa134f823b932b05433ccd335bbf6251f18167826da66",
4
+ "declares": {
5
+ "title": "cardano-foundation/cip113-programmable-tokens",
6
+ "version": "0.5.0-alpha.5",
7
+ "compiler": "Aiken v1.1.23+8949565",
8
+ "validators": 34
9
+ },
10
+ "upstream": {
11
+ "repo": "https://github.com/cardano-foundation/cip113-programmable-tokens",
12
+ "commit": "b83a041eaa053625c502f8ee64b607a787cf5f79",
13
+ "ref": "feat/verify-upgrade-authority-at-deployment",
14
+ "note": "PINNED TO THE COMMIT, NOT THE VERSION STRING, AND NOT THE BRANCH NAME — upstream publishes NO git tags, so \"0.5.0-alpha.5\" is a `version` field inside plutus.json on a MOVING branch. ⛔ THIS COMMIT IS NOT ON `main`. Reachability was VERIFIED, not assumed, by `git ls-remote` against the upstream URL on 2026-09-23: b83a041eaa053625c502f8ee64b607a787cf5f79 is BOTH `refs/heads/feat/verify-upgrade-authority-at-deployment` AND `refs/pull/143/head`, while `refs/heads/main` stood at c3d04b9ad0573f35852b1b2403d31956a685b12d. A PR head is the most perishable ref GitHub serves — a squash-merge orphans it the instant it lands, which has already bitten this repo twice (013c1154, then 2e067fe). The `refs/pull/143/head` co-reachability is what keeps this artifact fetchable after the branch is deleted; record it, do not rely on the branch name alone. ⚠ WHICH CLONE: this artifact was reproduced from /home/giovanni/Development/workspace/cip113-programmable-tokens-onchain. The sibling checkout whose path reads like \"the dependency\", workspace/deps/cip113-programmable-tokens, sits at 018415de and CANNOT produce this tree."
15
+ },
16
+ "blueprint_reproduced": true,
17
+ "provenance": "VERIFIED",
18
+ "reproduce": {
19
+ "requires": "Aiken v1.1.23+8949565",
20
+ "command": "git clone https://github.com/cardano-foundation/cip113-programmable-tokens && git fetch origin refs/pull/143/head && git checkout b83a041eaa053625c502f8ee64b607a787cf5f79 && aikup install v1.1.23 && rm plutus.json && aiken build",
21
+ "note": "`aikup install v1.1.23` with the version explicit, never bare `aikup install`, which follows latest and will stop reproducing this artifact the moment v1.1.24 ships. ⚠ aiken BUILDS ANYWAY on a mismatched compiler, emitting only a warning — check the preamble's compiler field, do not trust the environment."
22
+ },
23
+ "verified": {
24
+ "date": "2026-09-23",
25
+ "method": "REPRODUCED FROM SOURCE",
26
+ "findings": [
27
+ "OBSERVED: `aiken build` at upstream commit b83a041eaa053625c502f8ee64b607a787cf5f79, with Aiken v1.1.23+8949565 (the environment's installed v1.1.22 was upgraded by `aikup install v1.1.23` first), produced a plutus.json BYTE-IDENTICAL to the one upstream commits at that same commit. Both sha256 ca53475332b5932f021fa134f823b932b05433ccd335bbf6251f18167826da66, both 164120 bytes. The build ran in a THROWAWAY CLONE, and upstream's committed plutus.json was DELETED before the build so it could not be mistaken for output.",
28
+ "⚠ THE MUTABLE-DEPENDENCY CAVEAT THAT SCOPED EVERY EARLIER PIN IS GONE AT THIS COMMIT, AND THAT IS A CHANGE WORTH RECORDING RATHER THAN A SENTENCE WORTH DELETING. alpha.2, alpha.3 and alpha.4 all pinned `aiken-lang/fuzz` to the BRANCH `main`; at b83a041 aiken.toml pins it to the TAG `v2.2.0`. `aiken-lang/stdlib` remains the tag `v3.1.0`. Both dependencies are now immutable refs, so this reproducibility claim needs no scope note. aiken.lock's `[etags]` is empty either way — an empty etags table records nothing about what was fetched, which is exactly why the TAG, not the lockfile, is what makes this reproducible.",
29
+ "DELTA FROM alpha.4 (pin 7e8a63198c5b240135f1aa2f043ce5d7c046b2c4), MEASURED by hashing every validator's compiledCode either side rather than read from upstream's diff: 34 validators either side, no title added or removed. 31 are BYTE-IDENTICAL. The only three that move are `protocol_params.protocol_params.{mint,spend,else}` — which is ONE script, since every handler of an Aiken `validator` block shares a single compiledCode and hash. alpha.4 `20e612fcd69a51d0…` -> alpha.5 `edac935fccd8215a…` (sha256 prefixes of the compiledCode).",
30
+ "THE FUNCTIONAL CHANGE IS ONE LINE, in `protocol_params`'s mint handler: `pairs.has_key(self.withdrawals, genesis_params.upgrade_cred)?`. The genesis transaction that mints the protocol-params NFT must now carry a withdraw-0 from the credential the genesis datum names as `upgrade_cred` — proving the initial authority exists, can run and consents BEFORE it becomes canonical, by the same trampoline every later upgrade uses. Everything else in the validator's diff is prose.",
31
+ "⛔ THE CASCADE, AND IT IS WHY alpha.5 IS A REDEPLOYMENT AND NOT AN UPGRADE. `protocol_params`'s hash IS `paramsPolicy`, which parameterises `programmable_logic_base` (and through it transfer / third_party / unfracking / programmable_logic_global), `issuance_logic` and `issuance_mint`. Only `always_fail`, `issuance_cbor_hex_mint`, `registry` and `upgrade_multisig` hang off seeds or nonces instead, so ONLY those four keep their alpha.4 hashes for the same DeploymentParams. Measured, not assumed — see `test/hash-cascade.test.mjs`, which derives both sides from a live alpha.4 preview record's own seeds.",
32
+ "⚠ THE PARAMS DATUM DID NOT MOVE. Six fields, same order as alpha.4: programmable_logic_global_cred, issuance_logic_cred, transfer_cred, third_party_cred, upgrade_cred, pending_upgrade_cred. The alpha.3 -> alpha.4 field-order hazard recorded in the alpha.4 pin does NOT recur here; a positional reader built against alpha.4 reads alpha.5 correctly. What changed is the transaction shape at genesis, not the datum.",
33
+ "DERIVED: because the pin is keyed to a commit on a PR branch rather than a tag, re-running `aiken build` against that branch at a LATER date will legitimately produce a different artifact. That is not drift in this pin — it is a new pin. Do not update this file's sha256 to make a newer build pass; add a new directory."
34
+ ]
35
+ }
36
+ }