@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.
- package/README.md +152 -0
- package/blueprints/standard/v0.5.0-alpha.5/UPSTREAM_PIN.json +36 -0
- package/blueprints/standard/v0.5.0-alpha.5/plutus.json +1434 -0
- package/dist/core/evo-utils.d.ts +6 -1
- package/dist/core/evo-utils.d.ts.map +1 -1
- package/dist/core/evo-utils.js.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +81 -1
- package/dist/index.js.map +1 -1
- package/dist/standard/blueprint.d.ts +27 -3
- package/dist/standard/blueprint.d.ts.map +1 -1
- package/dist/standard/blueprint.js +27 -3
- package/dist/standard/blueprint.js.map +1 -1
- package/dist/standard/bootstrap.d.ts +662 -0
- package/dist/standard/bootstrap.d.ts.map +1 -0
- package/dist/standard/bootstrap.js +1221 -0
- package/dist/standard/bootstrap.js.map +1 -0
- package/dist/standard/scripts.d.ts +13 -2
- package/dist/standard/scripts.d.ts.map +1 -1
- package/dist/standard/scripts.js +13 -2
- package/dist/standard/scripts.js.map +1 -1
- package/dist/substandards/address-guard.d.ts +60 -0
- package/dist/substandards/address-guard.d.ts.map +1 -0
- package/dist/substandards/address-guard.js +159 -0
- package/dist/substandards/address-guard.js.map +1 -0
- package/dist/substandards/dummy/index.d.ts.map +1 -1
- package/dist/substandards/dummy/index.js +32 -5
- package/dist/substandards/dummy/index.js.map +1 -1
- package/dist/substandards/freeze-and-seize/index.d.ts.map +1 -1
- package/dist/substandards/freeze-and-seize/index.js +45 -9
- package/dist/substandards/freeze-and-seize/index.js.map +1 -1
- package/dist/substandards/interface.d.ts +20 -2
- package/dist/substandards/interface.d.ts.map +1 -1
- 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
|
+
}
|