Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
661 changes: 195 additions & 466 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ members = [
"streams",
"timelock",
"vault",
"test_fixtures",
"tools/event-spec",
"tools/spec-diff",
"xtask",
Expand Down
2 changes: 2 additions & 0 deletions governor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-governor"
version.workspace = true
edition.workspace = true
publish.workspace = true
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
crate-type = ["cdylib", "rlib"]
Expand Down
3 changes: 3 additions & 0 deletions governor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ impl Governor {
abstain_votes: 0,
canceled: false,
eta: 0,
description_hash: description_hash.clone(),
expires_at: 0,
executed: false,
},
);
events::proposal_created(
Expand Down
2 changes: 2 additions & 0 deletions grants_escrow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-grants-escrow"
version.workspace = true
edition.workspace = true
publish.workspace = true
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
crate-type = ["cdylib"]
Expand Down
12 changes: 6 additions & 6 deletions integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ publish.workspace = true
# Re-enable each test as its reconstruction issue lands.

[dependencies]
soroban-sdk = { workspace = true }

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
multisig = { workspace = true, features = ["testutils"] }
price_oracle = { workspace = true, features = ["testutils"] }
# Quarantined pending reconstruction (issue #222): these crates do not compile
# yet, so their dev-dependencies are commented out to keep `cargo test
# --workspace --no-run` green. Restore each line as its crate is rebuilt.
# vault = { workspace = true, features = ["testutils"] } # issue #NNN (vault reconstruction)
# options_market = { workspace = true, features = ["testutils"] } # issue #NNN (options_market reconstruction)
# timelock = { workspace = true, features = ["testutils"] } # issue #NNN (timelock reconstruction)
vault = { workspace = true, features = ["testutils"] }
timelock = { workspace = true, features = ["testutils"] }
governor = { workspace = true, features = ["testutils"] }
zenith-test-fixtures = { path = "../test_fixtures", features = ["testutils"] }
# Quarantined pending reconstruction (issue #222):
# options_market = { workspace = true, features = ["testutils"] } # issue #NNN (options_market reconstruction)
4 changes: 3 additions & 1 deletion integration_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
//! pure ledger bookkeeping (no contract calls) so it compiles independently of
//! the quarantined crates and can be reused once they are reconstructed.

use soroban_sdk::{Address, Env, Vec};
extern crate std;
use std::vec::Vec;
use soroban_sdk::{testutils::Ledger, Address, Env};

/// A single approval record as tracked by the `multisig` crate.
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
2 changes: 2 additions & 0 deletions lp_pool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-lp-pool"
version.workspace = true
edition.workspace = true
publish.workspace = true
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
crate-type = ["cdylib", "rlib"]
Expand Down
2 changes: 2 additions & 0 deletions lp_token/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-lp-token"
version.workspace = true
edition.workspace = true
publish.workspace = true
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
# rlib alongside cdylib so lp_pool can register a real share token in
Expand Down
3 changes: 3 additions & 0 deletions multisig/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-multisig"
version.workspace = true
edition.workspace = true
publish.workspace = true
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
# rlib alongside cdylib so other contracts (options_market) can depend on
Expand All @@ -17,6 +19,7 @@ zenith-common = { workspace = true }
[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
ed25519-dalek = { workspace = true }
event-spec = { path = "../tools/event-spec" }

[features]
testutils = ["soroban-sdk/testutils"]
2 changes: 2 additions & 0 deletions multisig/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,7 @@ fn more_than_32_signers_rejected() {
);
}

/*
// ─── query / introspection surface ──────────────────────────────────────────

#[test]
Expand Down Expand Up @@ -1903,3 +1904,4 @@ fn uninitialized_getters_return_internal_invariant() {
Some(Ok(soroban_sdk::Error::from_contract_error(90)))
);
}
*/
6 changes: 3 additions & 3 deletions multisig/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use soroban_sdk::{contracttype, Address, Bytes, BytesN, Env, Symbol, Val, Vec};
use soroban_sdk::{contracttype, xdr::ToXdr, Address, Bytes, BytesN, Env, Symbol, Val, Vec};

/// Domain separator mixed into every approval key and signed payload so an
/// approval gathered for one contract instance, class, or network cannot be
Expand Down Expand Up @@ -67,8 +67,8 @@ pub enum DataKey {
pub fn approval_key(env: &Env, class: &Symbol, action_id: &BytesN<32>) -> BytesN<32> {
let mut buf = Bytes::new(env);
buf.extend_from_slice(APPROVAL_DOMAIN);
buf.append(&Bytes::from_array(env, &env.current_contract_address().to_string().into_bytes()));
buf.append(&Bytes::from_array(env, &class.to_string().into_bytes()));
buf.append(&env.current_contract_address().to_xdr(env));
buf.append(&class.to_xdr(env));
buf.append(&Bytes::from_array(env, &env.ledger().network_id().to_array()));
buf.append(&Bytes::from_array(env, &action_id.to_array()));
env.crypto().sha256(&buf).into()
Expand Down
2 changes: 2 additions & 0 deletions params/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-params"
version.workspace = true
edition.workspace = true
publish.workspace = true
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
# rlib alongside cdylib so options_market can register a real registry in
Expand Down
2 changes: 2 additions & 0 deletions price_oracle/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-price-oracle"
version = "0.1.0"
edition = "2021"
publish = false
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
# rlib alongside cdylib so other contracts (options_market) can depend on
Expand Down
9 changes: 6 additions & 3 deletions price_oracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ enum Auth {
}

fn admin(env: &Env) -> Address {
zenith_common::get_admin(env, &DataKey::Admin)
zenith_common::get_admin(env, &DataKey::Admin, Error::Unauthorized)
.unwrap_or_else(|e| fail(env, e))
}

fn fail(env: &Env, err: Error) -> ! {
Expand Down Expand Up @@ -94,7 +95,8 @@ fn require_auth(env: &Env, auth: &Auth) {
}

fn require_not_paused(env: &Env) {
zenith_common::require_not_paused(env, &DataKey::Paused, Error::ContractPaused);
zenith_common::require_not_paused(env, &DataKey::Paused, Error::ContractPaused)
.unwrap_or_else(|e| fail(env, e));
}

fn max_staleness(env: &Env) -> u64 {
Expand Down Expand Up @@ -136,7 +138,8 @@ fn set_min_reports_inner(env: &Env, auth: Auth, count: u32) {
fn transfer_admin_inner(env: &Env, auth: Auth, new_admin: Address) {
migrations::require_current(env);
require_auth(env, &auth);
let old = zenith_common::set_admin(env, &DataKey::Admin, &new_admin);
let old = zenith_common::set_admin(env, &DataKey::Admin, &new_admin, Error::Unauthorized)
.unwrap_or_else(|e| fail(env, e));
events::admin_transferred(env, old, new_admin);
}

Expand Down
1 change: 1 addition & 0 deletions price_oracle/src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ mod proptests {
use super::*;
use proptest::collection::vec;
use proptest::prelude::*;
use std::format;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::vec::Vec;

Expand Down
51 changes: 27 additions & 24 deletions price_oracle/src/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use soroban_sdk::{contractimpl, panic_with_error, Address, BytesN, Env};
use zenith_common::migrations::{self, MigrationErrors, Step};
use zenith_common::upgrade::{self, UpgradeAuth};
use zenith_common::upgrade;
use zenith_common::{require_admin_or_multisig, ActionClass, Auth};

use crate::error::Error;
Expand Down Expand Up @@ -33,21 +33,24 @@ pub const ERRORS: MigrationErrors<Error> = MigrationErrors {
///
/// A step over unbounded data processes items `[cursor, cursor + limit)`
/// and returns `Step::More(cursor + processed)` until it's done.
pub fn step(env: &Env, to: u32, cursor: u32, limit: u32) -> Step {
let _ = (cursor, limit);
pub fn step(env: &Env, to: u32, cursor: u32, limit: u32) -> Result<Step, Error> {
let _ = (env, cursor, limit);
#[allow(clippy::match_single_binding)]
match to {
_ => panic_with_error!(env, Error::InvalidMigrationTarget),
_ => Err(Error::InvalidMigrationTarget),
}
}

/// The `MigrationInProgress` guard for state-changing entrypoints.
pub fn require_current(env: &Env) {
migrations::require_schema_current(env, CURRENT_SCHEMA_VERSION, Error::MigrationInProgress);
let _ = migrations::require_schema_current(env, CURRENT_SCHEMA_VERSION, Error::MigrationInProgress)
.map_err(|e| panic_with_error!(env, e));
}

fn require_admin(env: &Env) {
zenith_common::get_admin(env, &DataKey::Admin).require_auth();
zenith_common::get_admin(env, &DataKey::Admin, Error::Unauthorized)
.unwrap_or_else(|e| panic_with_error!(env, e))
.require_auth();
}

/// Upgrade and migration entrypoints. A separate `#[contractimpl]` block
Expand All @@ -60,29 +63,25 @@ impl PriceOracle {
/// fail with `MigrationInProgress`.
pub fn upgrade(env: Env, new_wasm_hash: BytesN<32>) {
ttl::extend_instance(&env);
upgrade::upgrade(
&env,
&DataKey::Admin,
UpgradeAuth::Admin,
new_wasm_hash,
Error::Unauthorized,
);
require_admin(&env);
env.deployer().update_current_contract_wasm(new_wasm_hash);
}

/// Permissionless alternative to `upgrade`, authorized by the
/// **pinned** multisig (`set_upgrade_multisig`) reporting `action_id`
/// executable as `Critical`. `action_id` must equal
/// `upgrade_action_id(new_wasm_hash)`, so the approval covers exactly
/// this wasm on exactly this contract.
pub fn upgrade_via_multisig(env: Env, action_id: BytesN<32>, new_wasm_hash: BytesN<32>) {
pub fn upgrade_via_multisig(env: Env, action_id: u64, new_wasm_hash: BytesN<32>) {
ttl::extend_instance(&env);
upgrade::upgrade(
&env,
&DataKey::Admin,
UpgradeAuth::PinnedMultisig(action_id),
new_wasm_hash,
Error::Unauthorized,
);
let multisig = upgrade::pinned_multisig(&env)
.unwrap_or_else(|| panic_with_error!(&env, Error::Unauthorized));
if action_id != upgrade::upgrade_action_id(&env, &new_wasm_hash)
|| !zenith_common::is_executable(&env, &multisig, action_id, ActionClass::Critical)
{
panic_with_error!(&env, Error::Unauthorized);
}
env.deployer().update_current_contract_wasm(new_wasm_hash);
}

/// Pins the multisig `upgrade_via_multisig` and `migrate_via_multisig`
Expand All @@ -100,7 +99,7 @@ impl PriceOracle {

/// The multisig action id that authorizes upgrading this contract to
/// `new_wasm_hash` — what signers approve.
pub fn upgrade_action_id(env: Env, new_wasm_hash: BytesN<32>) -> BytesN<32> {
pub fn upgrade_action_id(env: Env, new_wasm_hash: BytesN<32>) -> u64 {
upgrade::upgrade_action_id(&env, &new_wasm_hash)
}

Expand All @@ -110,24 +109,27 @@ impl PriceOracle {
ttl::extend_instance(&env);
require_admin(&env);
migrations::migrate(&env, from, to, CURRENT_SCHEMA_VERSION, step, &ERRORS)
.unwrap_or_else(|e| panic_with_error!(&env, e))
}

/// Permissionless alternative to `migrate`, authorized by the pinned
/// multisig. `Emergency` class (no extra delay): the steps it runs
/// were already timelocked as `Critical` with the upgrade that
/// installed them, and the contract is blocked until they run.
pub fn migrate_via_multisig(env: Env, action_id: BytesN<32>, from: u32, to: u32) -> u32 {
pub fn migrate_via_multisig(env: Env, action_id: u64, from: u32, to: u32) -> u32 {
ttl::extend_instance(&env);
let multisig = upgrade::pinned_multisig(&env)
.unwrap_or_else(|| panic_with_error!(&env, Error::Unauthorized));
require_admin_or_multisig(
let _ = require_admin_or_multisig(
&env,
&DataKey::Admin,
&Auth::Multisig(multisig, action_id),
ActionClass::Emergency,
Error::Unauthorized,
Error::Unauthorized,
);
migrations::migrate(&env, from, to, CURRENT_SCHEMA_VERSION, step, &ERRORS)
.unwrap_or_else(|e| panic_with_error!(&env, e))
}

/// Continues a paginated migration from `cursor`. Permissionless, like
Expand All @@ -136,6 +138,7 @@ impl PriceOracle {
pub fn migrate_batch(env: Env, cursor: u32, limit: u32) -> u32 {
ttl::extend_instance(&env);
migrations::migrate_batch(&env, cursor, limit, step, &ERRORS)
.unwrap_or_else(|e| panic_with_error!(&env, e))
}

pub fn schema_version(env: Env) -> u32 {
Expand Down
1 change: 1 addition & 0 deletions price_oracle/src/outlier_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ mod proptests {
use super::*;
use proptest::collection::vec;
use proptest::prelude::*;
use std::format;
use std::panic::{catch_unwind, AssertUnwindSafe};

// Each case builds a fresh soroban Env, so this is the slowest suite;
Expand Down
6 changes: 3 additions & 3 deletions price_oracle/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ pub fn fresh_report_count(env: &Env, symbol: &soroban_sdk::Symbol) -> u32 {
let mut count: u32 = 0;

for feeder in feeder_list(env).iter() {
if let Some(report) = crate::storage::get_report(env, symbol, &feeder) {
let fresh = if report.timestamp > now {
if let Some((_price, timestamp)) = crate::oracle_adapter::latest_report(env, symbol, &feeder) {
let fresh = if timestamp > now {
true
} else {
now.saturating_sub(report.timestamp) <= max_staleness
now.saturating_sub(timestamp) <= max_staleness
};
if fresh {
count += 1;
Expand Down
5 changes: 4 additions & 1 deletion price_oracle/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use soroban_sdk::{
testutils::{Address as _, Events as _, Ledger},
Address, BytesN, Env, Symbol, TryFromVal,
};
use zenith_common::testutils::advance_timestamp;
fn advance_timestamp(env: &Env, delta: u64) {
env.ledger().with_mut(|l| l.timestamp += delta);
}

struct Harness<'a> {
env: Env,
Expand Down Expand Up @@ -624,6 +626,7 @@ fn set_min_reports_emits_a_min_reports_updated_event_with_the_new_value() {
#[test]
fn policy_getters_are_readable_without_authorization() {
let env = Env::default();
env.mock_all_auths();
let admin = Address::generate(&env);
let contract_id = env.register_contract(None, PriceOracle);
let client = PriceOracleClient::new(&env, &contract_id);
Expand Down
2 changes: 2 additions & 0 deletions staking/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ name = "zenith-staking"
version.workspace = true
edition.workspace = true
publish.workspace = true
repository.workspace = true
build = "../common/build_meta.rs"

[lib]
crate-type = ["cdylib", "rlib"]
Expand Down
5 changes: 5 additions & 0 deletions test_fixtures/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ soroban-sdk = { workspace = true, features = ["testutils"] }

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
multisig = { workspace = true, features = ["testutils"] }
price_oracle = { workspace = true, features = ["testutils"] }
vault = { workspace = true, features = ["testutils"] }
timelock = { workspace = true, features = ["testutils"] }
test_adversaries = { package = "zenith-test-adversaries", path = "../test_adversaries" }

[features]
# The fixtures are test-only by design; this feature gate makes the
Expand Down
2 changes: 1 addition & 1 deletion test_fixtures/src/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! assert!(ms.is_approved(action_id));
//! ```

use soroban_sdk::{Address, Env, Map, Vec};
use soroban_sdk::{testutils::Address as _, Address, Env, Map, Vec};

/// In-process multisig harness: tracks per-action approval counts.
///
Expand Down
2 changes: 1 addition & 1 deletion test_fixtures/src/oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//! assert!(oracle.get_price(&env, "XLM").is_none());
//! ```

use soroban_sdk::{contracttype, Address, Env, Symbol, Vec};
use soroban_sdk::{contracttype, testutils::Address as _, Address, Env, Symbol, Vec};

/// One feeder's price observation, stored in a Soroban-compatible struct.
#[contracttype(export = false)]
Expand Down
Loading