Feat/update platform to latest contract + adding devnet support - #6
Merged
Conversation
…nfracking, upgrade_multisig)
Load all v0.4.0 validators from plutus.json and rebuild the parameterization
chain: always_fail -> coordination_spend -> protocol_params_mint -> {
programmable_logic_base, programmable_logic_global, unfracking } ->
upgrade_multisig -> issuance_cbor_hex_mint -> registry_spend ->
registry_mint. programmable_logic_base/global and unfracking are now
anchored on the protocol-params policy id (read live from the coordination
datum) instead of a fixed PLG credential, matching the in-place upgradability
model. The rest of deploy() is stubbed with `if (true) return;` pending
Task 2 (datums) and Task 3 (tx assembly).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ance-template datums
…view Review of the bootstrap-tx assembly found: the flat 50% margin on IssuanceCborHex's min-UTxO permanently burns extra ADA at an unspendable always_fail address for no benefit (the min-ada figure is already ledger-exact); the >=160 ADA funding precondition was stale once that output's ADA was raised; and dryRun/max-tx-size had no explicit guard. Switch to a small fixed buffer, raise the funding threshold with updated math, add a dryRun guard, and assert max-tx-size explicitly instead of relying on it having silently fit.
… params through deployment
…mplete-deployment JSON Review finding: PreprodProtocolDeploymentMintTest.deploy() has dryRun=false and is a plain @test, so running it submits a real preprod transaction and logs a BootstrapParams JSON that is silently missing the four v0.4.0 fields (coordinationParams, unfrackingParams, upgradeMultisigParams, unfrackingRefInput) this file has no wiring for. Disable it rather than fabricate values, until the file is ported to v0.4.0.
Flips PreviewProtocolDeploymentMintTest.deploy() to dryRun=false and submits the CIP-113 v0.4.0 bootstrap transaction to the local Yaci devnet. Verified on-chain: the three protocol UTxOs landed at their required addresses, the three withdraw-0 stake registrations (programmable_logic_global, unfracking, upgrade_multisig) are all present with matching script-hash credentials, and the coordination datum's five embedded credentials match the deployed script hashes. Records the emitted BootstrapParams as docs/deployments/devnet-v0.4.0.json (tx 2209835bd7e0914c9e58b62dc867f3ad4c04d80fa046fa9f174f07304678d75c). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… test - ProgrammableLogicBaseParams: ignore unknown properties so pre-v0.4.0 bootstrap JSONs (which still carry the old programmableLogicGlobalScriptHash key) deserialize again instead of throwing UnrecognizedPropertyException. Document that protocolParamsPolicyId is null for those legacy entries rather than silently renaming the stale key to a value it doesn't mean. - Remove the dead, hazardous registerAddress() test from both preview and preprod deployment-mint tests: it targets a stake credential none of this branch's withdraw-0 hashes match, has no assertions, and its allWalletUtxos.get(2) access can throw under the new >=2-UTxO precondition; drop the now-unused QuickTxBuilder import in both files. - Correct the stale "wallet-split fallback" rationale in DevnetFundingTest's funding comment now that deploy() registers all three withdraw-0s inline instead.
…ce, handoff file - skip reward accounts already registered on chain: upgrade_multisig is parameterised only by (signers, threshold), so redeploying with the same signer set collided with StakeKeyRegisteredDELEG and rejected the whole tx - derive the coordination nonce from the bootstrap UTxO so each deployment gets its own coordination address instead of all sharing one - write BootstrapParams to build/bootstrap-params.json (gradle swallows log.info, and this record is the deployment's only durable output) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…otstrap
WP-1: add protocol-bootstraps-devnet.json, populated from the fresh, verified
devnet deployment (build/bootstrap-params.json, tx 96343b91...ec015d). Make
ProtocolBootstrapService fail fast at load time, naming the exact missing
v0.4.0 component(s), instead of silently handing out a record with null
limbs that NPEs at first use. protocol-bootstraps-{preview,preprod}.json are
deliberately left incomplete (pre-v0.4.0 deployments) rather than fabricated.
WP-2: fix three ProtocolScriptBuilderService builders to match plutus.json's
validators[].parameters:
- programmable_logic_base: bare protocol-params policy id ByteArray
(was Constr(1, PLG hash) — wrong shape AND wrong value; this hash is the
payment credential of every programmable-token UTxO)
- registry_mint: add 3rd param registry_spend_cred (Credential)
- issuance_mint: add 4th param plg_stake_cred (Credential)
Added a unit test (no chain, no network) that re-derives programmable_logic_base,
programmable_logic_global, registry_mint, registry_spend, issuance_cbor_hex_mint
and protocol_params_mint from the devnet bootstrap JSON and asserts each against
the hash recorded there. Verified the test fails against the pre-fix builders
(2/7 cases) before restoring the fix. issuance_mint has no recorded ground-truth
hash in the bootstrap record (its 3rd param is a per-token substandard script,
not a protocol constant), so it gets a smoke assertion only, documented as such.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- ProtocolScriptBuilderServiceHashDerivationTest: replace the vacuous issuance_mint smoke assertion (any applied-parameter count yields a well-formed 56-hex-char hash, so it never exercised the plg_stake_cred fix) with a real check — split the applied script body on the substandard credential and assert PLG's hash lands in the postfix. Verified this now fails against the pre-fix 3-param builder alongside the two existing PLB/registry_mint failures. Also corrected the class Javadoc: it named the wrong deployment tx as this record's corroboration. - ProtocolBootstrapService.requireV040Complete: extend from 5 to all 13 ProtocolBootstrapParams components so a truncated/hand-edited bootstrap file (not just the two known-legacy ones) fails at load time by name instead of NPEing downstream. - ProtocolScriptBuilderService: add the missing contractOpt.isEmpty() guard to the programmable_logic_base builder, matching every sibling builder, so a renamed/missing blueprint entry fails with a named IllegalStateException instead of NoSuchElementException. - AppConfig.Network: add a "devnet" case (network id 0, magic 42 — this project's established local Yaci devnet convention) to getCardanoNetwork(). Without it, network=devnet silently fell through to Networks.mainnet(), so every address derived against the new protocol-bootstraps-devnet.json would be mainnet-shaped while the actual deployment lives at addr_test1.../stake_test1... — the same "valid-looking hash, wrong address" failure mode WP-2 fixed, at the network-tag layer instead of the script-parameter layer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every script parameterisation, datum shape and the hash-derivation test on this branch is written against this blueprint; leaving it uncommitted meant the branch did not build from a fresh clone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… (WP-3/WP-4)
RegistryNode grew from 5 to 7 fields on-chain (lib/registry_node.ak): minting_logic_script
at index 2 and unfracking_logic_script at index 5 are new, and every credential field now
carries its Aiken constructor tag (VerificationKey vs Script), not just a bare hash. The old
Java model wrote a 5-field constr (rejected outright by v0.4.0's registry_mint) and, on read,
silently shifted fields into the wrong names while always emitting Script(...) even for the
unset "empty_vkey" default that registry_mint's whole-record equality check requires to be a
VerificationKey.
- Add PlutusCredentialCodec: bidirectional Credential <-> PlutusData, keeping the constructor
tag as part of the value instead of collapsing it to a bare hash.
- Rework model/onchain/RegistryNode + RegistryNodeParser (and the duplicate parser,
model/DirectorySetNode) to the 7-field shape. The parser now walks the deserialized
PlutusData graph directly and throws on any arity/shape mismatch instead of defaulting a
missing field to a plausible-looking value.
- Extend RegistryNodeEntity/DTO with mintingLogicScript and unfrackingLogicScript; update
RegistryEventListener and RegistryService.deleteOrphanedNodes to populate them.
- Flyway V12: existing registry_node rows are silently wrong (not merely incomplete) under
the old parser, so the migration clears them rather than leaving corrupt data queryable,
then adds the two columns. Does not by itself replay chain history — the SQL comments spell
out the manual yaci-store cursor rewind an operator needs, since no automated reindex
trigger exists in this codebase today. Added RegistryReindexHealthCheck to surface that gap
at startup instead of the /registry/* endpoints silently returning zero tokens.
- Add protocol-params-devnet.json (transaction-id allowlist), previously missing for the
devnet network profile — without it protocol_params never indexes, which starves
registry_node regardless of any reindex.
- Minimal compile-only fixes to the 5 substandard handlers (WP-5 scope, not ported here):
wire the already-computed minting/transfer script hashes into their new named slots,
leave third-party/unfracking at the "forbidden" empty_vkey default with WP-5 TODOs, except
freeze-and-seize where its own code comment ("Issuer to be used for minting/burning/sieze")
justifies reusing the admin script for both slots.
Round-trip tests assert the origin node's serialized form is byte-identical to
PreviewProtocolDeploymentMintTest's known-good (on-chain-accepted) datum, and that 5/6-field
constrs are rejected rather than silently accepted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
issuance_mint's redeemer is now types.MintingRegistryProof directly: the
SmartTokenMintingAction { minting_logic_cred, minting_registry_proof }
wrapper is gone from the blueprint, because the credential became the
validator's compile-time parameter and is pinned to the policy id by
registry_mint's is_programmable_token_id_valid. Every site now emits the
bare proof — Constr 1 [Int] (OutputIndex) on the registration path,
Constr 0 [Int] (RefInput) on subsequent mint and burn.
RegistryInsert's second field is a Credential rather than a bare
ByteArray, so the substandard hash is wrapped as Script(hash) = Constr 1.
The two WP-3 TODO slots get real values. third_party_transfer_logic_script
(index 4) cannot be empty — is_28_byte_credential rejects it on a
non-origin node — and it is the sole gate on ThirdPartyAct seizure via
validate_3rd_party's has_key_or_fail on tx.withdrawals. So:
freeze-and-seize -> issuer_admin_contract (its declared seize authority)
security-token -> third_party_transfer_logic_validator, newly wired
through a SecurityTokenScriptBuilderService builder
dummy, kyc, -> always_fail. None of the three declares a
kyc-extended third-party validator, and their issuer-admin
scripts authorise issuance, not seizure; pointing
index 4 at an unsatisfiable script forbids seizure
structurally instead of inventing an authority.
Mutable later via is_field_updated_registry_node.
unfracking_logic_script (index 5) stays empty_vkey in all five — unfracking
forbidden, least permission, and no substandard declares a hook.
Also fixes DummySubstandardHandler.buildMintTransaction looking up
"issue.issue.withdraw", which does not exist in the dummy blueprint
(the validators live in transfer.ak), so every dummy mint died on an
unchecked Optional.get().
Verified end-to-end on the yaci devnet against the live v0.4.0 deployment
96343b91: registration tx 1498366a (block 13290) wrote a 7-field node with
third_party = Script(always_fail) and unfracking = VerificationKey(#""),
re-emitting the covering node under whole-record equality; subsequent mint
tx 61f0dd7c (block 13338) exercised the RefInput branch. Both accepted by
the node, not just the local evaluator.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… at 7ae4ce3
Replace the vendored fn-bafin-cardano-sc fork with a byte-identical copy of
FluidTokens/fn-bafin-cardano-sc @7ae4ce3db39a. The fork's deliberate 2<->3
registry-node index swap is gone: upstream's natural 2/3/4 ordering is already
exactly v0.4.0's RegistryNode layout, so the swap became the thing that would
break it.
Blueprint: upstream's committed plutus.json is used verbatim and was proven not
stale — rebuilding its own sources with aiken v1.1.21+42babe5 (the compiler its
preamble records; note its aiken.toml declares v1.1.22) reproduces every
validator hash and compiledCode byte-for-byte. No recompile, so no compiler
divergence to record. Every deployed validator hash except denylist spend
changes versus the fork, so any previously stored security-token script hash,
policy id or address is stale.
Handler port. Upstream is ahead of the fork, and the deltas are silent ones:
* GlobalStateDatum 9 -> 11 fields. requires_sender_kyc is INSERTED at index 8
(pushing requires_receiver_kyc 8 -> 9) and network_id appended at 10.
buildTransferTransaction read the live receiver-KYC flag at index 8, which
under upstream is requires_sender_kyc — it gated recipient proofs on the
wrong field. Datum length checks are now == 11, not >= 9, so a pre-pin
global state is rejected with an explicit "must be re-bootstrapped" error
instead of being misread.
* GlobalStateSpendAction constructors shift: SetRequiresSenderKyc inserted at
6, SetRequiresReceiverKyc 6 -> 7, UpdateMemberRootHash 7 -> 8, RotateAdmin
8 -> 9. Emitting a stale index still builds a valid tx, it just performs a
different action.
* Denylist add/remove redeemers gain power_user_node_ref_input_index, and the
sanction gate moves from the GS admin credential to a power user holding
is_admin who must sign. The power-user node is attached as a second
reference input and BOTH ref-input indices are now derived from the
lex-sorted (txHash, outputIndex) order rather than a hardcoded 0.
* network_id moved out of the compile-time env module into the datum, so the
off-chain side now owns it (kycNetworkId()).
New replaceGsField() mirrors upstream's utils.replace_data_field and now backs
all eleven "preserve the datum, change one field" sites; upstream compares the
whole output datum with equals_data, so one dropped field silently invalidates
the transaction.
Pinning. UPSTREAM_PIN.json records the SHA plus a sha256 per vendored file;
SecurityTokenUpstreamPinTest enforces it offline on every build and also asserts
the backend's own resources copy of plutus.json is byte-identical to the
vendored blueprint (aiken build does not sync it, and the backend loads it);
verify-upstream-pin.sh re-downloads the pinned tarball and diffs, so the
manifest cannot be regenerated over a divergent tree. Both guards were verified
negatively as well as positively. Chosen over a submodule because a submodule
covers neither the resources copy nor a checkout that forgot --recurse-submodules.
Known blocker, reported not worked around: the fork also carried two undeclared
patches upstream does not have — a registration-mode short-circuit in
minting_logic_script.ak and a mint/burn short-circuit in transfer_logic_script.ak.
The platform's registration tx withdraws-0 from the substandard's minting logic,
which upstream answers by deriving the issuance policy id from a registry node
among the reference inputs; at registration time that node is being created in
the same tx. Registration therefore cannot validate as currently shaped. Fixing
it is a platform decision (drop the withdraw at quantity 0, or ask upstream for
a registration branch), so the stale "rubber-stamp" comments were replaced with
accurate BLOCKED notes rather than a guessed restructure. buildMintTransaction
is unaffected — it already references the directory entry and uses the strict path.
Also found: requires_sender_kyc is dead upstream at this SHA —
transfer_logic_script.ak:109 gates the per-SENDER check on requires_receiver_kyc,
so that one flag controls both sides. The field is still written so the datum
matches exactly.
Verified: compileJava + compileTestJava clean; SecurityTokenUpstreamPinTest 2/2
plus two negative cases; verify-upstream-pin.sh green against live GitHub. No
on-chain security-token tx was submitted — there is no JUnit entry point for
that flow and registration is blocked above. The 63 pre-existing suite failures
(Spring/JPA wiring, pre-v0.4.0 bootstrap JSON, chain-dependent and bad-fixture
tests) are unchanged; no failing test touches security-token code.
Note: upstream's own README.md is the one file NOT vendored — this work package
was told never to commit a markdown file, so the conservative reading was taken.
It is documentation only, no compiled artifact depends on it, and the exclusion
is recorded in UPSTREAM_PIN.json and named explicitly in the verify script;
re-adding the file makes the pin test fail with UNEXPECTED README.md. Every
other upstream file is byte-identical with no exclusions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Registry-node slot 4 is the credential CIP-113's ThirdPartyAct branch demands a withdrawal from (registry_node.with_key_and_3rd_party_logic → programmable_logic/third_party.ak `has_key_or_fail`), and buildBurnTransaction takes that branch. WP-5 put the BaFin third_party_transfer_logic_validator there while the burn tx only withdraws mintingLogic + programmableLogicGlobal, so every security-token burn failed Plutus evaluation. The preferred fix — withdraw from the third-party validator — is not reachable at the pinned upstream commit: security-token/validators/third_party_transfer_logic_script.ak:44 passes `constants.transfer_logic_script_registry_node_index` (= 3) rather than `..._third_party_..._index` (= 4), so the validator asserts that registry field 3 holds its OWN hash. Field 3 must hold transferLogic for validate_transfer, so the third-party validator can never self-locate in a node that also supports transfers. The vendored tree is verbatim-pinned (FluidTokens/fn-bafin-cardano-sc 7ae4ce3) and must not be edited. Slot 4 therefore holds mintingLogic — the one vendored withdraw validator that self-locates correctly (index 2) and that the burn tx already withdraws. It still gates on a power-user node, so the branch stays authority-gated, though on can_burn rather than can_force_transfer and without the destination KYC/denylist checks. Same slot choice as FreezeAndSeizeHandler. Rewrites the stale burn-path comment that claimed field 3 held mintingLogic. Also: - IssueTokenTest: port the three issuance_mint parameterisations to the v0.4.0 four-parameter form, the directory datums to the 7-field RegistryNode (minting/transfer slots were swapped), and mintOnly() to a RefInput proof against a real registry reference input. - freezeandsieze PreviewMintTest: MintingRegistryProof is now the redeemer directly; add the missing registry reference input. PreviewWipeTest's dead twin fixed and marked as unported. - DummySubstandardHandler: filter a null scriptHash before it reaches Credential.fromScript. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ift guard WP-6 code-review follow-ups. Registration cannot validate at the pinned upstream revision: upstream's minting_logic_script.ak resolves the CIP-113 registry node with list.expect_find over the transaction's REFERENCE inputs, but registration creates that node in the same transaction. It used to trap deep in script evaluation as an opaque UPLC error — after buildGlobalStateInitTransaction had already persisted a SecurityTokenRegistrationEntity and a bootstrap power-user row, so every attempt left orphan rows. buildRegistrationTransaction and buildFullRegistrationChain now return a typed error naming the blocker before any build or DB write; the implementations are preserved as *Unchecked for when upstream is fixed. The offline drift guard claimed to run in every build but did not: the vendored tree sits outside the Gradle project and was not a declared input, so editing src/substandards/security-token/** left `test` UP-TO-DATE and SecurityTokenUpstreamPinTest silently never executed. Declared as a test input. Also: - transfer: upstream gates the SENDER kyc check on gs_datum.requires_receiver_kyc (the replaced fork checked it unconditionally). The senderMpfProofCborHex precondition moved below the live GS read and is gated on that flag, emitting the placeholder Membership shape when false — otherwise tokens bootstrapped with requiresReceiverKyc=false were untransferable, since nobody can produce a proof against an empty member root. Fixed the TTL bound that would then NPE. - RotateAdmin: global_state.ak needs both the outgoing and incoming admin in extra_signatories; buildSingleGsUpdateTx now takes a list of required signers. The incoming admin's signature must still be collected by the frontend. - verify-upstream-pin.sh --regenerate: rsync --delete so a dropped upstream file cannot abort step 1 with the tree already replaced; refresh vendored_at. - kycNetworkId() throws on an unrecognised network instead of baking in mainnet 0x2, which is immutable after genesis and checked against every attestation. - Align the pin test's `build` prune with the script's (any depth). - gitignore .claude/ (holds worktrees: full second copies of the repo). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ps-<network>.json BOOTSTRAP_OUT points the handoff writer at the resource file directly. The file is an array keyed by txHash that ProtocolBootstrapService selects from via programmable.token.default.txHash, so deployments are merged in rather than overwritten and older ones stay addressable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hed code Replaces the inline java.net.http.*, java.nio.file.*, Jackson TypeReference and cardano-client-lib references this branch introduced with imports. Where an import was added, all existing uses of that same type in the file were converted too, so no file is left half-qualified. com.bloxbean.cardano.client.common.model.Network in AppConfig stays qualified — the enclosing class declares its own nested Network, so importing it would clash. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kammerlo
marked this pull request as draft
August 12, 2026 07:19
Re-vendors src/substandards/security-token/ verbatim from a NEW upstream
repository, not merely a new SHA:
was FluidTokens/fn-bafin-cardano-sc @ 7ae4ce3db39a
now easy1staking-com/fn-bafin-cardano-sc @ e69c66afccee
(branch fix/cmta-requirements-fixes, which merges FluidTokens:main;
the SHA is pinned, never the branch)
This fixes all three defects in docs/UPSTREAM-BAFIN-DEFECTS.md:
A third_party_transfer_logic_script.ak now passes
third_party_transfer_logic_script_registry_node_index (4) instead of the
transfer index (3), so forced transfer / seizure is reachable at all.
B derive_issuance_policy_id_from_registry_node takes a
registry_node_ref_input_index and addresses the node BY INDEX instead of
list.expect_find over the registry policy alone.
C MintingLogicScriptWithdrawRedeemer became a sum type with a RegisterToken
constructor that resolves the node from outputs, making CIP-113
registration possible.
Blueprint verified NOT stale against its sources: the committed plutus.json
records compiler v1.1.23+8949565, which is also the locally installed aiken, and
rebuilding the vendored sources reproduces byte-identical compiledCode for all
21 validators. (Note the brief's "v1.1.22, same as before" was wrong on both
counts - the old pin was v1.1.21+42babe5.) `aiken check` on the tree is
143/143 green.
Validator hashes: every validator changed except denylist_validator.spend.
Pin machinery updated for the repository change, not just the SHA - neither
verify-upstream-pin.sh nor SecurityTokenUpstreamPinTest hard-codes an owner any
more; both read it from UPSTREAM_PIN.json, so a future re-pin edits one file.
The pin test's note claiming the local compiler differs from the blueprint's is
now false and was corrected rather than left to rot.
Both blueprints synced (the backend loads its own resource copy; aiken build
does not update it).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…workarounds ABI port -------- GlobalStateDatum gained `deactivated` at index 1, shifting mintable_amount to 2 and every later field up by one. This is silent and dangerous - reading mintable_amount at the old index 1 now yields a Bool - so every GS field index is now a named GS_IDX_* constant and no call site uses a raw literal. GS_DATUM_FIELD_COUNT 11 -> 12, and the genesis datum writes the new field. All three withdraw redeemers gained a leading registry_node_ref_input_index. Each is computed against the LEX-SORTED reference-input list (reference inputs are ledger-sorted by output reference before the script sees them), reusing the existing lexIndex helper. The minting-logic redeemer is now a sum type: - registration uses RegisterToken (constructor 1) with an OUTPUT index - mint/burn uses MintBurn (constructor 0) with a REF-INPUT index Mint destinations are now vetted like transfer destinations, so mints carry a denylist covering-node reference input they did not need before. Added findDenylistCoveringNode, which picks the greatest key strictly below the target rather than always the root - the root only covers everything while the list is empty. Undo of workaround 1 (commit dffb3d7) ------------------------------------- buildRegistrationTransaction / buildFullRegistrationChain no longer return REGISTRATION_BLOCKED_AT_UPSTREAM_PIN; the guard and the constant are deleted and the real bodies are restored. Registration is now the structural (quantity 0) RegisterToken shape: GlobalState REFERENCED, no GS spend, no power-user gate, no issuance mint - exactly what the zero-mint branch validates. Registration-carrying-a-first-mint is deliberately NOT built. The contract supports it, but it layers the whole MintBurn gate on top: GS spent under MintSecurity, a can_mint power user as a reference input that also signs, and a denylist covering node per destination. No power user exists on chain at registration time (AddPowerUser is a later tx), so the shape is unreachable for a first-time issuer anyway. It returns a typed error saying so rather than emitting a redeemer whose unset indices would trap in the evaluator. Undo of workaround 2 (commit 0ec401a) ------------------------------------- Registry-node slot 4 holds the substandard's real third_party_transfer_logic_validator again instead of mintingLogic. buildBurnTransaction therefore had to change: CIP-113's ThirdPartyAct requires a withdrawal keyed on whatever slot 4 names, and the burn can no longer free-ride on the mintingLogic withdrawal it needed anyway. It now also withdraws from the third-party validator. That withdrawal is UNVERIFIED on chain and carries a known risk, recorded here rather than discovered later: minting_logic's burn path reads GlobalState from self.inputs (it must be SPENT so MintSecurity enforces the cap), while the third-party validator reads it from self.reference_inputs. The one GS UTxO is therefore placed in both lists. Babbage forbade that overlap; Conway permits it. If the burn is ever rejected for non-disjoint reference inputs, that is the reason, and the two requirements are genuinely irreconcilable in one tx. The burn also now needs a power user holding can_force_transfer in addition to can_burn. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gradle discards the test JVM's streams, so log.info and System.out from a test are invisible — including the deployment test's BootstrapParams and derived script hashes. --info does not help; only testLogging.showStandardStreams does. Opt-in rather than always-on so the 116-test suite stays readable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wallet order is arbitrary. On a faucet-funded preview account most entries are small change, so taking the first two failed the >=175 ADA precondition with the funds sitting right there. Utxo is not Comparable, so an unqualified sorted() would have thrown at runtime. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…l registration buildFullRegistrationChain passes the genesis tx's GlobalState output into buildRegistrationTransaction, but the override was only consulted when willMint. The chain registers structurally (quantity 0), so willMint is false and the code fell through to a chain lookup for an NFT minted by a transaction that has not been submitted yet — failing with 'run the genesis init step first' while holding the UTxO it needed. Prefer the override in both branches, matching buildAddPowerUserTransaction. AddPowerUser only readFrom()s GlobalState, so the genesis output is still the live one at registration time. Also drops a stale BLOCKED note (resolved by the @e69c66a re-pin) and the TransactionUtil FQNs added after the import refactor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…egister its stake cred The genesis init tx was 18027 / 16384 bytes. 7211 of those were minting_logic attached inline purely so a Cert redeemer could run its publish handler. Conway's RegCert carries no witness requirement, so that handler never runs and the script need not be attached. Verified empirically by the protocol deployment, which registers three script stake credentials with a bare registerStakeAddress and no validator attached -- including upgrade_multisig, which has no publish handler at all (else(_) fail) and could not have registered if a witness were required. Drops the attach and the Cert redeemer injection; keeps the RegCert rewrite, which is still needed for the explicit 2 ADA deposit. Inline script bytes in this tx go 16653 -> 9442. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e script witness aa2f158 removed the attached minting_logic script but left the preBalanceTx rewrite from StakeRegistration to RegCert. That is the wrong half: RegCert IS witness-required for a script credential, so the submission failed with MissingScriptWitnessesUTXOW. The two must move together. Keep the legacy StakeRegistration that Bloxbean emits -- still valid in Conway, requires no witness, no script attached, and 7211 bytes smaller. This matches the protocol deployment, and all nine script-credential registrations currently on preview are STAKE_REGISTRATION; none is a RegCert. The PHASE 4 transferLogic cert tx keeps RegCert + attached script + Cert redeemer, which is internally consistent and left alone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kammerlo
marked this pull request as ready for review
August 14, 2026 13:02
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR updates the platform to use the latest Aiken implementation of the registry.
Additionally it gives devnet support. The issue is that the devnet can't be tested end to end right now since a browser wallet is missing.