From d0ba01dce4f91301b3f98cbd291292f64dae7e77 Mon Sep 17 00:00:00 2001 From: carrion256 Date: Mon, 8 Jun 2026 14:47:30 +0200 Subject: [PATCH] fix(proxy-curator): repair facade governance routes --- .gitignore | 1 + .../proxy-curator-soroban/src/contract.rs | 21 +--- contract/proxy-curator-soroban/src/lib.rs | 2 +- contract/proxy-curator-soroban/src/tests.rs | 114 +++++++++++++++--- 4 files changed, 108 insertions(+), 30 deletions(-) diff --git a/.gitignore b/.gitignore index 8d9ef7d98..b1f8b9fe4 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ _site/ # generated soroban test snapshots contract/vault/**/test_snapshots/ contract/proxy-oracle/**/test_snapshots/ +contract/proxy-*-soroban/**/test_snapshots/ # generated bindings client/vault/dist/ diff --git a/contract/proxy-curator-soroban/src/contract.rs b/contract/proxy-curator-soroban/src/contract.rs index 8adadc5a8..0b5cc3d42 100644 --- a/contract/proxy-curator-soroban/src/contract.rs +++ b/contract/proxy-curator-soroban/src/contract.rs @@ -7,8 +7,8 @@ use soroban_sdk::{ InvokeError, String, Symbol, TryFromVal, Val, Vec, }; use templar_soroban_governance::{ - GovernanceAction, GovernanceActionKind, GovernanceError, PendingProposal, TimelockKind, - Timelocks, + GovernanceAction, GovernanceActionKind, GovernanceError, PendingProposal, + SupplyQueueProposalEntry, TimelockKind, Timelocks, }; use templar_soroban_shared_types::{ EmptyReceipt, I128Receipt, ProxyPreviewFields, ProxyViewFields, ProxyViewResponse, @@ -130,9 +130,6 @@ pub(crate) enum VaultCommand { markets: Vec, }, ResyncIdleBalance, - CancelMigration { - caller: Address, - }, ExtendTtl, } @@ -155,9 +152,6 @@ impl VaultCommand { markets: soroban_u32_vec_to_alloc(markets), }), Self::ResyncIdleBalance => Ok(WireVaultCommand::ResyncIdleBalance), - Self::CancelMigration { caller } => Ok(WireVaultCommand::CancelMigration { - caller: address_to_wire(&caller)?, - }), Self::ExtendTtl => Ok(WireVaultCommand::ExtendTtl), } } @@ -251,12 +245,9 @@ impl SorobanCuratorProxyContract { expect_unit_result(invoke_vault_execute(&env, VaultCommand::ExtendTtl)?) } - pub fn cancel_migration(env: Env, admin: Address) -> Result<(), ContractError> { + pub fn cancel_migration(env: Env, admin: Address) -> Result { admin.require_auth(); - expect_unit_result(invoke_vault_execute( - &env, - VaultCommand::CancelMigration { caller: admin }, - )?) + invoke_governance(&env, "submit_cancel_migration", (admin,).into_val(&env)) } pub fn set_paused(env: Env, admin: Address, paused: bool) -> Result { @@ -293,13 +284,13 @@ impl SorobanCuratorProxyContract { pub fn set_supply_queue( env: Env, admin: Address, - markets: Vec, + entries: Vec, ) -> Result { admin.require_auth(); invoke_governance( &env, "submit_set_supply_queue", - (admin, markets).into_val(&env), + (admin, entries).into_val(&env), ) } diff --git a/contract/proxy-curator-soroban/src/lib.rs b/contract/proxy-curator-soroban/src/lib.rs index ef317a673..5a7410a48 100644 --- a/contract/proxy-curator-soroban/src/lib.rs +++ b/contract/proxy-curator-soroban/src/lib.rs @@ -14,7 +14,7 @@ pub use contract::{ }; pub use error::ContractError; pub use templar_soroban_governance::{ - GovernanceActionKind, PendingProposal, TimelockKind, Timelocks, + GovernanceActionKind, PendingProposal, SupplyQueueProposalEntry, TimelockKind, Timelocks, }; #[cfg(test)] diff --git a/contract/proxy-curator-soroban/src/tests.rs b/contract/proxy-curator-soroban/src/tests.rs index 337a2939e..acb9ef3c2 100644 --- a/contract/proxy-curator-soroban/src/tests.rs +++ b/contract/proxy-curator-soroban/src/tests.rs @@ -1,8 +1,8 @@ use soroban_sdk::testutils::Address as _; use soroban_sdk::{contract, contractimpl, contracttype, Address, Bytes, Env, Vec}; use templar_soroban_governance::{ - GovernanceAction, GovernanceActionKind, GovernanceError, PendingProposal, TimelockKind, - Timelocks, + GovernanceAction, GovernanceActionKind, GovernanceError, PendingProposal, + SupplyQueueProposalEntry, TimelockKind, Timelocks, }; use templar_soroban_runtime::ContractError as VaultContractError; use templar_soroban_shared_types::{ @@ -62,10 +62,12 @@ impl MockVaultContract { #[allow(clippy::enum_variant_names)] enum MockGovernanceDataKey { LastSetCap, + LastSetSupplyQueue, LastTimelock, LastFees, LastRestrictions, LastCapGroupUpdate, + LastCancelMigration, LastAccept, LastRevoke, PendingIds, @@ -80,6 +82,13 @@ struct MockSetCapCall { new_cap: i128, } +#[derive(Clone, Eq, PartialEq)] +#[contracttype] +struct MockSetSupplyQueueCall { + caller: Address, + entries: Vec, +} + #[derive(Clone, Eq, PartialEq)] #[contracttype] struct MockTimelockCall { @@ -109,6 +118,12 @@ struct MockCapGroupUpdateCall { update: CapGroupUpdate, } +#[derive(Clone, Debug, Eq, PartialEq)] +#[contracttype] +struct MockCancelMigrationCall { + caller: Address, +} + #[derive(Clone, Debug, Eq, PartialEq)] #[contracttype] struct MockAcceptCall { @@ -151,6 +166,24 @@ impl MockGovernanceContract { .get(&MockGovernanceDataKey::LastSetCap) } + pub fn submit_set_supply_queue( + env: Env, + caller: Address, + entries: Vec, + ) -> Result { + env.storage().instance().set( + &MockGovernanceDataKey::LastSetSupplyQueue, + &MockSetSupplyQueueCall { caller, entries }, + ); + Ok(91) + } + + pub fn last_set_supply_queue(env: Env) -> Option { + env.storage() + .instance() + .get(&MockGovernanceDataKey::LastSetSupplyQueue) + } + pub fn submit_set_timelock( env: Env, caller: Address, @@ -251,6 +284,20 @@ impl MockGovernanceContract { .get(&MockGovernanceDataKey::LastCapGroupUpdate) } + pub fn submit_cancel_migration(env: Env, caller: Address) -> Result { + env.storage().instance().set( + &MockGovernanceDataKey::LastCancelMigration, + &MockCancelMigrationCall { caller }, + ); + Ok(92) + } + + pub fn last_cancel_migration(env: Env) -> Option { + env.storage() + .instance() + .get(&MockGovernanceDataKey::LastCancelMigration) + } + pub fn accept(env: Env, caller: Address, proposal_id: u64) -> Result<(), GovernanceError> { env.storage().instance().set( &MockGovernanceDataKey::LastAccept, @@ -488,7 +535,6 @@ fn refresh_markets_encodes_refresh_command() { fn unit_vault_operations_encode_unit_commands() { let fixture = Fixture::new(); fixture.initialize().expect("initialize succeeds"); - let caller = Address::generate(&fixture.env); fixture .env @@ -502,15 +548,9 @@ fn unit_vault_operations_encode_unit_commands() { SorobanCuratorProxyContract::extend_vault_ttl(fixture.env.clone()) }) .unwrap(); - fixture - .env - .as_contract(&fixture.proxy, || { - SorobanCuratorProxyContract::cancel_migration(fixture.env.clone(), caller.clone()) - }) - .unwrap(); let payloads = fixture.recorded_payloads(); - assert_eq!(payloads.len(), 3); + assert_eq!(payloads.len(), 2); assert_eq!( decode_command(&payloads.get_unchecked(0)), WireVaultCommand::ResyncIdleBalance @@ -519,10 +559,28 @@ fn unit_vault_operations_encode_unit_commands() { decode_command(&payloads.get_unchecked(1)), WireVaultCommand::ExtendTtl ); - assert!(matches!( - decode_command(&payloads.get_unchecked(2)), - WireVaultCommand::CancelMigration { .. } - )); +} + +#[test] +fn cancel_migration_submits_timelocked_governance_proposal() { + let fixture = Fixture::new(); + fixture.initialize().expect("initialize succeeds"); + let admin = Address::generate(&fixture.env); + + assert_eq!( + fixture.env.as_contract(&fixture.proxy, || { + SorobanCuratorProxyContract::cancel_migration(fixture.env.clone(), admin.clone()) + }), + Ok(92) + ); + + assert_eq!(fixture.recorded_payloads().len(), 0); + assert_eq!( + fixture.env.as_contract(&fixture.governance, || { + MockGovernanceContract::last_cancel_migration(fixture.env.clone()) + }), + Some(MockCancelMigrationCall { caller: admin }) + ); } #[test] @@ -559,8 +617,36 @@ fn typed_governance_facade_forwards_domain_arguments() { let admin = Address::generate(&fixture.env); let fee_recipient = Address::generate(&fixture.env); let restriction_account = Address::generate(&fixture.env); + let adapter = Address::generate(&fixture.env); let group = soroban_sdk::String::from_str(&fixture.env, "senior"); + let supply_entries = Vec::from_array( + &fixture.env, + [SupplyQueueProposalEntry { + target_id: 17, + adapter: adapter.clone(), + }], + ); + assert_eq!( + fixture.env.as_contract(&fixture.proxy, || { + SorobanCuratorProxyContract::set_supply_queue( + fixture.env.clone(), + admin.clone(), + supply_entries.clone(), + ) + }), + Ok(91) + ); + let supply_queue_call = fixture + .env + .as_contract(&fixture.governance, || { + MockGovernanceContract::last_set_supply_queue(fixture.env.clone()) + }) + .expect("set supply queue call recorded"); + assert_eq!(supply_queue_call.caller, admin.clone()); + assert_eq!(supply_queue_call.entries.len(), 1); + assert!(supply_queue_call.entries.get_unchecked(0) == supply_entries.get_unchecked(0)); + let fees = Fees { performance_fee_wad: 10, performance_recipient: fee_recipient.clone(),