From c5a879a4913018f220bd5baad42cb7df1e449c7f Mon Sep 17 00:00:00 2001 From: CollinsKRO <286802049+CollinsKRO@users.noreply.github.com> Date: Wed, 30 Sep 2026 17:29:02 +0000 Subject: [PATCH] fix(round): reject seals outside the committed Drand reveal window (#376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bid seal is only meaningful for the Drand round the auction committed to open. The contract now stores that rule: `commit` takes the seal's round and rejects, before any escrow is locked, any value that differs from the stored `reveal_round` β€” with stable errors SealRoundTooEarly (40), SealRoundTooLate (41), and InvalidSealRoundZero (42), the last also covering zero/overflowing reveal rounds at `create_round` via the new checked_time_of_round. Off-chain, @sub-rosa/tlock enforces the same window in sealBid/sealPayload through assertSealRoundWindow (SealRoundError with matching stable reasons), so the TS helper and the contract reject the same fixture set built from the repo's quicknet chain parameters. The SDK forwards sealed.sealRound as seal_round, bindings are regenerated, drand-tools' timeOfRound rejects rounds the chain can never publish, and ERRORS.md plus all error registry guards stay in lock-step. πŸ€– Generated with Codebuff Co-Authored-By: Codebuff --- contracts/round/ERRORS.md | 4 + contracts/round/src/drand.rs | 35 +- contracts/round/src/error_paths.rs | 85 ++- contracts/round/src/lib.rs | 18 +- contracts/round/src/test.rs | 62 +- contracts/round/src/types.rs | 5 + ...round_seal_ttl_covers_reveal_window.1.json | 4 + ...r_and_settle_work_after_seal_expiry.1.json | 8 + .../test/commit_locks_escrow.1.json | 3 + .../commit_on_settled_round_rejected.1.json | 4 + ...e_before_close_refunds_prior_escrow.1.json | 6 + .../contract_balance_zero_after_settle.1.json | 8 + .../contract_balance_zero_after_void.1.json | 8 + ...nd_rejects_overflowing_reveal_round.1.json | 330 +++++++++ .../test/double_settle_rejected.1.json | 4 + .../test/double_void_rejected.1.json | 4 + .../test/duplicate_reveal_rejected.1.json | 4 + .../error_path_already_cleared.1.json | 4 + .../error_path_already_revealed.1.json | 4 + .../error_path_already_settled.1.json | 4 + .../error_path_bid_exceeds_escrow.1.json | 3 + .../error_path_hash_mismatch.1.json | 4 + .../error_path_invalid_drand_signature.1.json | 4 + .../error_path_invalid_seal_round_zero.1.json | 691 ++++++++++++++++++ .../error_paths/error_path_not_cleared.1.json | 4 + .../error_path_reveal_already_open.1.json | 4 + .../error_path_reveal_not_open.1.json | 4 + .../error_path_reveal_still_open.1.json | 4 + .../error_path_reveal_window_closed.1.json | 4 + .../error_path_round_voided.1.json | 4 + .../error_path_seal_round_too_early.1.json | 691 ++++++++++++++++++ .../error_path_seal_round_too_late.1.json | 691 ++++++++++++++++++ .../error_path_wrong_status.1.json | 4 + ...full_lifecycle_real_drand_signature.1.json | 6 + .../get_bidders_page_cursor_at_total.1.json | 9 + ...et_bidders_page_cursor_beyond_total.1.json | 9 + .../test/get_bidders_page_exact.1.json | 9 + .../test/get_bidders_page_final.1.json | 15 + .../test/get_bidders_page_multi.1.json | 30 + .../test/get_bidders_page_partial.1.json | 15 + .../get_bidders_page_preserves_order.1.json | 15 + .../get_bidders_returns_ordered_index.1.json | 9 + ...get_bidders_still_returns_full_list.1.json | 15 + .../test/highest_bid_table_driven.1.json | 12 + .../test/highest_bid_table_driven.2.json | 12 + .../test/highest_bid_table_driven.3.json | 12 + .../test/highest_bid_table_driven.4.json | 4 + ...s_deterministic_first_inserter_wins.1.json | 8 + ...s_deterministic_first_inserter_wins.2.json | 8 + ...after_window_even_with_seal_present.1.json | 4 + .../test/lowest_bid_table_driven.1.json | 12 + .../test/lowest_bid_table_driven.2.json | 12 + .../test/lowest_bid_table_driven.3.json | 12 + ...s_deterministic_first_inserter_wins.1.json | 8 + ..._reveal_bid_is_skipped_during_clear.1.json | 8 + .../no_valid_bids_after_reveal_window.1.json | 4 + ...id_state_after_lifecycle_completion.1.json | 4 + ..._extends_seal_through_reveal_window.1.json | 4 + ...en_reveal_on_settled_round_rejected.1.json | 4 + ...e_to_larger_escrow_conserves_tokens.1.json | 6 + ...ated_overwrites_escrow_conservation.1.json | 12 + ...eveal_hash_mismatch_invalidates_bid.1.json | 8 + .../reveal_on_settled_round_rejected.1.json | 8 + .../test/reveal_wrong_nonce_rejected.1.json | 4 + ...ed_case_42_highest_bid_reproducible.1.json | 12 + ...eded_case_7_lowest_bid_reproducible.1.json | 12 + .../test/settle_exact_payouts_table.1.json | 8 + .../test/settle_exact_payouts_table.2.json | 8 + .../test/settle_exact_payouts_table.3.json | 12 + ...rsistent_state_survives_seal_expiry.1.json | 4 + .../token_conservation_full_lifecycle.1.json | 8 + .../test/void_after_grace_refunds_all.1.json | 6 + ...d_round_refunds_survive_seal_expiry.1.json | 4 + packages/round-bindings/src/index.ts | 5 +- packages/sdk/scripts/live-smoke.ts | 1 + packages/sdk/scripts/mainnet-micro.ts | 1 + packages/sdk/src/client.test.ts | 1 + packages/sdk/src/client.ts | 23 + packages/sdk/src/encoding.test.ts | 1 + packages/sdk/src/preflight.test.ts | 1 + packages/tlock/package.json | 4 +- packages/tlock/src/index.ts | 7 + packages/tlock/src/payload.ts | 8 + packages/tlock/src/seal.test.ts | 96 ++- packages/tlock/src/seal.ts | 15 +- packages/tlock/src/window.test.ts | 101 +++ packages/tlock/src/window.ts | 71 ++ scripts/check-round-errors.test.mjs | 8 +- services/agent/src/bidder.test.ts | 2 +- services/agent/src/bidder.ts | 1 + services/auction-template/sealed-auction.ts | 4 +- services/drand-tools/src/quicknet.ts | 17 +- services/keeper/scripts/keeper-e2e.ts | 1 + services/keeper/scripts/lifecycle-e2e.ts | 4 +- 94 files changed, 3407 insertions(+), 53 deletions(-) create mode 100644 contracts/round/test_snapshots/test/create_round_rejects_overflowing_reveal_round.1.json create mode 100644 contracts/round/test_snapshots/test/error_paths/error_path_invalid_seal_round_zero.1.json create mode 100644 contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_early.1.json create mode 100644 contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_late.1.json create mode 100644 packages/tlock/src/window.test.ts create mode 100644 packages/tlock/src/window.ts diff --git a/contracts/round/ERRORS.md b/contracts/round/ERRORS.md index 529c9c5d..f3742e5d 100644 --- a/contracts/round/ERRORS.md +++ b/contracts/round/ERRORS.md @@ -28,6 +28,7 @@ stay in sync with `contracts/round/src/types.rs`. | 1–4 | Initialization & state lookup | | 10–22 | Lifecycle & timing | | 30–39 | Cryptography & validation | +| 40–42 | Seal-round window (issue #376) | ## Initialization & state lookup (1–4) @@ -70,6 +71,9 @@ stay in sync with `contracts/round/src/types.rs`. | 37 | `NoValidBids` | `settle` | `round.winner` is `None` on a round whose status is `Cleared`. | Round has no winner to settle against. | Investigate: under current behavior the contract transitions to `Voided` (with all escrow refunded) when no valid bid is revealed, so this code should not appear in normal flow. If it does, the round is in an inconsistent state and warrants a manual review. | | 38 | `RoundFull` | `commit` | `round.bidders.len() >= MAX_BIDDERS` (500). | The round has reached its bidder cap. | Start a new round to accept further bidders. | | 39 | `InvalidLimit` | `get_bidders_page` | `limit == 0` or `limit > 100`. | Page size must be between 1 and 100 (inclusive). | Pass a `limit` in `[1, 100]`; use `next_cursor` from the previous page to walk larger rounds. | +| 40 | `SealRoundTooEarly` | `commit` | `seal_round < round.reveal_round`: the seal names a Drand round before the one the auction committed to open. | The sealed bid is locked to the wrong Drand round. | Reseal the bid to the round published in the `created` event (`reveal_round`) and commit again; no escrow was moved. | +| 41 | `SealRoundTooLate` | `commit` | `seal_round > round.reveal_round`: the seal names a Drand round after the one the auction committed to open. | The sealed bid is locked to the wrong Drand round. | Reseal the bid to the round published in the `created` event (`reveal_round`) and commit again; no escrow was moved. | +| 42 | `InvalidSealRoundZero` | `create_round`, `commit` | `reveal_round == 0` at round creation, or `seal_round == 0` at commit. A zero or overflowing round can never be published by the Drand chain. | The Drand round number is malformed. | Use a positive round the quicknet chain can actually publish (`genesis + period Γ— R` must fit in `u64`); check before locking escrow. | ## How to use this table diff --git a/contracts/round/src/drand.rs b/contracts/round/src/drand.rs index 2f716460..9ddd7b59 100644 --- a/contracts/round/src/drand.rs +++ b/contracts/round/src/drand.rs @@ -3,7 +3,7 @@ use soroban_sdk::{ Bytes, BytesN, Env, Vec, }; -use crate::types::GlobalConfig; +use crate::types::{Error, GlobalConfig, Round}; /// Verify a Drand `round` threshold signature on-chain. /// @@ -55,10 +55,31 @@ pub fn verify_round( /// Wall-clock time (unix seconds) at which Drand round `round` is published. /// -/// Saturating arithmetic: an absurdly large `round` clamps to `u64::MAX`, which -/// `create_round` then rejects via its deadline checks rather than panicking. -pub fn time_of_round(config: &GlobalConfig, round: u64) -> u64 { - config - .drand_genesis - .saturating_add(config.drand_period.saturating_mul(round)) +/// Returns `None` for a zero round or an intermediate product/sum that would +/// exceed `u64` β€” i.e. a round number the chain can never publish. Callers must +/// reject `None` instead of comparing a saturating placeholder against real +/// deadlines: an overflowing round must fail validation before any escrow is +/// locked, never silently map to the far future or the epoch. +pub fn checked_time_of_round(config: &GlobalConfig, round: u64) -> Option { + if round == 0 { + return None; + } + let offset = config.drand_period.checked_mul(round)?; + config.drand_genesis.checked_add(offset) +} + +/// Validate that a bidder's seal round equals the round the auction stored. +/// +/// The allowed reveal round is always `round.reveal_round` β€” the value the +/// operator committed to at `create_round` β€” never a caller-supplied value. A +/// seal for any other round cannot be committed (issue #376). Returns a stable +/// [`Error`] for each failure shape so SDK callers and integrators can branch +/// without parsing strings. +pub fn validate_seal_round(round: &Round, seal_round: u64) -> Result<(), Error> { + match seal_round { + 0 => Err(Error::InvalidSealRoundZero), + r if r == round.reveal_round => Ok(()), + r if r > round.reveal_round => Err(Error::SealRoundTooLate), + _ => Err(Error::SealRoundTooEarly), + } } diff --git a/contracts/round/src/error_paths.rs b/contracts/round/src/error_paths.rs index e8b2545b..21f3efba 100644 --- a/contracts/round/src/error_paths.rs +++ b/contracts/round/src/error_paths.rs @@ -45,6 +45,9 @@ const ERROR_PATH_REGISTRY: &[(Error, &'static str)] = &[ (Error::NoValidBids, "error_path_no_valid_bids"), (Error::RoundFull, "error_path_round_full"), (Error::InvalidLimit, "error_path_invalid_limit"), + (Error::SealRoundTooEarly, "error_path_seal_round_too_early"), + (Error::SealRoundTooLate, "error_path_seal_round_too_late"), + (Error::InvalidSealRoundZero, "error_path_invalid_seal_round_zero"), ]; fn oversized_bytes(env: &Env, len: u32) -> Bytes { @@ -87,7 +90,7 @@ fn settle_happy_path(f: &Fixture, t_reveal: u64, commit_deadline: u64, reveal_de fn error_paths_registry_covers_every_variant() { assert_eq!( ERROR_PATH_REGISTRY.len(), - 27, + 30, "update ERROR_PATH_REGISTRY when adding/removing Error variants" ); for (variant, name) in ERROR_PATH_REGISTRY { @@ -188,6 +191,7 @@ fn error_path_commit_closed() { &Bytes::from_array(&f.env, b"c"), &600, &Bytes::from_array(&f.env, b"id"), + &2_000, ), Error::CommitClosed, ); @@ -355,6 +359,7 @@ fn error_path_wrong_status() { &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id"), + &2_000, ), Error::WrongStatus, ); @@ -445,6 +450,7 @@ fn error_path_invalid_amount() { &Bytes::from_array(&f.env, b"c"), &0, &Bytes::from_array(&f.env, b"id"), + &2_000, ), Error::InvalidAmount, ); @@ -466,6 +472,7 @@ fn error_path_bid_exceeds_escrow() { &Bytes::from_array(&f.env, b"sealed"), &500, &Bytes::from_array(&f.env, b"id-blob"), + &VEC_ROUND, ); f.env.ledger().with_mut(|l| l.timestamp = t_reveal + 1); f.client.open_reveal(&id, &real_sig(&f.env)); @@ -522,6 +529,7 @@ fn error_path_round_full() { &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id"), + &2_000, ), Error::RoundFull, ); @@ -535,3 +543,78 @@ fn error_path_invalid_limit() { assert_try_contract_err(f.client.try_get_bidders_page(&id, &0, &0), Error::InvalidLimit); assert_try_contract_err(f.client.try_get_bidders_page(&id, &0, &101), Error::InvalidLimit); } + +/// Issue #376: a seal for a round earlier than the stored reveal round is +/// rejected with a stable error before any escrow is locked. +#[test] +fn error_path_seal_round_too_early() { + let (f, _t_reveal, _commit_deadline, _reveal_deadline) = setup_drand(); + let operator = Address::generate(&f.env); + let id = drand_round(&f, &operator, _commit_deadline, _reveal_deadline, ClearingRule::HighestBid); + let bidder = funded_bidder(&f, 1_000); + let nonce = b32(&f.env, 0x01); + let h = commitment(&f.env, 500, &nonce); + assert_try_contract_err( + f.client.try_commit( + &id, + &bidder, + &h, + &Bytes::from_array(&f.env, b"sealed"), + &500, + &Bytes::from_array(&f.env, b"id-blob"), + &(VEC_ROUND - 1), + ), + Error::SealRoundTooEarly, + ); + // No escrow was locked: the bid state must not exist. + assert_try_contract_err(f.client.try_get_bid_state(&id, &bidder), Error::BidNotFound); +} + +/// Issue #376: a seal for a round later than the stored reveal round is +/// rejected with a stable error before any escrow is locked. +#[test] +fn error_path_seal_round_too_late() { + let (f, _t_reveal, _commit_deadline, _reveal_deadline) = setup_drand(); + let operator = Address::generate(&f.env); + let id = drand_round(&f, &operator, _commit_deadline, _reveal_deadline, ClearingRule::HighestBid); + let bidder = funded_bidder(&f, 1_000); + let nonce = b32(&f.env, 0x01); + let h = commitment(&f.env, 500, &nonce); + assert_try_contract_err( + f.client.try_commit( + &id, + &bidder, + &h, + &Bytes::from_array(&f.env, b"sealed"), + &500, + &Bytes::from_array(&f.env, b"id-blob"), + &(VEC_ROUND + 1), + ), + Error::SealRoundTooLate, + ); + assert_try_contract_err(f.client.try_get_bid_state(&id, &bidder), Error::BidNotFound); +} + +/// Issue #376: a zero seal round is malformed and rejected before escrow. +#[test] +fn error_path_invalid_seal_round_zero() { + let f = setup(); + let operator = Address::generate(&f.env); + let id = open_round(&f, &operator); + let bidder = funded_bidder(&f, 1_000); + let nonce = b32(&f.env, 0x01); + let h = commitment(&f.env, 500, &nonce); + assert_try_contract_err( + f.client.try_commit( + &id, + &bidder, + &h, + &Bytes::from_array(&f.env, b"sealed"), + &500, + &Bytes::from_array(&f.env, b"id-blob"), + &0, + ), + Error::InvalidSealRoundZero, + ); + assert_try_contract_err(f.client.try_get_bid_state(&id, &bidder), Error::BidNotFound); +} diff --git a/contracts/round/src/lib.rs b/contracts/round/src/lib.rs index c0e40058..5729c069 100644 --- a/contracts/round/src/lib.rs +++ b/contracts/round/src/lib.rs @@ -81,14 +81,19 @@ impl SubRosaRound { bump_instance(&env); if reveal_round == 0 { - return Err(Error::InvalidAmount); + return Err(Error::InvalidSealRoundZero); } if auditor_pubkey.len() > MAX_AUDITOR_PUBKEY { return Err(Error::PayloadTooLarge); } let now = env.ledger().timestamp(); - let t_reveal = drand::time_of_round(&config, reveal_round); + // Reject a reveal round the quicknet chain can never publish before any + // deadline comparison: genesis + periodΓ—R must fit in u64. A saturating + // placeholder here would let an overflowing round pass the deadline + // checks and strand the round past the void grace window. + let t_reveal = drand::checked_time_of_round(&config, reveal_round) + .ok_or(Error::InvalidSealRoundZero)?; // Commit must close strictly before R is published, otherwise a bidder // could decrypt others' sealed bids before committing. @@ -132,6 +137,9 @@ impl SubRosaRound { /// - `escrow` is a public USDC budget and an upper bound on the sealed bid; /// locked now so the winner can always pay. /// - `auditor_blob` is the bidder identity encrypted to the auditor key. + /// - `seal_round` must equal the round's stored `reveal_round`: the seal is + /// only meaningful for the Drand round this auction committed to open. + /// Mismatched seals are rejected before any escrow is locked. pub fn commit( env: Env, round_id: u64, @@ -140,6 +148,7 @@ impl SubRosaRound { ciphertext: Bytes, escrow: i128, auditor_blob: Bytes, + seal_round: u64, ) -> Result<(), Error> { bidder.require_auth(); let config = get_config(&env)?; @@ -163,6 +172,11 @@ impl SubRosaRound { if ciphertext.len() > MAX_CIPHERTEXT || auditor_blob.len() > MAX_AUDITOR_BLOB { return Err(Error::PayloadTooLarge); } + // The allowed reveal round is the one stored on the auction, not a + // caller-supplied value. Rejecting here β€” before the escrow transfer β€” + // means a seal for a different Drand round can never lock funds and the + // bidder keeps their full error budget for honest resubmission. + drand::validate_seal_round(&round, seal_round)?; let usdc = token::Client::new(&env, &config.usdc); let contract = env.current_contract_address(); diff --git a/contracts/round/src/test.rs b/contracts/round/src/test.rs index 596af7eb..decd3b09 100644 --- a/contracts/round/src/test.rs +++ b/contracts/round/src/test.rs @@ -181,6 +181,7 @@ fn commitment(env: &Env, value: i128, nonce: &BytesN<32>) -> BytesN<32> { fn commit_bid(f: &Fixture, round_id: u64, bidder: &Address, value: i128, escrow: i128, nonce_byte: u8) -> BytesN<32> { let nonce = b32(&f.env, nonce_byte); let h = commitment(&f.env, value, &nonce); + let round = f.client.get_round(&round_id); f.client.commit( &round_id, bidder, @@ -188,6 +189,7 @@ fn commit_bid(f: &Fixture, round_id: u64, bidder: &Address, value: i128, escrow: &Bytes::from_array(&f.env, b"sealed"), &escrow, &Bytes::from_array(&f.env, b"id-blob"), + &round.reveal_round, ); nonce } @@ -310,13 +312,27 @@ fn create_round_rejects_deadline_in_past() { assert!(res.is_err()); } +/// Issue #376: a reveal round the quicknet chain can never publish β€” genesis + +/// periodΓ—R overflows u64 β€” must fail create_round instead of saturating into +/// a far-future deadline that would strand the round past the void window. +#[test] +fn create_round_rejects_overflowing_reveal_round() { + let f = setup(); + let operator = Address::generate(&f.env); + let res = f.client.try_create_round( + &operator, &b32(&f.env, 1), &u64::MAX, &ClearingRule::HighestBid, + &1_500, &2_500, &Bytes::from_array(&f.env, b"a"), + ); + assert!(res.is_err()); +} + #[test] fn commit_locks_escrow() { let f = setup(); let operator = Address::generate(&f.env); let id = open_round(&f, &operator); let bidder = funded_bidder(&f, 1_000); - f.client.commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"ciphertext"), &600, &Bytes::from_array(&f.env, b"id-blob")); + f.client.commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"ciphertext"), &600, &Bytes::from_array(&f.env, b"id-blob"), &2_000); assert_eq!(f.usdc_token.balance(&bidder), 400); assert_eq!(f.usdc_token.balance(&f.client.address), 600); let round = f.client.get_round(&id); @@ -333,9 +349,9 @@ fn get_bidders_returns_ordered_index() { let id = open_round(&f, &operator); let a = funded_bidder(&f, 1_000); let b = funded_bidder(&f, 1_000); - f.client.commit(&id, &a, &b32(&f.env, 1), &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id")); - f.client.commit(&id, &b, &b32(&f.env, 2), &Bytes::from_array(&f.env, b"c"), &200, &Bytes::from_array(&f.env, b"id")); - f.client.commit(&id, &a, &b32(&f.env, 3), &Bytes::from_array(&f.env, b"c"), &150, &Bytes::from_array(&f.env, b"id")); + f.client.commit(&id, &a, &b32(&f.env, 1), &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id"), &2_000); + f.client.commit(&id, &b, &b32(&f.env, 2), &Bytes::from_array(&f.env, b"c"), &200, &Bytes::from_array(&f.env, b"id"), &2_000); + f.client.commit(&id, &a, &b32(&f.env, 3), &Bytes::from_array(&f.env, b"c"), &150, &Bytes::from_array(&f.env, b"id"), &2_000); let bidders = f.client.get_bidders(&id); assert_eq!(bidders.len(), 2); assert_eq!(bidders.get(0).unwrap(), a); @@ -348,8 +364,8 @@ fn commit_overwrite_before_close_refunds_prior_escrow() { let operator = Address::generate(&f.env); let id = open_round(&f, &operator); let bidder = funded_bidder(&f, 1_000); - f.client.commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"c1"), &600, &Bytes::from_array(&f.env, b"id")); - f.client.commit(&id, &bidder, &b32(&f.env, 9), &Bytes::from_array(&f.env, b"c2"), &200, &Bytes::from_array(&f.env, b"id")); + f.client.commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"c1"), &600, &Bytes::from_array(&f.env, b"id"), &2_000); + f.client.commit(&id, &bidder, &b32(&f.env, 9), &Bytes::from_array(&f.env, b"c2"), &200, &Bytes::from_array(&f.env, b"id"), &2_000); assert_eq!(f.usdc_token.balance(&bidder), 800); assert_eq!(f.usdc_token.balance(&f.client.address), 200); assert_eq!(f.client.get_round(&id).bidders.len(), 1); @@ -362,7 +378,7 @@ fn commit_after_deadline_rejected() { let id = open_round(&f, &operator); let bidder = funded_bidder(&f, 1_000); f.env.ledger().with_mut(|l| l.timestamp = 1_600); - let res = f.client.try_commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"c"), &600, &Bytes::from_array(&f.env, b"id")); + let res = f.client.try_commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"c"), &600, &Bytes::from_array(&f.env, b"id"), &2_000); assert!(res.is_err()); } @@ -372,7 +388,7 @@ fn commit_zero_escrow_rejected() { let operator = Address::generate(&f.env); let id = open_round(&f, &operator); let bidder = funded_bidder(&f, 1_000); - let res = f.client.try_commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"c"), &0, &Bytes::from_array(&f.env, b"id")); + let res = f.client.try_commit(&id, &bidder, &b32(&f.env, 7), &Bytes::from_array(&f.env, b"c"), &0, &Bytes::from_array(&f.env, b"id"), &2_000); assert!(res.is_err()); } @@ -383,8 +399,8 @@ fn void_after_grace_refunds_all() { let id = open_round(&f, &operator); let a = funded_bidder(&f, 1_000); let bbidder = funded_bidder(&f, 1_000); - f.client.commit(&id, &a, &b32(&f.env, 1), &Bytes::from_array(&f.env, b"c"), &300, &Bytes::from_array(&f.env, b"id")); - f.client.commit(&id, &bbidder, &b32(&f.env, 2), &Bytes::from_array(&f.env, b"c"), &500, &Bytes::from_array(&f.env, b"id")); + f.client.commit(&id, &a, &b32(&f.env, 1), &Bytes::from_array(&f.env, b"c"), &300, &Bytes::from_array(&f.env, b"id"), &2_000); + f.client.commit(&id, &bbidder, &b32(&f.env, 2), &Bytes::from_array(&f.env, b"c"), &500, &Bytes::from_array(&f.env, b"id"), &2_000); f.env.ledger().with_mut(|l| l.timestamp = 2_500 + 3_600 + 1); f.client.void(&id); assert_eq!(f.usdc_token.balance(&a), 1_000); @@ -625,7 +641,7 @@ fn repeated_overwrites_escrow_conservation() { let initial: i128 = 2_000; let escrows: &[i128] = &[500, 300, 800, 100]; for (i, &escrow) in escrows.iter().enumerate() { - f.client.commit(&id, &bidder, &b32(&f.env, (i + 1) as u8), &Bytes::from_array(&f.env, b"c"), &escrow, &Bytes::from_array(&f.env, b"id")); + f.client.commit(&id, &bidder, &b32(&f.env, (i + 1) as u8), &Bytes::from_array(&f.env, b"c"), &escrow, &Bytes::from_array(&f.env, b"id"), &2_000); let sum = f.usdc_token.balance(&bidder) + f.usdc_token.balance(&f.client.address); assert_eq!(sum, initial, "conservation violated after overwrite #{}", i + 1); assert_eq!(f.usdc_token.balance(&f.client.address), escrow, "contract must hold latest escrow after #{}", i + 1); @@ -639,8 +655,8 @@ fn overwrite_to_larger_escrow_conserves_tokens() { let operator = Address::generate(&f.env); let id = open_round(&f, &operator); let bidder = funded_bidder(&f, 1_000); - f.client.commit(&id, &bidder, &b32(&f.env, 1), &Bytes::from_array(&f.env, b"c"), &200, &Bytes::from_array(&f.env, b"id")); - f.client.commit(&id, &bidder, &b32(&f.env, 2), &Bytes::from_array(&f.env, b"c"), &700, &Bytes::from_array(&f.env, b"id")); + f.client.commit(&id, &bidder, &b32(&f.env, 1), &Bytes::from_array(&f.env, b"c"), &200, &Bytes::from_array(&f.env, b"id"), &2_000); + f.client.commit(&id, &bidder, &b32(&f.env, 2), &Bytes::from_array(&f.env, b"c"), &700, &Bytes::from_array(&f.env, b"id"), &2_000); assert_eq!(f.usdc_token.balance(&bidder), 300); assert_eq!(f.usdc_token.balance(&f.client.address), 700); assert_eq!(f.usdc_token.balance(&bidder) + f.usdc_token.balance(&f.client.address), 1_000); @@ -829,7 +845,7 @@ fn commit_on_settled_round_rejected() { f.client.settle(&id); let late = funded_bidder(&f, 1_000); - assert!(f.client.try_commit(&id, &late, &b32(&f.env, 0x77), &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id")).is_err(), + assert!(f.client.try_commit(&id, &late, &b32(&f.env, 0x77), &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id"), &2_000).is_err(), "commit on settled round must be rejected"); } @@ -1004,8 +1020,8 @@ fn full_lifecycle_real_drand_signature() { let a_value: i128 = 700; let b_value: i128 = 500; - f.client.commit(&id, &alice, &commitment(&f.env, a_value, &a_nonce), &Bytes::from_array(&f.env, b"sealedA"), &1_000, &Bytes::from_array(&f.env, b"idA")); - f.client.commit(&id, &bob, &commitment(&f.env, b_value, &b_nonce), &Bytes::from_array(&f.env, b"sealedB"), &1_000, &Bytes::from_array(&f.env, b"idB")); + f.client.commit(&id, &alice, &commitment(&f.env, a_value, &a_nonce), &Bytes::from_array(&f.env, b"sealedA"), &1_000, &Bytes::from_array(&f.env, b"idA"), &VEC_ROUND); + f.client.commit(&id, &bob, &commitment(&f.env, b_value, &b_nonce), &Bytes::from_array(&f.env, b"sealedB"), &1_000, &Bytes::from_array(&f.env, b"idB"), &VEC_ROUND); f.env.ledger().with_mut(|l| l.timestamp = t_reveal + 1); let sig = hexn::<96>(&f.env, VEC_SIG_G1); @@ -1045,7 +1061,7 @@ fn round_with_n_bidders(n: u32) -> (Fixture, u64, Vec
) { let mut all = Vec::new(&f.env); for i in 0..n { let bidder = funded_bidder(&f, 1_000 + i as i128); - f.client.commit(&id, &bidder, &b32(&f.env, (i + 1) as u8), &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id")); + f.client.commit(&id, &bidder, &b32(&f.env, (i + 1) as u8), &Bytes::from_array(&f.env, b"c"), &100, &Bytes::from_array(&f.env, b"id"), &2_000); all.push_back(bidder); } (f, id, all) @@ -1401,6 +1417,10 @@ pub(super) const DOCUMENTED_ERROR_CODES: &[(Error, u32)] = &[ (Error::NoValidBids, 37), (Error::RoundFull, 38), (Error::InvalidLimit, 39), + // ── 40–42: seal-round window (issue #376) ── + (Error::SealRoundTooEarly, 40), + (Error::SealRoundTooLate, 41), + (Error::InvalidSealRoundZero, 42), ]; /// Convert an `Error` to its on-chain discriminant using the [`repr(u32)`] @@ -1439,6 +1459,9 @@ pub(super) fn variant_name(e: Error) -> &'static str { Error::NoValidBids => "NoValidBids", Error::RoundFull => "RoundFull", Error::InvalidLimit => "InvalidLimit", + Error::SealRoundTooEarly => "SealRoundTooEarly", + Error::SealRoundTooLate => "SealRoundTooLate", + Error::InvalidSealRoundZero => "InvalidSealRoundZero", } } @@ -1486,7 +1509,7 @@ fn error_table_enumerates_every_variant() { // DOCUMENTED_ERROR_CODES. assert_eq!( DOCUMENTED_ERROR_CODES.len(), - 27, + 30, "DOCUMENTED_ERROR_CODES appears missing entries. The exhaustive \ `variant_name` match already enforces parity at compile time β€” \ update it together with this list and contracts/round/ERRORS.md." @@ -1499,11 +1522,12 @@ fn error_codes_use_reserved_ranges() { // 1–4 β†’ initialization/lookup // 10–22 β†’ lifecycle/timing // 30–39 β†’ crypto/validation + // 40–42 β†’ seal-round window // New categories should pick a fresh, contiguous range β€” not collide with // logging conventions β€” and update ERRORS.md at the same time. for (variant, code) in DOCUMENTED_ERROR_CODES { let name = variant_name(*variant); - let in_range = matches!(*code, 1..=4 | 10..=22 | 30..=39); + let in_range = matches!(*code, 1..=4 | 10..=22 | 30..=42); assert!( in_range, "{name} = {code} falls outside the documented code ranges; \ diff --git a/contracts/round/src/types.rs b/contracts/round/src/types.rs index ea7010a8..459749f9 100644 --- a/contracts/round/src/types.rs +++ b/contracts/round/src/types.rs @@ -35,6 +35,11 @@ pub enum Error { NoValidBids = 37, RoundFull = 38, InvalidLimit = 39, + // Seal-round window (issue #376): a seal must name the round the auction + // committed to open β€” exactly `Round::reveal_round`, never Β±1 or 0. + SealRoundTooEarly = 40, + SealRoundTooLate = 41, + InvalidSealRoundZero = 42, } /// Round lifecycle. Mirrors the state machine in PRD Β§6. diff --git a/contracts/round/test_snapshots/test/active_round_seal_ttl_covers_reveal_window.1.json b/contracts/round/test_snapshots/test/active_round_seal_ttl_covers_reveal_window.1.json index 76b2bf86..249fdfa5 100644 --- a/contracts/round/test_snapshots/test/active_round_seal_ttl_covers_reveal_window.1.json +++ b/contracts/round/test_snapshots/test/active_round_seal_ttl_covers_reveal_window.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/clear_and_settle_work_after_seal_expiry.1.json b/contracts/round/test_snapshots/test/clear_and_settle_work_after_seal_expiry.1.json index d73a91b5..db7874ca 100644 --- a/contracts/round/test_snapshots/test/clear_and_settle_work_after_seal_expiry.1.json +++ b/contracts/round/test_snapshots/test/clear_and_settle_work_after_seal_expiry.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/commit_locks_escrow.1.json b/contracts/round/test_snapshots/test/commit_locks_escrow.1.json index 819c5ebf..753f58c4 100644 --- a/contracts/round/test_snapshots/test/commit_locks_escrow.1.json +++ b/contracts/round/test_snapshots/test/commit_locks_escrow.1.json @@ -119,6 +119,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/commit_on_settled_round_rejected.1.json b/contracts/round/test_snapshots/test/commit_on_settled_round_rejected.1.json index d00836ee..64d46530 100644 --- a/contracts/round/test_snapshots/test/commit_on_settled_round_rejected.1.json +++ b/contracts/round/test_snapshots/test/commit_on_settled_round_rejected.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/commit_overwrite_before_close_refunds_prior_escrow.1.json b/contracts/round/test_snapshots/test/commit_overwrite_before_close_refunds_prior_escrow.1.json index 423dd7c0..814feb44 100644 --- a/contracts/round/test_snapshots/test/commit_overwrite_before_close_refunds_prior_escrow.1.json +++ b/contracts/round/test_snapshots/test/commit_overwrite_before_close_refunds_prior_escrow.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -180,6 +183,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/contract_balance_zero_after_settle.1.json b/contracts/round/test_snapshots/test/contract_balance_zero_after_settle.1.json index 15732178..a3123b5a 100644 --- a/contracts/round/test_snapshots/test/contract_balance_zero_after_settle.1.json +++ b/contracts/round/test_snapshots/test/contract_balance_zero_after_settle.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/contract_balance_zero_after_void.1.json b/contracts/round/test_snapshots/test/contract_balance_zero_after_void.1.json index f66a2015..65e2928a 100644 --- a/contracts/round/test_snapshots/test/contract_balance_zero_after_void.1.json +++ b/contracts/round/test_snapshots/test/contract_balance_zero_after_void.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/create_round_rejects_overflowing_reveal_round.1.json b/contracts/round/test_snapshots/test/create_round_rejects_overflowing_reveal_round.1.json new file mode 100644 index 00000000..8fd6b355 --- /dev/null +++ b/contracts/round/test_snapshots/test/create_round_rejects_overflowing_reveal_round.1.json @@ -0,0 +1,330 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + { + "function": { + "contract_fn": { + "contract_address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 1000, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "balance": 0, + "seq_num": 0, + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + null + ] + ], + [ + { + "contract_data": { + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Config" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "drand_genesis" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "drand_period" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "drand_pubkey" + }, + "val": { + "bytes": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "dst" + }, + "val": { + "bytes": "424c535f5349475f424c53313233383147315f584d443a5348412d3235365f535357555f524f5f4e554c5f" + } + }, + { + "key": { + "symbol": "g2_neg_generator" + }, + "val": { + "bytes": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "usdc" + }, + "val": { + "address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL" + } + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 1036800 + ] + ], + [ + { + "contract_data": { + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000002" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 120960 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 1036800 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/round/test_snapshots/test/double_settle_rejected.1.json b/contracts/round/test_snapshots/test/double_settle_rejected.1.json index 4b824884..2c8ace49 100644 --- a/contracts/round/test_snapshots/test/double_settle_rejected.1.json +++ b/contracts/round/test_snapshots/test/double_settle_rejected.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/double_void_rejected.1.json b/contracts/round/test_snapshots/test/double_void_rejected.1.json index 217f3888..2197c2b9 100644 --- a/contracts/round/test_snapshots/test/double_void_rejected.1.json +++ b/contracts/round/test_snapshots/test/double_void_rejected.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/duplicate_reveal_rejected.1.json b/contracts/round/test_snapshots/test/duplicate_reveal_rejected.1.json index b03a8aa4..5e0fc28a 100644 --- a/contracts/round/test_snapshots/test/duplicate_reveal_rejected.1.json +++ b/contracts/round/test_snapshots/test/duplicate_reveal_rejected.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_already_cleared.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_already_cleared.1.json index 94f41d71..a702e855 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_already_cleared.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_already_cleared.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_already_revealed.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_already_revealed.1.json index d5108fd9..c951397a 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_already_revealed.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_already_revealed.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_already_settled.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_already_settled.1.json index 1ed0aaed..d5263b52 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_already_settled.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_already_settled.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_bid_exceeds_escrow.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_bid_exceeds_escrow.1.json index 87078c8b..d009d614 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_bid_exceeds_escrow.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_bid_exceeds_escrow.1.json @@ -119,6 +119,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_hash_mismatch.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_hash_mismatch.1.json index 9e773344..5361a859 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_hash_mismatch.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_hash_mismatch.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_invalid_drand_signature.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_invalid_drand_signature.1.json index b25088d4..dec0da84 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_invalid_drand_signature.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_invalid_drand_signature.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155654 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_invalid_seal_round_zero.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_invalid_seal_round_zero.1.json new file mode 100644 index 00000000..351f0d99 --- /dev/null +++ b/contracts/round/test_snapshots/test/error_paths/error_path_invalid_seal_round_zero.1.json @@ -0,0 +1,691 @@ +{ + "generators": { + "address": 5, + "nonce": 0 + }, + "auth": [ + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + { + "function": { + "contract_fn": { + "contract_address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "function_name": "create_round", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "u64": 2000 + }, + { + "vec": [ + { + "symbol": "HighestBid" + } + ] + }, + { + "u64": 1500 + }, + { + "u64": 2500 + }, + { + "bytes": "61756469746f722d7075626b6579" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "function_name": "mint", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + }, + { + "i128": { + "hi": 0, + "lo": 1000 + } + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 1000, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "balance": 0, + "seq_num": 0, + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + null + ] + ], + [ + { + "contract_data": { + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Round" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Round" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_pubkey" + }, + "val": { + "bytes": "61756469746f722d7075626b6579" + } + }, + { + "key": { + "symbol": "bidders" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "clearing_rule" + }, + "val": { + "vec": [ + { + "symbol": "HighestBid" + } + ] + } + }, + { + "key": { + "symbol": "commit_deadline" + }, + "val": { + "u64": 1500 + } + }, + { + "key": { + "symbol": "item_ref" + }, + "val": { + "bytes": "0101010101010101010101010101010101010101010101010101010101010101" + } + }, + { + "key": { + "symbol": "operator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "reveal_deadline" + }, + "val": { + "u64": 2500 + } + }, + { + "key": { + "symbol": "reveal_round" + }, + "val": { + "u64": 2000 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "vec": [ + { + "symbol": "Open" + } + ] + } + }, + { + "key": { + "symbol": "winner" + }, + "val": "void" + }, + { + "key": { + "symbol": "winning_bid" + }, + "val": { + "i128": { + "hi": 0, + "lo": 0 + } + } + } + ] + } + } + }, + "ext": "v0" + }, + 1036800 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Config" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "drand_genesis" + }, + "val": { + "u64": 0 + } + }, + { + "key": { + "symbol": "drand_period" + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "symbol": "drand_pubkey" + }, + "val": { + "bytes": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "dst" + }, + "val": { + "bytes": "424c535f5349475f424c53313233383147315f584d443a5348412d3235365f535357555f524f5f4e554c5f" + } + }, + { + "key": { + "symbol": "g2_neg_generator" + }, + "val": { + "bytes": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "usdc" + }, + "val": { + "address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RoundCounter" + } + ] + }, + "val": { + "u64": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 1036800 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "amount" + }, + "val": { + "i128": { + "hi": 0, + "lo": 1000 + } + } + }, + { + "key": { + "symbol": "authorized" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "clawback" + }, + "val": { + "bool": false + } + } + ] + } + } + }, + "ext": "v0" + }, + 518400 + ] + ], + [ + { + "contract_data": { + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000002" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 120960 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 1036800 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_not_cleared.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_not_cleared.1.json index 68ce19c8..92cca8a3 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_not_cleared.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_not_cleared.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_already_open.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_already_open.1.json index 9e773344..5361a859 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_already_open.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_already_open.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_not_open.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_not_open.1.json index 3a1ad968..ba3470eb 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_not_open.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_not_open.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_still_open.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_still_open.1.json index 9e773344..5361a859 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_still_open.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_still_open.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_window_closed.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_window_closed.1.json index 3298ede7..dfbfebb8 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_reveal_window_closed.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_reveal_window_closed.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_round_voided.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_round_voided.1.json index 2600f07e..9b7c5bd9 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_round_voided.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_round_voided.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_early.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_early.1.json new file mode 100644 index 00000000..b7577c1a --- /dev/null +++ b/contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_early.1.json @@ -0,0 +1,691 @@ +{ + "generators": { + "address": 5, + "nonce": 0 + }, + "auth": [ + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + { + "function": { + "contract_fn": { + "contract_address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "function_name": "create_round", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "abababababababababababababababababababababababababababababababab" + }, + { + "u64": 29155653 + }, + { + "vec": [ + { + "symbol": "HighestBid" + } + ] + }, + { + "u64": 1780270226 + }, + { + "u64": 1780270526 + }, + { + "bytes": "61756469746f72" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "function_name": "mint", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + }, + { + "i128": { + "hi": 0, + "lo": 1000 + } + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 1780270126, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "balance": 0, + "seq_num": 0, + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + null + ] + ], + [ + { + "contract_data": { + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Round" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Round" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_pubkey" + }, + "val": { + "bytes": "61756469746f72" + } + }, + { + "key": { + "symbol": "bidders" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "clearing_rule" + }, + "val": { + "vec": [ + { + "symbol": "HighestBid" + } + ] + } + }, + { + "key": { + "symbol": "commit_deadline" + }, + "val": { + "u64": 1780270226 + } + }, + { + "key": { + "symbol": "item_ref" + }, + "val": { + "bytes": "abababababababababababababababababababababababababababababababab" + } + }, + { + "key": { + "symbol": "operator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "reveal_deadline" + }, + "val": { + "u64": 1780270526 + } + }, + { + "key": { + "symbol": "reveal_round" + }, + "val": { + "u64": 29155653 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "vec": [ + { + "symbol": "Open" + } + ] + } + }, + { + "key": { + "symbol": "winner" + }, + "val": "void" + }, + { + "key": { + "symbol": "winning_bid" + }, + "val": { + "i128": { + "hi": 0, + "lo": 0 + } + } + } + ] + } + } + }, + "ext": "v0" + }, + 1036800 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Config" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "drand_genesis" + }, + "val": { + "u64": 1692803367 + } + }, + { + "key": { + "symbol": "drand_period" + }, + "val": { + "u64": 3 + } + }, + { + "key": { + "symbol": "drand_pubkey" + }, + "val": { + "bytes": "03cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a01a714f2edb74119a2f2b0d5a7c75ba902d163700a61bc224ededd8e63aef7be1aaf8e93d7a9718b047ccddb3eb5d68b0e5db2b6bfbb01c867749cadffca88b36c24f3012ba09fc4d3022c5c37dce0f977d3adb5d183c7477c442b1f04515273" + } + }, + { + "key": { + "symbol": "dst" + }, + "val": { + "bytes": "424c535f5349475f424c53313233383147315f584d443a5348412d3235365f535357555f524f5f4e554c5f" + } + }, + { + "key": { + "symbol": "g2_neg_generator" + }, + "val": { + "bytes": "13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb813fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed0d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa" + } + }, + { + "key": { + "symbol": "usdc" + }, + "val": { + "address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RoundCounter" + } + ] + }, + "val": { + "u64": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 1036800 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "amount" + }, + "val": { + "i128": { + "hi": 0, + "lo": 1000 + } + } + }, + { + "key": { + "symbol": "authorized" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "clawback" + }, + "val": { + "bool": false + } + } + ] + } + } + }, + "ext": "v0" + }, + 518400 + ] + ], + [ + { + "contract_data": { + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000002" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 120960 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 1036800 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_late.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_late.1.json new file mode 100644 index 00000000..b7577c1a --- /dev/null +++ b/contracts/round/test_snapshots/test/error_paths/error_path_seal_round_too_late.1.json @@ -0,0 +1,691 @@ +{ + "generators": { + "address": 5, + "nonce": 0 + }, + "auth": [ + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + { + "function": { + "contract_fn": { + "contract_address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "function_name": "create_round", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "abababababababababababababababababababababababababababababababab" + }, + { + "u64": 29155653 + }, + { + "vec": [ + { + "symbol": "HighestBid" + } + ] + }, + { + "u64": 1780270226 + }, + { + "u64": 1780270526 + }, + { + "bytes": "61756469746f72" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + { + "function": { + "contract_fn": { + "contract_address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "function_name": "mint", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + }, + { + "i128": { + "hi": 0, + "lo": 1000 + } + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 1780270126, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "balance": 0, + "seq_num": 0, + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + null + ] + ], + [ + { + "contract_data": { + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Round" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "vec": [ + { + "symbol": "Round" + }, + { + "u64": 1 + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_pubkey" + }, + "val": { + "bytes": "61756469746f72" + } + }, + { + "key": { + "symbol": "bidders" + }, + "val": { + "vec": [] + } + }, + { + "key": { + "symbol": "clearing_rule" + }, + "val": { + "vec": [ + { + "symbol": "HighestBid" + } + ] + } + }, + { + "key": { + "symbol": "commit_deadline" + }, + "val": { + "u64": 1780270226 + } + }, + { + "key": { + "symbol": "item_ref" + }, + "val": { + "bytes": "abababababababababababababababababababababababababababababababab" + } + }, + { + "key": { + "symbol": "operator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "symbol": "reveal_deadline" + }, + "val": { + "u64": 1780270526 + } + }, + { + "key": { + "symbol": "reveal_round" + }, + "val": { + "u64": 29155653 + } + }, + { + "key": { + "symbol": "status" + }, + "val": { + "vec": [ + { + "symbol": "Open" + } + ] + } + }, + { + "key": { + "symbol": "winner" + }, + "val": "void" + }, + { + "key": { + "symbol": "winning_bid" + }, + "val": { + "i128": { + "hi": 0, + "lo": 0 + } + } + } + ] + } + } + }, + "ext": "v0" + }, + 1036800 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Config" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "drand_genesis" + }, + "val": { + "u64": 1692803367 + } + }, + { + "key": { + "symbol": "drand_period" + }, + "val": { + "u64": 3 + } + }, + { + "key": { + "symbol": "drand_pubkey" + }, + "val": { + "bytes": "03cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a01a714f2edb74119a2f2b0d5a7c75ba902d163700a61bc224ededd8e63aef7be1aaf8e93d7a9718b047ccddb3eb5d68b0e5db2b6bfbb01c867749cadffca88b36c24f3012ba09fc4d3022c5c37dce0f977d3adb5d183c7477c442b1f04515273" + } + }, + { + "key": { + "symbol": "dst" + }, + "val": { + "bytes": "424c535f5349475f424c53313233383147315f584d443a5348412d3235365f535357555f524f5f4e554c5f" + } + }, + { + "key": { + "symbol": "g2_neg_generator" + }, + "val": { + "bytes": "13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb813fa4d4a0ad8b1ce186ed5061789213d993923066dddaf1040bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed0d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17f9ee3837a55024f78c71363275a75d75d86bab79f74782aa" + } + }, + { + "key": { + "symbol": "usdc" + }, + "val": { + "address": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RoundCounter" + } + ] + }, + "val": { + "u64": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 1036800 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": { + "vec": [ + { + "symbol": "Balance" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "amount" + }, + "val": { + "i128": { + "hi": 0, + "lo": 1000 + } + } + }, + { + "key": { + "symbol": "authorized" + }, + "val": { + "bool": true + } + }, + { + "key": { + "symbol": "clawback" + }, + "val": { + "bool": false + } + } + ] + } + } + }, + "ext": "v0" + }, + 518400 + ] + ], + [ + { + "contract_data": { + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGWF" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000002" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 120960 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 1036800 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/round/test_snapshots/test/error_paths/error_path_wrong_status.1.json b/contracts/round/test_snapshots/test/error_paths/error_path_wrong_status.1.json index 446d5bf3..990057ba 100644 --- a/contracts/round/test_snapshots/test/error_paths/error_path_wrong_status.1.json +++ b/contracts/round/test_snapshots/test/error_paths/error_path_wrong_status.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/full_lifecycle_real_drand_signature.1.json b/contracts/round/test_snapshots/test/full_lifecycle_real_drand_signature.1.json index 252d8669..dba92a3a 100644 --- a/contracts/round/test_snapshots/test/full_lifecycle_real_drand_signature.1.json +++ b/contracts/round/test_snapshots/test/full_lifecycle_real_drand_signature.1.json @@ -144,6 +144,9 @@ }, { "bytes": "696441" + }, + { + "u64": 29155653 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "696442" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_page_cursor_at_total.1.json b/contracts/round/test_snapshots/test/get_bidders_page_cursor_at_total.1.json index 7f800c2a..4a178c97 100644 --- a/contracts/round/test_snapshots/test/get_bidders_page_cursor_at_total.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_page_cursor_at_total.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_page_cursor_beyond_total.1.json b/contracts/round/test_snapshots/test/get_bidders_page_cursor_beyond_total.1.json index 7f800c2a..4a178c97 100644 --- a/contracts/round/test_snapshots/test/get_bidders_page_cursor_beyond_total.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_page_cursor_beyond_total.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_page_exact.1.json b/contracts/round/test_snapshots/test/get_bidders_page_exact.1.json index 7f800c2a..4a178c97 100644 --- a/contracts/round/test_snapshots/test/get_bidders_page_exact.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_page_exact.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_page_final.1.json b/contracts/round/test_snapshots/test/get_bidders_page_final.1.json index 41054674..607401a2 100644 --- a/contracts/round/test_snapshots/test/get_bidders_page_final.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_page_final.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -377,6 +386,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -463,6 +475,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_page_multi.1.json b/contracts/round/test_snapshots/test/get_bidders_page_multi.1.json index cd51f30c..19f7f8e6 100644 --- a/contracts/round/test_snapshots/test/get_bidders_page_multi.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_page_multi.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -377,6 +386,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -463,6 +475,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -549,6 +564,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -635,6 +653,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -721,6 +742,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -807,6 +831,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -893,6 +920,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_page_partial.1.json b/contracts/round/test_snapshots/test/get_bidders_page_partial.1.json index 41054674..607401a2 100644 --- a/contracts/round/test_snapshots/test/get_bidders_page_partial.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_page_partial.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -377,6 +386,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -463,6 +475,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_page_preserves_order.1.json b/contracts/round/test_snapshots/test/get_bidders_page_preserves_order.1.json index 4676edb5..ad07d87b 100644 --- a/contracts/round/test_snapshots/test/get_bidders_page_preserves_order.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_page_preserves_order.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -377,6 +386,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -463,6 +475,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_returns_ordered_index.1.json b/contracts/round/test_snapshots/test/get_bidders_returns_ordered_index.1.json index e69e5f8b..21bd1dae 100644 --- a/contracts/round/test_snapshots/test/get_bidders_returns_ordered_index.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_returns_ordered_index.1.json @@ -144,6 +144,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -266,6 +272,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/get_bidders_still_returns_full_list.1.json b/contracts/round/test_snapshots/test/get_bidders_still_returns_full_list.1.json index 41054674..607401a2 100644 --- a/contracts/round/test_snapshots/test/get_bidders_still_returns_full_list.1.json +++ b/contracts/round/test_snapshots/test/get_bidders_still_returns_full_list.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -291,6 +297,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -377,6 +386,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -463,6 +475,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/highest_bid_table_driven.1.json b/contracts/round/test_snapshots/test/highest_bid_table_driven.1.json index 56388cae..6b18055b 100644 --- a/contracts/round/test_snapshots/test/highest_bid_table_driven.1.json +++ b/contracts/round/test_snapshots/test/highest_bid_table_driven.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/highest_bid_table_driven.2.json b/contracts/round/test_snapshots/test/highest_bid_table_driven.2.json index fa639c0a..e5661d86 100644 --- a/contracts/round/test_snapshots/test/highest_bid_table_driven.2.json +++ b/contracts/round/test_snapshots/test/highest_bid_table_driven.2.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/highest_bid_table_driven.3.json b/contracts/round/test_snapshots/test/highest_bid_table_driven.3.json index 39042437..288ffa90 100644 --- a/contracts/round/test_snapshots/test/highest_bid_table_driven.3.json +++ b/contracts/round/test_snapshots/test/highest_bid_table_driven.3.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/highest_bid_table_driven.4.json b/contracts/round/test_snapshots/test/highest_bid_table_driven.4.json index ca047099..39966cae 100644 --- a/contracts/round/test_snapshots/test/highest_bid_table_driven.4.json +++ b/contracts/round/test_snapshots/test/highest_bid_table_driven.4.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.1.json b/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.1.json index eec2e046..67f91f93 100644 --- a/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.1.json +++ b/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.2.json b/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.2.json index 264f3725..7b92b5c4 100644 --- a/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.2.json +++ b/contracts/round/test_snapshots/test/highest_bid_tie_is_deterministic_first_inserter_wins.2.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/late_reveal_rejected_after_window_even_with_seal_present.1.json b/contracts/round/test_snapshots/test/late_reveal_rejected_after_window_even_with_seal_present.1.json index 337995ad..9e927f28 100644 --- a/contracts/round/test_snapshots/test/late_reveal_rejected_after_window_even_with_seal_present.1.json +++ b/contracts/round/test_snapshots/test/late_reveal_rejected_after_window_even_with_seal_present.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/lowest_bid_table_driven.1.json b/contracts/round/test_snapshots/test/lowest_bid_table_driven.1.json index 8c2b6df2..66927f20 100644 --- a/contracts/round/test_snapshots/test/lowest_bid_table_driven.1.json +++ b/contracts/round/test_snapshots/test/lowest_bid_table_driven.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/lowest_bid_table_driven.2.json b/contracts/round/test_snapshots/test/lowest_bid_table_driven.2.json index 12503dac..2d06111f 100644 --- a/contracts/round/test_snapshots/test/lowest_bid_table_driven.2.json +++ b/contracts/round/test_snapshots/test/lowest_bid_table_driven.2.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/lowest_bid_table_driven.3.json b/contracts/round/test_snapshots/test/lowest_bid_table_driven.3.json index 9390cd94..9e544d22 100644 --- a/contracts/round/test_snapshots/test/lowest_bid_table_driven.3.json +++ b/contracts/round/test_snapshots/test/lowest_bid_table_driven.3.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/lowest_bid_tie_is_deterministic_first_inserter_wins.1.json b/contracts/round/test_snapshots/test/lowest_bid_tie_is_deterministic_first_inserter_wins.1.json index 1e438be5..9caaaf31 100644 --- a/contracts/round/test_snapshots/test/lowest_bid_tie_is_deterministic_first_inserter_wins.1.json +++ b/contracts/round/test_snapshots/test/lowest_bid_tie_is_deterministic_first_inserter_wins.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/missing_reveal_bid_is_skipped_during_clear.1.json b/contracts/round/test_snapshots/test/missing_reveal_bid_is_skipped_during_clear.1.json index c7d965e9..669e1234 100644 --- a/contracts/round/test_snapshots/test/missing_reveal_bid_is_skipped_during_clear.1.json +++ b/contracts/round/test_snapshots/test/missing_reveal_bid_is_skipped_during_clear.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/no_valid_bids_after_reveal_window.1.json b/contracts/round/test_snapshots/test/no_valid_bids_after_reveal_window.1.json index eb960fe1..1d4d9307 100644 --- a/contracts/round/test_snapshots/test/no_valid_bids_after_reveal_window.1.json +++ b/contracts/round/test_snapshots/test/no_valid_bids_after_reveal_window.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/observer_reads_round_and_bid_state_after_lifecycle_completion.1.json b/contracts/round/test_snapshots/test/observer_reads_round_and_bid_state_after_lifecycle_completion.1.json index 3725fb31..a94e202f 100644 --- a/contracts/round/test_snapshots/test/observer_reads_round_and_bid_state_after_lifecycle_completion.1.json +++ b/contracts/round/test_snapshots/test/observer_reads_round_and_bid_state_after_lifecycle_completion.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/open_reveal_extends_seal_through_reveal_window.1.json b/contracts/round/test_snapshots/test/open_reveal_extends_seal_through_reveal_window.1.json index c30da398..127240ba 100644 --- a/contracts/round/test_snapshots/test/open_reveal_extends_seal_through_reveal_window.1.json +++ b/contracts/round/test_snapshots/test/open_reveal_extends_seal_through_reveal_window.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/open_reveal_on_settled_round_rejected.1.json b/contracts/round/test_snapshots/test/open_reveal_on_settled_round_rejected.1.json index 1ed0aaed..d5263b52 100644 --- a/contracts/round/test_snapshots/test/open_reveal_on_settled_round_rejected.1.json +++ b/contracts/round/test_snapshots/test/open_reveal_on_settled_round_rejected.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/overwrite_to_larger_escrow_conserves_tokens.1.json b/contracts/round/test_snapshots/test/overwrite_to_larger_escrow_conserves_tokens.1.json index e5084521..9d72b92f 100644 --- a/contracts/round/test_snapshots/test/overwrite_to_larger_escrow_conserves_tokens.1.json +++ b/contracts/round/test_snapshots/test/overwrite_to_larger_escrow_conserves_tokens.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -180,6 +183,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/repeated_overwrites_escrow_conservation.1.json b/contracts/round/test_snapshots/test/repeated_overwrites_escrow_conservation.1.json index d13be1af..4fabb7e5 100644 --- a/contracts/round/test_snapshots/test/repeated_overwrites_escrow_conservation.1.json +++ b/contracts/round/test_snapshots/test/repeated_overwrites_escrow_conservation.1.json @@ -119,6 +119,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -183,6 +186,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -247,6 +253,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -311,6 +320,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/reveal_hash_mismatch_invalidates_bid.1.json b/contracts/round/test_snapshots/test/reveal_hash_mismatch_invalidates_bid.1.json index 95c6d564..579a14d4 100644 --- a/contracts/round/test_snapshots/test/reveal_hash_mismatch_invalidates_bid.1.json +++ b/contracts/round/test_snapshots/test/reveal_hash_mismatch_invalidates_bid.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/reveal_on_settled_round_rejected.1.json b/contracts/round/test_snapshots/test/reveal_on_settled_round_rejected.1.json index ee83044e..f1921747 100644 --- a/contracts/round/test_snapshots/test/reveal_on_settled_round_rejected.1.json +++ b/contracts/round/test_snapshots/test/reveal_on_settled_round_rejected.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/reveal_wrong_nonce_rejected.1.json b/contracts/round/test_snapshots/test/reveal_wrong_nonce_rejected.1.json index fc23e294..8678d3fe 100644 --- a/contracts/round/test_snapshots/test/reveal_wrong_nonce_rejected.1.json +++ b/contracts/round/test_snapshots/test/reveal_wrong_nonce_rejected.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/seeded_case_42_highest_bid_reproducible.1.json b/contracts/round/test_snapshots/test/seeded_case_42_highest_bid_reproducible.1.json index 4f3837fc..bd72dd99 100644 --- a/contracts/round/test_snapshots/test/seeded_case_42_highest_bid_reproducible.1.json +++ b/contracts/round/test_snapshots/test/seeded_case_42_highest_bid_reproducible.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/seeded_case_7_lowest_bid_reproducible.1.json b/contracts/round/test_snapshots/test/seeded_case_7_lowest_bid_reproducible.1.json index 2109c990..1a716e78 100644 --- a/contracts/round/test_snapshots/test/seeded_case_7_lowest_bid_reproducible.1.json +++ b/contracts/round/test_snapshots/test/seeded_case_7_lowest_bid_reproducible.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/settle_exact_payouts_table.1.json b/contracts/round/test_snapshots/test/settle_exact_payouts_table.1.json index 5ee4d783..5be29543 100644 --- a/contracts/round/test_snapshots/test/settle_exact_payouts_table.1.json +++ b/contracts/round/test_snapshots/test/settle_exact_payouts_table.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/settle_exact_payouts_table.2.json b/contracts/round/test_snapshots/test/settle_exact_payouts_table.2.json index 1e5c4531..99d2d3e2 100644 --- a/contracts/round/test_snapshots/test/settle_exact_payouts_table.2.json +++ b/contracts/round/test_snapshots/test/settle_exact_payouts_table.2.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/settle_exact_payouts_table.3.json b/contracts/round/test_snapshots/test/settle_exact_payouts_table.3.json index 04d81da9..31a0dbb7 100644 --- a/contracts/round/test_snapshots/test/settle_exact_payouts_table.3.json +++ b/contracts/round/test_snapshots/test/settle_exact_payouts_table.3.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -176,6 +180,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -205,6 +210,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -262,6 +270,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM", @@ -291,6 +300,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/settled_round_persistent_state_survives_seal_expiry.1.json b/contracts/round/test_snapshots/test/settled_round_persistent_state_survives_seal_expiry.1.json index f34db81c..a8d4ee8f 100644 --- a/contracts/round/test_snapshots/test/settled_round_persistent_state_survives_seal_expiry.1.json +++ b/contracts/round/test_snapshots/test/settled_round_persistent_state_survives_seal_expiry.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/token_conservation_full_lifecycle.1.json b/contracts/round/test_snapshots/test/token_conservation_full_lifecycle.1.json index 0fe85729..05740c2b 100644 --- a/contracts/round/test_snapshots/test/token_conservation_full_lifecycle.1.json +++ b/contracts/round/test_snapshots/test/token_conservation_full_lifecycle.1.json @@ -115,6 +115,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -144,6 +145,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } @@ -180,6 +184,7 @@ [], [], [], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", @@ -209,6 +214,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 29155653 } ] } diff --git a/contracts/round/test_snapshots/test/void_after_grace_refunds_all.1.json b/contracts/round/test_snapshots/test/void_after_grace_refunds_all.1.json index e7ae3803..2c0192a4 100644 --- a/contracts/round/test_snapshots/test/void_after_grace_refunds_all.1.json +++ b/contracts/round/test_snapshots/test/void_after_grace_refunds_all.1.json @@ -144,6 +144,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } @@ -205,6 +208,9 @@ }, { "bytes": "6964" + }, + { + "u64": 2000 } ] } diff --git a/contracts/round/test_snapshots/test/voided_round_refunds_survive_seal_expiry.1.json b/contracts/round/test_snapshots/test/voided_round_refunds_survive_seal_expiry.1.json index 86dbe8f3..ed9f9cdb 100644 --- a/contracts/round/test_snapshots/test/voided_round_refunds_survive_seal_expiry.1.json +++ b/contracts/round/test_snapshots/test/voided_round_refunds_survive_seal_expiry.1.json @@ -90,6 +90,7 @@ } ] ], + [], [ [ "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", @@ -119,6 +120,9 @@ }, { "bytes": "69642d626c6f62" + }, + { + "u64": 2000 } ] } diff --git a/packages/round-bindings/src/index.ts b/packages/round-bindings/src/index.ts index abe1a0c2..0ea30ad0 100644 --- a/packages/round-bindings/src/index.ts +++ b/packages/round-bindings/src/index.ts @@ -219,8 +219,11 @@ export interface Client { * - `escrow` is a public USDC budget and an upper bound on the sealed bid; * locked now so the winner can always pay. * - `auditor_blob` is the bidder identity encrypted to the auditor key. + * - `seal_round` must equal the round's stored `reveal_round`: the seal is + * only meaningful for the Drand round this auction committed to open. + * Mismatched seals are rejected before any escrow is locked. */ - commit: ({round_id, bidder, commitment, ciphertext, escrow, auditor_blob}: {round_id: u64, bidder: string, commitment: Buffer, ciphertext: Buffer, escrow: i128, auditor_blob: Buffer}, options?: MethodOptions) => Promise>> + commit: ({round_id, bidder, commitment, ciphertext, escrow, auditor_blob, seal_round}: {round_id: u64, bidder: string, commitment: Buffer, ciphertext: Buffer, escrow: i128, auditor_blob: Buffer, seal_round: u64}, options?: MethodOptions) => Promise>> /** * Construct and simulate a reveal transaction. Returns an `AssembledTransaction` object which will have a `result` field containing the result of the simulation. If this transaction changes contract state, you will need to call `signAndSend()` on the returned object. diff --git a/packages/sdk/scripts/live-smoke.ts b/packages/sdk/scripts/live-smoke.ts index 8958748c..489a0596 100644 --- a/packages/sdk/scripts/live-smoke.ts +++ b/packages/sdk/scripts/live-smoke.ts @@ -129,6 +129,7 @@ async function main() { value, nonce, round: revealRound, + revealRound, client: drand, identity, auditorPublicKey: auditor.publicKey, diff --git a/packages/sdk/scripts/mainnet-micro.ts b/packages/sdk/scripts/mainnet-micro.ts index a42608de..fb7f8f13 100644 --- a/packages/sdk/scripts/mainnet-micro.ts +++ b/packages/sdk/scripts/mainnet-micro.ts @@ -157,6 +157,7 @@ async function main() { value: bid, nonce, round: revealRound, + revealRound, client: drand, identity: new TextEncoder().encode(`micro:${bidderKp.publicKey()}`), auditorPublicKey: auditor.publicKey, diff --git a/packages/sdk/src/client.test.ts b/packages/sdk/src/client.test.ts index b7325288..b9de5803 100644 --- a/packages/sdk/src/client.test.ts +++ b/packages/sdk/src/client.test.ts @@ -164,6 +164,7 @@ describe("SubRosaClient source configuration", () => { commitment: new Uint8Array(32), ciphertext: new Uint8Array([0x61, 0x67, 0x65]), // non-empty auditorBlob: new Uint8Array(1), // non-empty + sealRound: 1, }, escrow: 1n, }), diff --git a/packages/sdk/src/client.ts b/packages/sdk/src/client.ts index 5ddb4cae..6e0a3a43 100644 --- a/packages/sdk/src/client.ts +++ b/packages/sdk/src/client.ts @@ -123,6 +123,13 @@ export interface CommitParams { escrow: bigint; /** Bidder address. Default: the configured signer's public key. */ bidder?: string; + /** + * Drand round the seal was encrypted to. Must equal the round's stored + * `reveal_round` β€” the contract rejects mismatched seals before locking + * escrow (issue #376). Defaults to `sealed.sealRound` when the seal carries + * it (tlock >= this change), otherwise it must be supplied. + */ + sealRound?: number | bigint; } export interface RevealParams { @@ -347,6 +354,13 @@ export class SubRosaClient { } const bidder = params.bidder ?? this.#requireSource("bidder"); + const rawSealRound = params.sealRound ?? (params.sealed as { sealRound?: number | bigint }).sealRound; + if (rawSealRound === undefined) { + throw new SubRosaClientConfigError( + "sealRound is required: pass the Drand round the seal was encrypted to (issue #376 commit window)", + ); + } + const seal_round = toBigInt(rawSealRound); const tx = await this.#validatedContractCall(() => this.contract.commit({ round_id: normalizeRoundId(params.roundId), @@ -355,6 +369,7 @@ export class SubRosaClient { ciphertext: toBuffer(params.sealed.ciphertext), escrow: params.escrow, auditor_blob: toBuffer(params.sealed.auditorBlob), + seal_round, }), ); await this.#sendUnwrap(tx); @@ -459,6 +474,13 @@ export class SubRosaClient { preflightCommit(params: CommitParams): Promise> { return this.#preflight("commit", () => { const bidder = params.bidder ?? this.#requireSource("bidder"); + const rawSealRound = params.sealRound ?? (params.sealed as { sealRound?: number | bigint }).sealRound; + if (rawSealRound === undefined) { + throw new SubRosaClientConfigError( + "sealRound is required: pass the Drand round the seal was encrypted to (issue #376 commit window)", + ); + } + const seal_round = toBigInt(rawSealRound); return this.#validatedContractCall(() => this.contract.commit({ round_id: toBigInt(params.roundId), @@ -467,6 +489,7 @@ export class SubRosaClient { ciphertext: toBuffer(params.sealed.ciphertext), escrow: params.escrow, auditor_blob: toBuffer(params.sealed.auditorBlob), + seal_round, }), ); }); diff --git a/packages/sdk/src/encoding.test.ts b/packages/sdk/src/encoding.test.ts index fca994cb..bcdd09ce 100644 --- a/packages/sdk/src/encoding.test.ts +++ b/packages/sdk/src/encoding.test.ts @@ -140,6 +140,7 @@ test("a tlock SealedBid encodes byte-for-byte into commit", () => { commitment: h, ciphertext: new TextEncoder().encode("age-armored"), auditorBlob: new Uint8Array(0), + sealRound: 9, }; const args = c.spec.funcArgsToScVals("commit", { diff --git a/packages/sdk/src/preflight.test.ts b/packages/sdk/src/preflight.test.ts index 47ed3300..5bc19359 100644 --- a/packages/sdk/src/preflight.test.ts +++ b/packages/sdk/src/preflight.test.ts @@ -290,6 +290,7 @@ describe("SubRosaClient preflight helpers", () => { commitment: new Uint8Array(32), ciphertext: new Uint8Array(64), auditorBlob: new Uint8Array(32), + sealRound: 1, }, escrow: 1_000_000n, }); diff --git a/packages/tlock/package.json b/packages/tlock/package.json index 89c9f621..7f5387a5 100644 --- a/packages/tlock/package.json +++ b/packages/tlock/package.json @@ -20,9 +20,9 @@ }, "main": "src/index.ts", "scripts": { - "test": "node --import tsx --test src/commitment.test.ts src/payload.test.ts src/auditor.test.ts src/auditor-recovery-cli.test.ts src/bls.test.ts src/seal.test.ts src/freshness.test.ts src/quicknet.test.ts src/validate.test.ts", + "test": "node --import tsx --test src/commitment.test.ts src/payload.test.ts src/auditor.test.ts src/auditor-recovery-cli.test.ts src/bls.test.ts src/seal.test.ts src/freshness.test.ts src/quicknet.test.ts src/validate.test.ts src/window.test.ts", "test:quicknet": "node --import tsx --test src/quicknet.test.ts", - "test:unit": "node --import tsx --test src/commitment.test.ts src/payload.test.ts src/auditor.test.ts src/auditor-recovery-cli.test.ts src/bls.test.ts src/freshness.test.ts src/quicknet.test.ts src/validate.test.ts", + "test:unit": "node --import tsx --test src/commitment.test.ts src/payload.test.ts src/auditor.test.ts src/auditor-recovery-cli.test.ts src/bls.test.ts src/freshness.test.ts src/quicknet.test.ts src/validate.test.ts src/window.test.ts", "test:seal": "node --import tsx --test src/seal.test.ts", "recover:identities": "node --import tsx src/recover-identities.cli.ts", "typecheck": "tsc --noEmit -p tsconfig.json" diff --git a/packages/tlock/src/index.ts b/packages/tlock/src/index.ts index 05f8239c..2ec00018 100644 --- a/packages/tlock/src/index.ts +++ b/packages/tlock/src/index.ts @@ -58,6 +58,13 @@ export { type FreshnessResult, } from "./freshness.js"; +export { + assertSealRoundWindow, + isMalformedRound, + SealRoundError, + type SealRoundErrorReason, +} from "./window.js"; + export { encodePayloadEnvelope, decodePayloadEnvelope, diff --git a/packages/tlock/src/payload.ts b/packages/tlock/src/payload.ts index f1527b17..1f225b61 100644 --- a/packages/tlock/src/payload.ts +++ b/packages/tlock/src/payload.ts @@ -16,6 +16,7 @@ import { timelockDecrypt, timelockEncrypt, Buffer as TlockBuffer } from "tlock-j import { sealIdentity } from "./auditor.js"; import { beBytesToI128, i128ToBeBytes, NONCE_BYTES, VALUE_BYTES } from "./commitment.js"; import type { DrandClient } from "./quicknet.js"; +import { assertSealRoundWindow } from "./window.js"; const utf8Encode = new TextEncoder(); const utf8Decode = new TextDecoder(); @@ -47,6 +48,9 @@ export interface PayloadEnvelope { export interface SealPayloadParams extends PayloadEnvelope { round: number; + /// The Drand round the auction committed to open (`Round::reveal_round`). + /// The seal must name exactly this round, or sealing is rejected. + revealRound: number; client: DrandClient; identity?: Uint8Array; auditorPublicKey?: Uint8Array; @@ -149,6 +153,7 @@ export function payloadCommitment(envelope: PayloadEnvelope): Uint8Array { export async function sealPayload(params: SealPayloadParams): Promise { const { round, + revealRound, client, identity, auditorPublicKey, @@ -156,6 +161,9 @@ export async function sealPayload(params: SealPayloadParams): Promise { const client = quicknet(); for (const round of [0, -1, -100]) { await assert.rejects( - sealBid({ value: 1n, nonce: generateNonce(), round, client }), + sealBid({ value: 1n, nonce: generateNonce(), round, revealRound: round, client }), /round must be a positive integer/, ); } @@ -129,6 +132,7 @@ test( value: 999n, nonce: generateNonce(), round: futureRound, + revealRound: futureRound, client, }); await assert.rejects(openBid(sealed.ciphertext, client)); @@ -141,19 +145,19 @@ test("sealBid rejects non-positive or non-integer round numbers", async () => { const value = 100n; await assert.rejects( - () => sealBid({ value, nonce, round: 0, client }), + () => sealBid({ value, nonce, round: 0, revealRound: 0, client }), (err: any) => err instanceof RangeError && /round must be a positive integer/.test(err.message), ); await assert.rejects( - () => sealBid({ value, nonce, round: -5, client }), + () => sealBid({ value, nonce, round: -5, revealRound: -5, client }), (err: any) => err instanceof RangeError && /round must be a positive integer/.test(err.message), ); await assert.rejects( - () => sealBid({ value, nonce, round: 1.5, client }), + () => sealBid({ value, nonce, round: 1.5, revealRound: 1.5, client }), (err: any) => err instanceof RangeError && /round must be a positive integer/.test(err.message), ); await assert.rejects( - () => sealBid({ value, nonce, round: NaN, client }), + () => sealBid({ value, nonce, round: NaN, revealRound: NaN, client }), (err: any) => err instanceof RangeError && /round must be a positive integer/.test(err.message), ); }); @@ -164,15 +168,15 @@ test("sealBid rejects invalid nonce lengths", async () => { const round = 1000; await assert.rejects( - () => sealBid({ value, nonce: new Uint8Array(16), round, client }), + () => sealBid({ value, nonce: new Uint8Array(16), round, revealRound: round, client }), /nonce must be 32 bytes/, ); await assert.rejects( - () => sealBid({ value, nonce: new Uint8Array(31), round, client }), + () => sealBid({ value, nonce: new Uint8Array(31), round, revealRound: round, client }), /nonce must be 32 bytes/, ); await assert.rejects( - () => sealBid({ value, nonce: new Uint8Array(33), round, client }), + () => sealBid({ value, nonce: new Uint8Array(33), round, revealRound: round, client }), /nonce must be 32 bytes/, ); }); @@ -185,3 +189,77 @@ test("openBid rejects empty ciphertext", async () => { ); }); +// ── Issue #376: seal-round commit window ──────────────────────────────────── + +test("sealBid rejects a seal whose round is earlier than the auction's round", async () => { + const client = quicknet(); + // Quicknet genesis (2023-08-23) + fixture math keeps this an honest, fully + // published historical round for both sides of the window check. + const revealRound = 10_000_000; + await assert.rejects( + sealBid({ + value: 100n, + nonce: generateNonce(), + round: revealRound - 1, + revealRound, + client, + }), + (err: unknown) => + err instanceof SealRoundError && + err.reason === "seal-round-too-early" && + err.revealRound === revealRound, + ); +}); + +test("sealBid rejects a seal whose round is later than the auction's round", async () => { + const client = quicknet(); + const revealRound = 10_000_000; + await assert.rejects( + sealBid({ + value: 100n, + nonce: generateNonce(), + round: revealRound + 1, + revealRound, + client, + }), + (err: unknown) => + err instanceof SealRoundError && err.reason === "seal-round-too-late", + ); +}); + +test("sealBid rejects malformed seal rounds before any network call", async () => { + const client = quicknet(); + const revealRound = 10_000_000; + for (const round of [0, -3, 1.5, NaN, Number.MAX_SAFE_INTEGER + 1]) { + await assert.rejects( + sealBid({ + value: 100n, + nonce: generateNonce(), + round, + revealRound, + client, + }), + (err: unknown) => + // Legacy input guard (RangeError) or the stable window error β€” both + // reject before any escrow lock. The helper's stable errors are + // covered exhaustively in window.test.ts. + err instanceof RangeError || + (err instanceof SealRoundError && err.reason === "invalid-seal-round-zero"), + ); + } +}); + +test("a bid sealed exactly at the auction's round passes the window check", { timeout: NET_TIMEOUT }, async () => { + const client = quicknet(); + const round = (await currentRound(client)) - 5; + const sealed = await sealBid({ + value: 7n, + nonce: generateNonce(), + round, + revealRound: round, + client, + }); + const opened = await openBid(sealed.ciphertext, client); + assert.equal(opened.value, 7n); +}); + diff --git a/packages/tlock/src/seal.ts b/packages/tlock/src/seal.ts index b907cbfe..1394834b 100644 --- a/packages/tlock/src/seal.ts +++ b/packages/tlock/src/seal.ts @@ -13,6 +13,7 @@ import { randomBytes } from "@noble/hashes/utils.js"; import { commitment, decodeBidPreimage, encodeBidPreimage, NONCE_BYTES } from "./commitment.js"; import { sealIdentity } from "./auditor.js"; import type { DrandClient } from "./quicknet.js"; +import { assertSealRoundWindow } from "./window.js"; const utf8Encode = new TextEncoder(); const utf8Decode = new TextDecoder(); @@ -22,6 +23,9 @@ export interface SealBidParams { nonce: Uint8Array; round: number; client: DrandClient; + /// The Drand round the auction committed to open (`Round::reveal_round`). + /// The seal must name exactly this round, or sealing is rejected. + revealRound: number; /// Optional selective-disclosure identity, sealed to the auditor key. identity?: Uint8Array; auditorPublicKey?: Uint8Array; @@ -34,6 +38,10 @@ export interface SealedBid { ciphertext: Uint8Array; /// enc(identity, auditor_pubkey); empty if no identity was provided. auditorBlob: Uint8Array; + /// The Drand round this seal was encrypted to. The SDK forwards it to the + /// contract `commit` as `seal_round`, where it must equal the auction's + /// stored `reveal_round` (issue #376). + sealRound: number; } export function generateNonce(): Uint8Array { @@ -41,7 +49,7 @@ export function generateNonce(): Uint8Array { } export async function sealBid(params: SealBidParams): Promise { - const { value, nonce, round, client, identity, auditorPublicKey } = params; + const { value, nonce, round, revealRound, client, identity, auditorPublicKey } = params; if (!Number.isInteger(round) || round < 1) { throw new RangeError(`round must be a positive integer, got ${round}`); @@ -49,6 +57,9 @@ export async function sealBid(params: SealBidParams): Promise { if (!nonce || nonce.length !== NONCE_BYTES) { throw new Error(`nonce must be ${NONCE_BYTES} bytes, got ${nonce?.length}`); } + // Issue #376: the seal must name exactly the round the auction committed to + // open β€” same rule the contract enforces inside `commit`. + assertSealRoundWindow(round, revealRound); const preimage = encodeBidPreimage(value, nonce); const h = commitment(value, nonce); @@ -62,7 +73,7 @@ export async function sealBid(params: SealBidParams): Promise { throw new Error("identity and auditorPublicKey must be provided together"); } - return { commitment: h, ciphertext, auditorBlob }; + return { commitment: h, ciphertext, auditorBlob, sealRound: round }; } export interface OpenedBid { diff --git a/packages/tlock/src/window.test.ts b/packages/tlock/src/window.test.ts new file mode 100644 index 00000000..e781dc43 --- /dev/null +++ b/packages/tlock/src/window.test.ts @@ -0,0 +1,101 @@ +// Copyright (c) 2026 Sub Rosa contributors +// SPDX-License-Identifier: MIT +// +// Test vectors for the seal-round commit window (issue #376). +// +// These vectors use the quicknet chain parameters already committed in the +// repo (genesis_time 1692803367, period 3, quicknet chain hash) so the +// TypeScript helper and the Soroban contract can be validated against the +// exact same fixture set. The contract side runs the same cases in +// `contracts/round/src/error_paths.rs` (error_path_seal_round_too_early, +// error_path_seal_round_too_late, error_path_invalid_seal_round_zero) against +// the real quicknet BLS fixture in `contracts/round/src/test.rs`. + +import { test } from "node:test"; +import assert from "node:assert/strict"; + +import { + assertSealRoundWindow, + isMalformedRound, + SealRoundError, +} from "./window.js"; + +// Frozen quicknet chain parameters (same fixture as quicknet.test.ts and the +// contract's VEC_GENESIS / VEC_PERIOD / QUICKNET_HASH). +const QUICKNET_FIXTURE = { + genesis_time: 1_692_803_367, + period: 3, + hash: "52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971", +} as const; + +test("window vectors share the frozen quicknet chain parameters", () => { + assert.equal(QUICKNET_FIXTURE.period, 3); + assert.match(QUICKNET_FIXTURE.hash, /^[0-9a-f]{64}$/); +}); + +test("a seal exactly at the auction's round is inside the window", () => { + const revealRound = 10_000_000; + assert.doesNotThrow(() => assertSealRoundWindow(revealRound, revealRound)); +}); + +test("one round before the auction's round is too early (stable reason)", () => { + const revealRound = 10_000_000; + assert.throws( + () => assertSealRoundWindow(revealRound - 1, revealRound), + (err: unknown) => + err instanceof SealRoundError && + err.reason === "seal-round-too-early" && + err.sealRound === revealRound - 1 && + err.revealRound === revealRound, + ); +}); + +test("one round after the auction's round is too late (stable reason)", () => { + const revealRound = 10_000_000; + assert.throws( + () => assertSealRoundWindow(revealRound + 1, revealRound), + (err: unknown) => + err instanceof SealRoundError && err.reason === "seal-round-too-late", + ); +}); + +test("zero, negative, fractional, NaN, and unsafe rounds are malformed", () => { + for (const round of [0, -1, -100, 1.5, NaN, Infinity, -Infinity, Number.MAX_SAFE_INTEGER + 1]) { + assert.equal(isMalformedRound(round), true, `round ${round} must be malformed`); + assert.throws( + () => assertSealRoundWindow(round, 10_000_000), + (err: unknown) => + err instanceof SealRoundError && err.reason === "invalid-seal-round-zero", + `round ${round} must fail before any escrow lock`, + ); + } +}); + +test("a malformed auction round is also rejected", () => { + for (const revealRound of [0, -1, NaN, 2.5]) { + assert.throws( + () => assertSealRoundWindow(10_000_000, revealRound), + (err: unknown) => + err instanceof SealRoundError && err.reason === "invalid-seal-round-zero", + ); + } +}); + +test("window error messages name the auction's round for integrators", () => { + try { + assertSealRoundWindow(9_999_999, 10_000_000); + assert.fail("expected SealRoundError"); + } catch (err) { + assert.ok(err instanceof SealRoundError); + assert.match(err.message, /10_000_000|10000000/); + } +}); + +test("round publish time from the fixture stays representable (sanity)", () => { + // genesis + period Γ— R must fit in a JS-safe integer for realistic rounds; + // the contract enforces the same shape via checked_time_of_round in u64. + const round = 100_000_000; + const publishAtSeconds = QUICKNET_FIXTURE.genesis_time + QUICKNET_FIXTURE.period * round; + assert.ok(Number.isSafeInteger(publishAtSeconds)); + assert.ok(Number.isSafeInteger(publishAtSeconds * 1000)); +}); diff --git a/packages/tlock/src/window.ts b/packages/tlock/src/window.ts new file mode 100644 index 00000000..5c9ed0c3 --- /dev/null +++ b/packages/tlock/src/window.ts @@ -0,0 +1,71 @@ +// Copyright (c) 2026 Sub Rosa contributors +// SPDX-License-Identifier: MIT +// +// Seal-round commit window β€” the single off-chain counterpart of the Round +// contract's seal-round check (issue #376). +// +// A bid seal is only meaningful for the Drand round the auction committed to +// open. The contract stores that round as `Round::reveal_round` at +// `create_round` and rejects, inside `commit`, any seal whose round differs β€” +// with stable errors for too-early, too-late, and malformed round numbers. +// This module enforces the same rule off-chain, before a seal is ever +// encrypted, so both sides reject the same fixture set. + +/** + * Stable reasons a seal round can fall outside the commit window. Mirrors the + * contract's `Error` variants: SealRoundTooEarly (40), SealRoundTooLate (41), + * InvalidSealRoundZero (42). + */ +export type SealRoundErrorReason = + | "seal-round-too-early" + | "seal-round-too-late" + | "invalid-seal-round-zero"; + +export class SealRoundError extends Error { + readonly reason: SealRoundErrorReason; + readonly sealRound: number; + readonly revealRound: number; + + constructor(reason: SealRoundErrorReason, sealRound: number, revealRound: number) { + super( + reason === "invalid-seal-round-zero" + ? `seal round must be a positive integer, got ${sealRound}` + : `seal round ${sealRound} is outside the commit window: the auction opens at round ${revealRound}`, + ); + this.name = "SealRoundError"; + this.reason = reason; + this.sealRound = sealRound; + this.revealRound = revealRound; + } +} + +/// A round number the quicknet chain can never have published: zero, negative, +/// non-integer, NaN, or beyond Number.MAX_SAFE_INTEGER. +export function isMalformedRound(round: number): boolean { + return !Number.isSafeInteger(round) || round < 1; +} + +/** + * Validate a seal round against the round the auction committed to open. + * + * The allowed reveal round is always the value stored on the auction (`reveal + * round`), never a caller-supplied value. Throws SealRoundError with a stable + * `reason` for: + * - "invalid-seal-round-zero": zero, negative, non-integer, or unsafe rounds + * - "seal-round-too-early": seal round before the auction's round + * - "seal-round-too-late": seal round after the auction's round + */ +export function assertSealRoundWindow(sealRound: number, revealRound: number): void { + if (isMalformedRound(sealRound)) { + throw new SealRoundError("invalid-seal-round-zero", sealRound, revealRound); + } + if (isMalformedRound(revealRound)) { + throw new SealRoundError("invalid-seal-round-zero", sealRound, revealRound); + } + if (sealRound < revealRound) { + throw new SealRoundError("seal-round-too-early", sealRound, revealRound); + } + if (sealRound > revealRound) { + throw new SealRoundError("seal-round-too-late", sealRound, revealRound); + } +} diff --git a/scripts/check-round-errors.test.mjs b/scripts/check-round-errors.test.mjs index 0d508f9b..18814376 100644 --- a/scripts/check-round-errors.test.mjs +++ b/scripts/check-round-errors.test.mjs @@ -45,7 +45,7 @@ describe("parseTypesRs", () => { "utf-8", ); const variants = parseTypesRs(content); - assert.equal(variants.length, 27); + assert.equal(variants.length, 30); assert.deepEqual( variants.find((v) => v.name === "CommitClosed"), { name: "CommitClosed", code: 10 }, @@ -60,7 +60,7 @@ describe("parseErrorsMd", () => { "utf-8", ); const variants = parseErrorsMd(content); - assert.equal(variants.length, 27); + assert.equal(variants.length, 30); assert.deepEqual( variants.find((v) => v.name === "InvalidLimit"), { name: "InvalidLimit", code: 39 }, @@ -72,8 +72,8 @@ describe("check-round-errors script", () => { it("passes against the real repo sources", () => { const result = runScript(); assert.match(result, /PASS\s+types\.rs and ERRORS\.md list the same error codes\./); - assert.match(result, /types\.rs : 27 variants/); - assert.match(result, /ERRORS\.md: 27 rows/); + assert.match(result, /types\.rs : 30 variants/); + assert.match(result, /ERRORS\.md: 30 rows/); }); it("fails when ERRORS.md is missing a variant", () => { diff --git a/services/agent/src/bidder.test.ts b/services/agent/src/bidder.test.ts index ed13aaf4..46d24885 100644 --- a/services/agent/src/bidder.test.ts +++ b/services/agent/src/bidder.test.ts @@ -76,7 +76,7 @@ function bidderFixture() { calls.sealed++; duringSeal(); assert.equal(revealRound, 123); assert.deepEqual(auditorPublicKey, new Uint8Array(round.auditor_pubkey)); - return { commitment: new Uint8Array(32), ciphertext: new Uint8Array(4), auditorBlob: new Uint8Array(4) }; + return { commitment: new Uint8Array(32), ciphertext: new Uint8Array(4), auditorBlob: new Uint8Array(4), sealRound: 123 }; }, }; return { config, round, calls, deps, clock, diff --git a/services/agent/src/bidder.ts b/services/agent/src/bidder.ts index 44dd915a..1e43f00b 100644 --- a/services/agent/src/bidder.ts +++ b/services/agent/src/bidder.ts @@ -161,6 +161,7 @@ export async function runBidderAgent(config: BidderAgentConfig, dependencies: Bi value: bidValue, nonce, round: revealRound, + revealRound, client: drand, identity: new TextEncoder().encode(`agent:${sessionKp.publicKey()}`), auditorPublicKey, diff --git a/services/auction-template/sealed-auction.ts b/services/auction-template/sealed-auction.ts index 5372b936..d3da6385 100644 --- a/services/auction-template/sealed-auction.ts +++ b/services/auction-template/sealed-auction.ts @@ -216,12 +216,12 @@ async function testnetMain() { async function commitBid(secret: string, value: bigint, escrow: bigint, who: string) { const nonce = generateNonce(); const sealed = await sealBid({ - value, nonce, round: revealRound, client: drand, + value, nonce, round: revealRound, revealRound, client: drand, identity: new TextEncoder().encode(`bidder:${who}`), auditorPublicKey: auditor.publicKey, }); const client = new SubRosaClient({ rpcUrl: RPC_URL, networkPassphrase: NETWORK, contractId, secretKey: secret }); - await client.commit({ roundId, sealed, escrow }); + await client.commit({ roundId, sealed, escrow, sealRound: revealRound }); diagnostics.info("progress-4", ` ${who}: bid ${usdc(value)} / escrow ${usdc(escrow)}`); } diff --git a/services/drand-tools/src/quicknet.ts b/services/drand-tools/src/quicknet.ts index 1fa89a3b..768a4c52 100644 --- a/services/drand-tools/src/quicknet.ts +++ b/services/drand-tools/src/quicknet.ts @@ -38,6 +38,21 @@ export function roundAt(info: ChainInfo, unixSeconds: number): number { return Math.floor((unixSeconds - info.genesis_time) / info.period) + 1; } +/// Wall-clock time (unix seconds) at which Drand round `round` is published. +/// Throws for a zero/unsafe round or an intermediate value that overflows the +/// safe-integer range: the chain can never publish such a round, so callers +/// must reject it before committing any seal or locking escrow (issue #376). export function timeOfRound(info: ChainInfo, round: number): number { - return info.genesis_time + info.period * round; + if (!Number.isSafeInteger(round) || round < 1) { + throw new RangeError(`round must be a positive safe integer, got ${round}`); + } + if (!Number.isSafeInteger(info.period) || info.period <= 0) { + throw new RangeError(`period must be a positive safe integer, got ${info.period}`); + } + const offsetSeconds = info.period * round; + const publishAtSeconds = info.genesis_time + offsetSeconds; + if (!Number.isSafeInteger(offsetSeconds) || !Number.isSafeInteger(publishAtSeconds)) { + throw new RangeError(`round ${round} publish time overflows the safe-integer range`); + } + return publishAtSeconds; } diff --git a/services/keeper/scripts/keeper-e2e.ts b/services/keeper/scripts/keeper-e2e.ts index 1f7343d9..11287602 100644 --- a/services/keeper/scripts/keeper-e2e.ts +++ b/services/keeper/scripts/keeper-e2e.ts @@ -119,6 +119,7 @@ async function main() { value, nonce, round: revealRound, + revealRound, client: drand, identity: new TextEncoder().encode("bidder:keeper-e2e"), auditorPublicKey: auditor.publicKey, diff --git a/services/keeper/scripts/lifecycle-e2e.ts b/services/keeper/scripts/lifecycle-e2e.ts index 8d885786..c6684683 100644 --- a/services/keeper/scripts/lifecycle-e2e.ts +++ b/services/keeper/scripts/lifecycle-e2e.ts @@ -173,12 +173,12 @@ async function main() { async function commitBid(secret: string, value: bigint, escrow: bigint, who: string) { const nonce = generateNonce(); const sealed = await sealBid({ - value, nonce, round: revealRound, client: drand, + value, nonce, round: revealRound, revealRound, client: drand, identity: new TextEncoder().encode(`bidder:${who}`), auditorPublicKey: auditor.publicKey, }); const client = new SubRosaClient({ rpcUrl: RPC_URL, networkPassphrase: NETWORK, contractId, secretKey: secret }); - await client.commit({ roundId, sealed, escrow }); + await client.commit({ roundId, sealed, escrow, sealRound: revealRound }); diagnostics.info("progress-2", ` βœ” ${who} committed bid ${usdc(value)} / escrow ${usdc(escrow)} USDC`); return { label: who, blobHex: bytesHex(sealed.auditorBlob) }; }