From 1bc4e949abc7aff4684e7257c7c6df0d01d51201 Mon Sep 17 00:00:00 2001 From: Kayos Date: Thu, 7 May 2026 18:09:20 -0700 Subject: [PATCH] fix(dao): use PermitVote (not DepositWithdraw) for stake spend on proposal_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stake validator's DepositWithdraw branch requires locked_by to stay EMPTY. proposal_create wants to ADD a Created lock for the new proposal — that's PermitVote's job, not DepositWithdraw's. Caught by base64-decoding the CekError's failing-script header on preprod_test today: 0x59 0x14 0x37 = bytes(5175) ⇒ 5178-byte script = stake validator (57d6b17f), not the governor we'd been suspecting. This is the audit C-2b fix that landed late. --- crates/aldabra-dao/src/builder/proposal_create.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crates/aldabra-dao/src/builder/proposal_create.rs b/crates/aldabra-dao/src/builder/proposal_create.rs index ef67c07..dd962dd 100644 --- a/crates/aldabra-dao/src/builder/proposal_create.rs +++ b/crates/aldabra-dao/src/builder/proposal_create.rs @@ -374,12 +374,13 @@ pub fn build_unsigned_proposal_create( // Governor spend: GovernorRedeemer::CreateProposal = Integer 0 (per // EnumIsData encoding fix 2026-05-05). // - // Stake spend: AUDIT-C2 — the reference tx (7c8db1432a07...) shows the - // stake input being spent with the stake validator invoked. Per Agora's - // design the stake validator's DepositWithdraw branch handles "modify - // stake AND register a Created lock" when the same tx has the governor's - // CreateProposal redeemer. For an InfoOnly proposal with no deposit: - // DepositWithdraw(0). The reference tx had DepositWithdraw(200) (50→250). + // Stake spend: redeemer is PermitVote (Constr 2 []). DepositWithdraw + // requires locked_by to STAY empty — which conflicts with adding a + // Created lock for the new proposal. PermitVote is the redeemer that + // grants new locks (for create/vote/cosign) on a stake. Caught + // 2026-05-07 PM via base64-decoded failing-script header (5178 bytes + // = stake validator); the bare CekError under traces-stripped Agora + // pointed at the stake's lock-state invariant. // // Mint redeemer: per `Agora/Proposal/Scripts.hs:118` the policy is // `\_gst _redeemer ctx -> ...` — redeemer is unused. Constr 0 [] is fine. @@ -388,7 +389,7 @@ pub fn build_unsigned_proposal_create( minicbor::to_vec(&crate::agora::plutus_data::int(0)?) .map_err(|e| DaoError::Cbor(format!("governor spend redeemer encode: {e}")))?; let stake_spend_redeemer_cbor = - minicbor::to_vec(&StakeRedeemer::DepositWithdraw(0).to_plutus_data()?) + minicbor::to_vec(&StakeRedeemer::PermitVote.to_plutus_data()?) .map_err(|e| DaoError::Cbor(format!("stake spend redeemer encode: {e}")))?; let mint_redeemer_cbor = minicbor::to_vec(&crate::agora::plutus_data::constr(0, vec![]))