Summary
Following up on #447 / #432 (native-script DRep voters), the same defect still exists for the third governance
entity, constitutional committee members. TxBuilder.authCommitteeHot() and TxBuilder.resignCommitteeCold() reject a native-script (multisig) cold credential, demanding a Plutus redeemer even when the native script is attached via .attachScript(). Native scripts are satisfied by vkey witnesses, not redeemers, so a multisig CC member currently cannot authorize a hot credential or resign through the SDK. (@evolution-sdk/evolution@0.5.11)
On-chain, this is valid: ' cardano-cli` builds both certificates with just the native script and the threshold vkey signatures, no redeemer:
cardano-cli conway governance committee create-hot-key-authorization-certificate \
--cold-script-file multisig.json \
--hot-verification-key-file hot.vkey \
--out-file auth.cert
cardano-cli conway transaction build ... \
--certificate-file auth.cert --certificate-script-file multisig.json ...
Root cause
In packages/evolution/src/sdk/builders/operations/Governance.ts, both CC programs fail eagerly at operation time, before the attached script can be classified as native vs Plutus:
// createAuthCommitteeHotProgram
const isScriptControlled = params.coldCredential._tag === "ScriptHash"
if (isScriptControlled && !params.redeemer) {
return yield* Effect.fail(
new TransactionBuilderError({
message: "Redeemer required for script-controlled cold credential authorization"
})
)
}
(createResignCommitteeColdProgram has the identical check for resignation.)
Reproduction
import {
Client, preprod, NativeScripts, ScriptHash, KeyHash, Address,
} from "@evolution-sdk/evolution";
// 2-of-3 native (multisig) script as the CC cold credential
const script = NativeScripts.makeScriptNOfK(
2n,
keyHashes.map((kh) => NativeScripts.makeScriptPubKey(kh).script), // 3 x 28-byte key
hashes
);
const coldCredential = new ScriptHash.ScriptHash({
hash: ScriptHash.fromScript(script).hash,
});
const hotCredential = new KeyHash.KeyHash({ hash: hotKeyHash }); // 28-byte key hash
const client = Client.make(preprod).withKoios({ baseUrl:
"https://preprod.koios.rest/api/v1" });
const utxos = await client.getUtxos(Address.fromBech32(fundedAddr));
await client.newTx()
.authCommitteeHot({ coldCredential, hotCredential })
.attachScript({ script }) // native script attached, no redeemer
.collectFrom({ inputs: utxos })
.build({ availableUtxos: utxos, changeAddress: Address.fromBech32(fundedAddr) });
Actual: build fails with TxBuilderError: "Redeemer required for script-controlled cold credential authorization". The equivalent
.resignCommitteeCold({ coldCredential, anchor: null }) fails the same way ("... cold credential resignation"). A key-hash cold credential builds fine, isolating the failure to script credentials.
Expected: the certificate builds with the native script in the witness set and the fee sized for the threshold number of vkey witnesses; no
redeemer, no scriptDataHash. A redeemer should be required only for Plutus-script cold credentials.
Suggested fix
Same recipe as #447 :
- Remove the two eager redeemer checks from
createAuthCommitteeHotProgram and createResignCommitteeColdProgram.
- Extend
validateCertRedeemers in internal/txBuilder.ts to resolve the cold credential script hash for AuthCommitteeHotCert and
ResignCommitteeColdCert (alongside the existing DRep cert cases), so the native-vs-Plutus distinction is made at build time once the script is attached or supplied via reference input.
The repro in the issue uses the public client.newTx() API to match #425's style; I verified the identical failure through makeTxBuilder directly.
Summary
Following up on #447 / #432 (native-script DRep voters), the same defect still exists for the third governance
entity, constitutional committee members.
TxBuilder.authCommitteeHot()andTxBuilder.resignCommitteeCold()reject a native-script (multisig) cold credential, demanding a Plutus redeemer even when the native script is attached via.attachScript(). Native scripts are satisfied by vkey witnesses, not redeemers, so a multisig CC member currently cannot authorize a hot credential or resign through the SDK. (@evolution-sdk/evolution@0.5.11)On-chain, this is valid: ' cardano-cli` builds both certificates with just the native script and the threshold vkey signatures, no redeemer:
Root cause
In
packages/evolution/src/sdk/builders/operations/Governance.ts, both CC programs fail eagerly at operation time, before the attached script can be classified as native vs Plutus:(
createResignCommitteeColdProgramhas the identical check for resignation.)Reproduction
Actual: build fails with
TxBuilderError: "Redeemer required for script-controlled cold credential authorization". The equivalent.resignCommitteeCold({ coldCredential, anchor: null })fails the same way ("... cold credential resignation"). A key-hash cold credential builds fine, isolating the failure to script credentials.Expected: the certificate builds with the native script in the witness set and the fee sized for the threshold number of vkey witnesses; no
redeemer, no
scriptDataHash. A redeemer should be required only for Plutus-script cold credentials.Suggested fix
Same recipe as #447 :
createAuthCommitteeHotProgramandcreateResignCommitteeColdProgram.validateCertRedeemersininternal/txBuilder.tsto resolve the cold credential script hash forAuthCommitteeHotCertandResignCommitteeColdCert(alongside the existing DRep cert cases), so the native-vs-Plutus distinction is made at build time once the script is attached or supplied via reference input.The repro in the issue uses the public client.newTx() API to match #425's style; I verified the identical failure through makeTxBuilder directly.