From 5235a5d4c3ae3a1cb9400a2d3eab5960fba48770 Mon Sep 17 00:00:00 2001 From: Kayos Date: Thu, 7 May 2026 20:19:27 -0700 Subject: [PATCH] fix(dao): center starting_time in proposal_create validity window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For tiny-window test DAOs (preprod_test: 30s), the prior anchor (valid_from = starting_time, invalid_from = starting_time + 30) gave zero past-side slack. With koios block_time vs real chain clock skewing ±60s on the public endpoint, hitting that window is essentially a coin flip — the tx submits but never confirms because the next block lands after invalid_from. Centering keeps the validator-required width unchanged but moves valid_from to starting_time - 15, so the chain now has 15s of past-side slack to land the tx in a block. Same width, same in-script time check (starting_time still ∈ [valid_from, invalid_from)), better landing odds. Sulkta-shape DAOs (1800s windows) are unaffected: 900s of slack each side is plenty either way. --- .../aldabra-dao/src/builder/proposal_create.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/aldabra-dao/src/builder/proposal_create.rs b/crates/aldabra-dao/src/builder/proposal_create.rs index d569e8c..ca583c6 100644 --- a/crates/aldabra-dao/src/builder/proposal_create.rs +++ b/crates/aldabra-dao/src/builder/proposal_create.rs @@ -610,8 +610,20 @@ pub fn build_unsigned_proposal_create( // `pvalidateProposalStartingTime` is satisfied because // `starting_time_slot ∈ [valid_from, invalid_after - 1]` by // construction. - staging = staging.valid_from_slot(args.starting_time_slot); - staging = staging.invalid_from_slot(args.starting_time_slot + max_width_slots); + // 2026-05-08: CENTER `starting_time_slot` inside the validity range + // (rather than putting it at the lower bound). Tiny test DAOs run on + // a 30-second create_proposal_time_range_max_width, and koios's tip + // endpoint lag vs. the actual node can swing ±60s. With + // valid_from = starting_time, the window only spans [now, now+30]. + // If chain is even slightly past `now` when the tx lands, the tx + // expires. Centering gives [now-15, now+15] of slack — same width, + // same validator-bound, but the chain-now-at-block-time can drift + // ±15s without missing the window. + let half_width_slots = max_width_slots / 2; + let valid_from = args.starting_time_slot.saturating_sub(half_width_slots); + let invalid_from = valid_from + max_width_slots; + staging = staging.valid_from_slot(valid_from); + staging = staging.invalid_from_slot(invalid_from); let proposer_pkh_arr: [u8; 28] = args .proposer_pkh