From 15eebc3cf064adf23d856a945947c0b6d9618101 Mon Sep 17 00:00:00 2001 From: ZacLou Date: Thu, 3 Sep 2026 05:26:48 +0800 Subject: [PATCH 1/2] feat(contracts): TTL management for vault and adapters (#553) - Add TTL constants and extend helpers to vault, blend-adapter, defindex-adapter. - Bump instance TTL on all state-changing vault and adapter entry points. - Bump position TTL on deposit, withdraw, get_position and permissionless extend_position_ttl. - Add tests covering TTL extension behavior. --- packages/contracts/blend-adapter/src/lib.rs | 67 +++++++++++++- .../contracts/defindex-adapter/src/lib.rs | 50 ++++++++++- packages/contracts/vault/src/lib.rs | 90 +++++++++++++++++++ 3 files changed, 205 insertions(+), 2 deletions(-) diff --git a/packages/contracts/blend-adapter/src/lib.rs b/packages/contracts/blend-adapter/src/lib.rs index 8e253148..b166007b 100644 --- a/packages/contracts/blend-adapter/src/lib.rs +++ b/packages/contracts/blend-adapter/src/lib.rs @@ -18,6 +18,11 @@ use soroban_sdk::{ const POOL_KEY: Symbol = symbol_short!("POOL"); const TOTAL_KEY: Symbol = symbol_short!("TOTAL"); +// TTL bump targets. A "day" is ~17,280 ledgers at ~5 s/ledger. +const DAY_IN_LEDGERS: u32 = 17_280; +const INSTANCE_BUMP: u32 = 30 * DAY_IN_LEDGERS; +const INSTANCE_THRESHOLD: u32 = INSTANCE_BUMP - DAY_IN_LEDGERS; + // Blend RequestType constants, per // blend-contracts-v2/pool/src/request_type.rs (submitted against the pool's // `submit`). The "collateral" suffix is deliberate and load-bearing: this @@ -221,6 +226,7 @@ impl MeridianBlendAdapter { /// tracks genuine, appreciating shares instead of raw principal (#486). pub fn deposit(env: Env, amount: i128) -> i128 { require_vault_auth(&env); + Self::extend_instance(&env); let pool: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -300,6 +306,7 @@ impl MeridianBlendAdapter { /// measured directly rather than assumed to equal the request (#489). pub fn withdraw(env: Env, shares: i128, recipient: Address) -> i128 { require_vault_auth(&env); + Self::extend_instance(&env); let pool: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -361,6 +368,8 @@ impl MeridianBlendAdapter { /// (`get_positions`) rather than self-tracking it, so there is no risk of /// drift between the stored total and Blend's actual accounting. pub fn accrue(env: Env) -> Result<(), ContractError> { + Self::extend_instance(&env); + let pool: Address = env .storage() .instance() @@ -446,6 +455,15 @@ impl MeridianBlendAdapter { pub fn get_protocol(env: Env) -> Symbol { Symbol::new(&env, "blend") } + + /// Extends the TTL of the contract instance. Called at the start of + /// every state-changing entry point so the adapter's configuration + /// never expires while it is actively used. + fn extend_instance(env: &Env) { + env.storage() + .instance() + .extend_ttl(INSTANCE_THRESHOLD, INSTANCE_BUMP); + } } // --------------------------------------------------------------------------- @@ -457,7 +475,7 @@ mod tests { use super::*; use soroban_sdk::{ contract, contractimpl, - testutils::{Address as _, Events, MockAuth, MockAuthInvoke}, + testutils::{Address as _, Events, Ledger as _, MockAuth, MockAuthInvoke}, token::{StellarAssetClient, TokenClient}, Address, Env, }; @@ -1085,4 +1103,51 @@ mod tests { soroban_sdk::TryIntoVal::try_into_val(&accrue_event.2, &env).unwrap(); assert_eq!(data, (expected_prev, expected_new)); } + + #[test] + fn deposit_extends_instance_ttl() { + let (env, vault, usdc_id, adapter, _pool) = setup(); + let adapter_id = adapter.address.clone(); + let amount = 100_0000000_i128; + TokenClient::new(&env, &usdc_id).transfer(&vault, &adapter_id, &amount); + adapter.deposit(&amount); + env.ledger() + .with_mut(|li| li.sequence_number += INSTANCE_THRESHOLD - 1); + env.as_contract(&adapter_id, || { + assert!(env.storage().instance().has(&TOTAL_KEY)); + }); + } + + #[test] + fn withdraw_extends_instance_ttl() { + let (env, vault, usdc_id, adapter, _pool) = setup(); + let adapter_id = adapter.address.clone(); + let amount = 100_0000000_i128; + TokenClient::new(&env, &usdc_id).transfer(&vault, &adapter_id, &amount); + adapter.deposit(&amount); + let recipient = Address::generate(&env); + adapter.withdraw(&amount, &recipient); + env.ledger() + .with_mut(|li| li.sequence_number += INSTANCE_THRESHOLD - 1); + env.as_contract(&adapter_id, || { + assert!(env.storage().instance().has(&TOTAL_KEY)); + }); + } + + #[test] + fn accrue_extends_instance_ttl() { + let (env, vault, usdc_id, adapter, pool) = setup(); + let adapter_id = adapter.address.clone(); + let amount = 100_0000000_i128; + TokenClient::new(&env, &usdc_id).transfer(&vault, &adapter_id, &amount); + adapter.deposit(&amount); + let new_rate = SCALAR + SCALAR / 10; + pool.set_rate(&new_rate); + adapter.accrue(); + env.ledger() + .with_mut(|li| li.sequence_number += INSTANCE_THRESHOLD - 1); + env.as_contract(&adapter_id, || { + assert!(env.storage().instance().has(&TOTAL_KEY)); + }); + } } diff --git a/packages/contracts/defindex-adapter/src/lib.rs b/packages/contracts/defindex-adapter/src/lib.rs index 662bbeaa..d50aab24 100644 --- a/packages/contracts/defindex-adapter/src/lib.rs +++ b/packages/contracts/defindex-adapter/src/lib.rs @@ -14,6 +14,11 @@ use soroban_sdk::{ const DFX_VAULT: Symbol = symbol_short!("DFXVAULT"); +// TTL bump targets. A "day" is ~17,280 ledgers at ~5 s/ledger. +const DAY_IN_LEDGERS: u32 = 17_280; +const INSTANCE_BUMP: u32 = 30 * DAY_IN_LEDGERS; +const INSTANCE_THRESHOLD: u32 = INSTANCE_BUMP - DAY_IN_LEDGERS; + // --------------------------------------------------------------------------- // DeFindex vault interface // --------------------------------------------------------------------------- @@ -137,6 +142,7 @@ impl MeridianDefindexAdapter { /// returns the dfToken shares received. pub fn deposit(env: Env, amount: i128) -> i128 { require_vault_auth(&env); + Self::extend_instance(&env); let dfx: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -169,6 +175,7 @@ impl MeridianDefindexAdapter { /// `recipient`. Returns the USDC amount received. pub fn withdraw(env: Env, shares: i128, recipient: Address) -> i128 { require_vault_auth(&env); + Self::extend_instance(&env); let dfx: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -194,6 +201,8 @@ impl MeridianDefindexAdapter { /// Live USDC value of the adapter's dfToken position, computed by the /// DeFindex vault's exchange rate. Updates automatically as yield accrues. pub fn total_assets(env: Env) -> i128 { + Self::extend_instance(&env); + let dfx: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, env.storage().instance().get(&DFX_VAULT), @@ -241,6 +250,15 @@ impl MeridianDefindexAdapter { pub fn get_protocol(env: Env) -> Symbol { Symbol::new(&env, "defindex") } + + /// Extends the TTL of the contract instance. Called at the start of + /// every state-changing entry point so the adapter's configuration + /// never expires while it is actively used. + fn extend_instance(env: &Env) { + env.storage() + .instance() + .extend_ttl(INSTANCE_THRESHOLD, INSTANCE_BUMP); + } } // --------------------------------------------------------------------------- @@ -252,7 +270,7 @@ mod tests { use super::*; use soroban_sdk::{ contract, contractimpl, symbol_short, - testutils::Address as _, + testutils::{Address as _, Ledger as _}, token::{StellarAssetClient, TokenClient}, Address, Env, }; @@ -677,4 +695,34 @@ mod tests { let _ = ContractError::Overflow; let _ = ContractError::NotInitialized; } + + #[test] + fn deposit_extends_instance_ttl() { + let (env, vault, usdc_id, adapter, _dfx) = setup(); + let adapter_id = adapter.address.clone(); + let amount = 100_0000000_i128; + TokenClient::new(&env, &usdc_id).transfer(&vault, &adapter_id, &amount); + adapter.deposit(&amount); + env.ledger() + .with_mut(|li| li.sequence_number += INSTANCE_THRESHOLD - 1); + env.as_contract(&adapter_id, || { + assert!(env.storage().instance().has(&DFX_VAULT)); + }); + } + + #[test] + fn withdraw_extends_instance_ttl() { + let (env, vault, usdc_id, adapter, _dfx) = setup(); + let adapter_id = adapter.address.clone(); + let amount = 100_0000000_i128; + TokenClient::new(&env, &usdc_id).transfer(&vault, &adapter_id, &amount); + adapter.deposit(&amount); + let recipient = Address::generate(&env); + adapter.withdraw(&amount, &recipient); + env.ledger() + .with_mut(|li| li.sequence_number += INSTANCE_THRESHOLD - 1); + env.as_contract(&adapter_id, || { + assert!(env.storage().instance().has(&DFX_VAULT)); + }); + } } diff --git a/packages/contracts/vault/src/lib.rs b/packages/contracts/vault/src/lib.rs index 30c5c694..5b8e0239 100644 --- a/packages/contracts/vault/src/lib.rs +++ b/packages/contracts/vault/src/lib.rs @@ -34,6 +34,12 @@ const MIN_LEDGER_GAP: u32 = 12; /// Top-level topic shared by all vault admin-action events. const ADMIN_EVT: Symbol = symbol_short!("admin"); +// TTL bump targets. A "day" is ~17,280 ledgers at ~5 s/ledger. +const DAY_IN_LEDGERS: u32 = 17_280; +const INSTANCE_BUMP: u32 = 30 * DAY_IN_LEDGERS; +const INSTANCE_THRESHOLD: u32 = INSTANCE_BUMP - DAY_IN_LEDGERS; +const POSITION_BUMP: u32 = 120 * DAY_IN_LEDGERS; +const POSITION_THRESHOLD: u32 = POSITION_BUMP - 7 * DAY_IN_LEDGERS; // Virtual shares/assets offset (OpenZeppelin ERC-4626 mitigation against the // first-depositor inflation attack). Share price is computed against @@ -274,6 +280,8 @@ impl MeridianVault { return Err(ContractError::ZeroAmount); } + Self::extend_instance(&env); + let usdc = Self::usdc(&env)?; let musdc = Self::musdc(&env)?; let adapter_addr: Address = env @@ -375,6 +383,8 @@ impl MeridianVault { .persistent() .set(&principal_key, &(prev_principal + amount)); + Self::extend_position(&env, &caller); + Ok(shares_to_mint) } @@ -402,6 +412,8 @@ impl MeridianVault { return Err(ContractError::ZeroAmount); } + Self::extend_instance(&env); + let usdc = Self::usdc(&env)?; let musdc = Self::musdc(&env)?; let adapter_addr: Address = env @@ -490,6 +502,8 @@ impl MeridianVault { Self::clear_position_records(&env, &caller); } + Self::extend_position(&env, &caller); + Ok(usdc_out) } @@ -646,6 +660,7 @@ impl MeridianVault { /// used by dashboards, and "no position" is the truthful answer for a /// vault that holds nothing yet. pub fn get_position(env: Env, address: Address) -> i128 { + Self::extend_position(&env, &address); match Self::musdc(&env) { Ok(musdc) => TokenClient::new(&env, &musdc).balance(&address), Err(_) => 0, @@ -712,6 +727,15 @@ impl MeridianVault { env.storage().persistent().get(&key).unwrap_or(0) } + /// Permissionless entry point that extends the TTL of instance storage + /// and the position records for `address`. Anyone can call it, so + /// off-chain keepers or the user themselves can keep a position alive + /// without needing a signature on the vault. + pub fn extend_position_ttl(env: Env, address: Address) { + Self::extend_instance(&env); + Self::extend_position(&env, &address); + } + /// Total USDC value managed by the vault as reported by the adapter. /// Includes yield accrued by the underlying protocol. pub fn get_total_assets(env: Env) -> Result { @@ -736,6 +760,7 @@ impl MeridianVault { /// Withdrawals are deliberately left open so a pause can never trap funds. pub fn set_paused(env: Env, paused: bool) -> Result<(), ContractError> { Self::require_admin(&env)?; + Self::extend_instance(&env); env.storage().instance().set(&PAUSED, &paused); env.events() .publish((ADMIN_EVT, symbol_short!("paused")), paused); @@ -756,6 +781,7 @@ impl MeridianVault { /// not-yet-accepted nomination. pub fn transfer_admin(env: Env, new_admin: Address) -> Result<(), ContractError> { Self::require_admin(&env)?; + Self::extend_instance(&env); env.storage().instance().set(&PEND_ADM, &new_admin); env.events() .publish((ADMIN_EVT, symbol_short!("transfer")), new_admin.clone()); @@ -774,6 +800,7 @@ impl MeridianVault { .get(&PEND_ADM) .ok_or(ContractError::NoPendingAdmin)?; pending.require_auth(); + Self::extend_instance(&env); env.storage().instance().set(&ADMIN, &pending); env.storage().instance().remove(&PEND_ADM); env.events() @@ -810,6 +837,7 @@ impl MeridianVault { /// already zero) leaving `ADPT_SH` alone is a no-op. pub fn set_adapter(env: Env, new_adapter: Address) -> Result<(), ContractError> { Self::require_admin(&env)?; + Self::extend_instance(&env); let total_adapter_shares: i128 = env.storage().instance().get(&ADPT_SH).unwrap_or(0); if Self::get_total_shares(env.clone()) > 0 || total_adapter_shares > 0 { return Err(ContractError::AdapterSwapUnsafe); @@ -840,6 +868,7 @@ impl MeridianVault { /// the ledger gap to elapse before calling `migrate_adapter`. pub fn begin_migration(env: Env, new_adapter: Address) -> Result<(), ContractError> { Self::require_admin(&env)?; + Self::extend_instance(&env); let old_adapter_addr = Self::get_adapter(env.clone())?; if new_adapter == old_adapter_addr { @@ -926,6 +955,7 @@ impl MeridianVault { max_slippage_bps: u32, ) -> Result<(), ContractError> { Self::require_admin(&env)?; + Self::extend_instance(&env); if max_slippage_bps > 10_000 { return Err(ContractError::InvalidSlippageBps); @@ -1097,6 +1127,30 @@ impl MeridianVault { .persistent() .remove(&DataKey::Principal(address.clone())); } + + /// Extends the TTL of the contract instance. Called at the start of + /// every state-changing entry point so the vault's configuration never + /// expires while it is actively used. + fn extend_instance(env: &Env) { + env.storage() + .instance() + .extend_ttl(INSTANCE_THRESHOLD, INSTANCE_BUMP); + } + + /// Extends the TTL of an address's position records (entry time and + /// principal) whenever the position is read or written. Permissionless + /// `extend_position_ttl` calls this for keepers. + fn extend_position(env: &Env, address: &Address) { + let storage = env.storage().persistent(); + for key in [ + DataKey::Entry(address.clone()), + DataKey::Principal(address.clone()), + ] { + if storage.has(&key) { + storage.extend_ttl(&key, POSITION_THRESHOLD, POSITION_BUMP); + } + } + } } // --------------------------------------------------------------------------- @@ -3251,4 +3305,40 @@ mod tests { let usdc_out = vault.withdraw(&user, &shares, &exact_floor); assert_eq!(usdc_out, amount); } + + #[test] + fn extend_position_ttl_is_permissionless() { + let (_env, _admin, user, _usdc, _musdc, _adapter, vault) = setup(); + vault.deposit(&user, &100_0000000_i128, &0_i128); + vault.extend_position_ttl(&user); + } + + #[test] + fn position_records_survive_ttl_advance() { + let (env, _admin, user, _usdc, _musdc, _adapter, vault) = setup(); + vault.deposit(&user, &100_0000000_i128, &0_i128); + vault.extend_position_ttl(&user); + env.ledger() + .with_mut(|li| li.sequence_number += INSTANCE_THRESHOLD - 1); + env.as_contract(&vault.address, || { + assert!(env + .storage() + .persistent() + .has(&DataKey::Entry(user.clone()))); + assert!(env + .storage() + .persistent() + .has(&DataKey::Principal(user.clone()))); + }); + } + + #[test] + fn admin_state_calls_extend_instance_ttl() { + let (env, _admin, _user, _usdc, _musdc, _adapter, vault) = setup(); + vault.set_paused(&true); + env.ledger() + .with_mut(|li| li.sequence_number += INSTANCE_THRESHOLD - 1); + vault.set_paused(&false); + assert!(!vault.is_paused()); + } } From e53609886b962b954c62b389d7ad7dba90ece858 Mon Sep 17 00:00:00 2001 From: Zac Lou <97340247+ZacLou@users.noreply.github.com> Date: Sat, 5 Sep 2026 00:47:26 +0800 Subject: [PATCH 2/2] fix(contracts): move TTL scaffolding to adapter-common, remove dead get_position extend (#553) Addresses review feedback on #704: 1. Move DAY_IN_LEDGERS/INSTANCE_BUMP/INSTANCE_THRESHOLD constants and extend_instance() from blend-adapter and defindex-adapter into adapter-common, so a future TTL policy change is made in one place rather than independently in every adapter crate. 2. Remove Self::extend_position from get_position(): the real-world caller (coordinator.ts) reads it exclusively through simulateTransaction, which never commits ledger state, so the TTL bump is dead in practice. Deposit, withdraw, and extend_position_ttl remain the real TTL-renewal paths. 3. migrate_adapter now has extend_instance (was already in commit 15eebc3), confirmed against review point. --- packages/contracts/adapter-common/src/lib.rs | 23 +++++++++++++++++++ packages/contracts/blend-adapter/src/lib.rs | 22 ++++-------------- .../contracts/defindex-adapter/src/lib.rs | 22 ++++-------------- packages/contracts/vault/src/lib.rs | 1 - 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/packages/contracts/adapter-common/src/lib.rs b/packages/contracts/adapter-common/src/lib.rs index ec3f1cf0..edaaa55b 100644 --- a/packages/contracts/adapter-common/src/lib.rs +++ b/packages/contracts/adapter-common/src/lib.rs @@ -8,6 +8,29 @@ use soroban_sdk::{contracterror, panic_with_error, symbol_short, Address, Env, Error, Symbol}; +// --------------------------------------------------------------------------- +// TTL constants — shared across all adapters so a policy change (e.g. +// adjusting the 30-day bump window) is made in one place rather than +// independently in every adapter crate, where the copies can silently drift +// out of sync. +// --------------------------------------------------------------------------- + +/// Approximate number of ledgers in a 24-hour period (at ~5 s/ledger). +pub const DAY_IN_LEDGERS: u32 = 17_280; +/// Instance TTL extension amount: 30 days in ledgers. +pub const INSTANCE_BUMP: u32 = 30 * DAY_IN_LEDGERS; +/// Extend instance TTL when remaining lifetime drops below this threshold. +pub const INSTANCE_THRESHOLD: u32 = INSTANCE_BUMP - DAY_IN_LEDGERS; + +/// Extends the contract instance's storage TTL. Called at the start of every +/// state-changing entry point so the adapter's configuration never expires +/// while it is actively used. +pub fn extend_instance(env: &Env) { + env.storage() + .instance() + .extend_ttl(INSTANCE_THRESHOLD, INSTANCE_BUMP); +} + // --------------------------------------------------------------------------- // Storage keys // --------------------------------------------------------------------------- diff --git a/packages/contracts/blend-adapter/src/lib.rs b/packages/contracts/blend-adapter/src/lib.rs index b166007b..833ddb8a 100644 --- a/packages/contracts/blend-adapter/src/lib.rs +++ b/packages/contracts/blend-adapter/src/lib.rs @@ -1,7 +1,8 @@ #![no_std] use adapter_common::{ - get_usdc, require_not_initialized, require_vault_auth, store_vault_and_usdc, AdapterError, + extend_instance, get_usdc, require_not_initialized, require_vault_auth, + store_vault_and_usdc, AdapterError, }; use soroban_sdk::{ auth::{ContractContext, InvokerContractAuthEntry, SubContractInvocation}, @@ -18,11 +19,6 @@ use soroban_sdk::{ const POOL_KEY: Symbol = symbol_short!("POOL"); const TOTAL_KEY: Symbol = symbol_short!("TOTAL"); -// TTL bump targets. A "day" is ~17,280 ledgers at ~5 s/ledger. -const DAY_IN_LEDGERS: u32 = 17_280; -const INSTANCE_BUMP: u32 = 30 * DAY_IN_LEDGERS; -const INSTANCE_THRESHOLD: u32 = INSTANCE_BUMP - DAY_IN_LEDGERS; - // Blend RequestType constants, per // blend-contracts-v2/pool/src/request_type.rs (submitted against the pool's // `submit`). The "collateral" suffix is deliberate and load-bearing: this @@ -226,7 +222,7 @@ impl MeridianBlendAdapter { /// tracks genuine, appreciating shares instead of raw principal (#486). pub fn deposit(env: Env, amount: i128) -> i128 { require_vault_auth(&env); - Self::extend_instance(&env); + extend_instance(&env); let pool: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -306,7 +302,7 @@ impl MeridianBlendAdapter { /// measured directly rather than assumed to equal the request (#489). pub fn withdraw(env: Env, shares: i128, recipient: Address) -> i128 { require_vault_auth(&env); - Self::extend_instance(&env); + extend_instance(&env); let pool: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -368,7 +364,7 @@ impl MeridianBlendAdapter { /// (`get_positions`) rather than self-tracking it, so there is no risk of /// drift between the stored total and Blend's actual accounting. pub fn accrue(env: Env) -> Result<(), ContractError> { - Self::extend_instance(&env); + extend_instance(&env); let pool: Address = env .storage() @@ -456,15 +452,7 @@ impl MeridianBlendAdapter { Symbol::new(&env, "blend") } - /// Extends the TTL of the contract instance. Called at the start of - /// every state-changing entry point so the adapter's configuration - /// never expires while it is actively used. - fn extend_instance(env: &Env) { - env.storage() - .instance() - .extend_ttl(INSTANCE_THRESHOLD, INSTANCE_BUMP); } -} // --------------------------------------------------------------------------- // Tests diff --git a/packages/contracts/defindex-adapter/src/lib.rs b/packages/contracts/defindex-adapter/src/lib.rs index d50aab24..08573cb1 100644 --- a/packages/contracts/defindex-adapter/src/lib.rs +++ b/packages/contracts/defindex-adapter/src/lib.rs @@ -1,7 +1,8 @@ #![no_std] use adapter_common::{ - get_usdc, require_not_initialized, require_vault_auth, store_vault_and_usdc, AdapterError, + extend_instance, get_usdc, require_not_initialized, require_vault_auth, + store_vault_and_usdc, AdapterError, }; use soroban_sdk::{ contract, contractclient, contracterror, contractimpl, panic_with_error, symbol_short, @@ -14,11 +15,6 @@ use soroban_sdk::{ const DFX_VAULT: Symbol = symbol_short!("DFXVAULT"); -// TTL bump targets. A "day" is ~17,280 ledgers at ~5 s/ledger. -const DAY_IN_LEDGERS: u32 = 17_280; -const INSTANCE_BUMP: u32 = 30 * DAY_IN_LEDGERS; -const INSTANCE_THRESHOLD: u32 = INSTANCE_BUMP - DAY_IN_LEDGERS; - // --------------------------------------------------------------------------- // DeFindex vault interface // --------------------------------------------------------------------------- @@ -142,7 +138,7 @@ impl MeridianDefindexAdapter { /// returns the dfToken shares received. pub fn deposit(env: Env, amount: i128) -> i128 { require_vault_auth(&env); - Self::extend_instance(&env); + extend_instance(&env); let dfx: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -175,7 +171,7 @@ impl MeridianDefindexAdapter { /// `recipient`. Returns the USDC amount received. pub fn withdraw(env: Env, shares: i128, recipient: Address) -> i128 { require_vault_auth(&env); - Self::extend_instance(&env); + extend_instance(&env); let dfx: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -201,7 +197,7 @@ impl MeridianDefindexAdapter { /// Live USDC value of the adapter's dfToken position, computed by the /// DeFindex vault's exchange rate. Updates automatically as yield accrues. pub fn total_assets(env: Env) -> i128 { - Self::extend_instance(&env); + extend_instance(&env); let dfx: Address = adapter_common::get_or_not_initialized::<_, ContractError>( &env, @@ -251,15 +247,7 @@ impl MeridianDefindexAdapter { Symbol::new(&env, "defindex") } - /// Extends the TTL of the contract instance. Called at the start of - /// every state-changing entry point so the adapter's configuration - /// never expires while it is actively used. - fn extend_instance(env: &Env) { - env.storage() - .instance() - .extend_ttl(INSTANCE_THRESHOLD, INSTANCE_BUMP); } -} // --------------------------------------------------------------------------- // Tests diff --git a/packages/contracts/vault/src/lib.rs b/packages/contracts/vault/src/lib.rs index 5b8e0239..e829892c 100644 --- a/packages/contracts/vault/src/lib.rs +++ b/packages/contracts/vault/src/lib.rs @@ -660,7 +660,6 @@ impl MeridianVault { /// used by dashboards, and "no position" is the truthful answer for a /// vault that holds nothing yet. pub fn get_position(env: Env, address: Address) -> i128 { - Self::extend_position(&env, &address); match Self::musdc(&env) { Ok(musdc) => TokenClient::new(&env, &musdc).balance(&address), Err(_) => 0,