Skip to content
Closed
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
36 changes: 36 additions & 0 deletions contracts/creditline-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,42 @@ impl CreditLineContract {

env.deployer().update_current_contract_wasm(new_wasm_hash);
events::emit_contract_upgraded(&env, old_version, new_version);

// Automatically execute migrate() during upgrade() by calling self.
// This spins up a new VM running the upgraded WASM hash.
env.invoke_contract::<()>(
&env.current_contract_address(),
&Symbol::new(&env, "migrate"),
(),
);
}

pub fn get_schema_version(env: Env) -> u32 {
storage::get_schema_version(&env)
}

pub fn migrate(env: Env) {
let admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err));
admin.require_auth();

let mut current_version = storage::get_schema_version(&env);
let target_version = 2;

if current_version >= target_version {
return;
}

if current_version == 0 {
// Version 0 -> 1 migration logic (idempotent & safe)
current_version = 1;
storage::set_schema_version(&env, current_version);
}

if current_version == 1 {
// Version 1 -> 2 migration logic (idempotent & safe)
current_version = 2;
storage::set_schema_version(&env, current_version);
}
}
pub fn get_admin(env: Env) -> Result<Address, CreditLineError> {
storage::get_admin(&env)
Expand Down
19 changes: 19 additions & 0 deletions contracts/creditline-contract/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,22 @@ pub fn get_version(env: &Env) -> Result<u32, CreditLineError> {
pub fn set_version(env: &Env, version: u32) {
env.storage().instance().set(&VERSION_KEY, &version);
}

pub const SCHEMA_VERSION_KEY: Symbol = symbol_short!("SCH_VER");

/// Get the contract schema version (persistent storage). Defaults to 0 when not set.
pub fn get_schema_version(env: &Env) -> u32 {
env.storage()
.persistent()
.get(&SCHEMA_VERSION_KEY)
.unwrap_or(0u32)
}

/// Set the contract schema version in persistent storage.
pub fn set_schema_version(env: &Env, version: u32) {
env.storage().persistent().set(&SCHEMA_VERSION_KEY, &version);
env.storage()
.persistent()
.extend_ttl(&SCHEMA_VERSION_KEY, PERSISTENT_TTL_THRESHOLD, PERSISTENT_TTL_EXTEND_TO);
}

37 changes: 37 additions & 0 deletions contracts/creditline-contract/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3125,3 +3125,40 @@ fn test_safe_math_boundaries() {
assert_eq!(safe_math::mul_i128(max, 2), Err(CreditLineError::Overflow));
assert_eq!(safe_math::div_i128(max, 0), Err(CreditLineError::Overflow));
}

#[test]
fn test_schema_version_and_migration() {
let env = Env::default();
env.mock_all_auths();

let contract_id = env.register(CreditLineContract, ());
let client = CreditLineContractClient::new(&env, &contract_id);

let admin = Address::generate(&env);
let reputation_contract = Address::generate(&env);
let vendor_registry = Address::generate(&env);
let liquidity_pool = Address::generate(&env);
let token = Address::generate(&env);

client.initialize(
&admin,
&reputation_contract,
&vendor_registry,
&liquidity_pool,
&token,
);

// Default version should be 0
assert_eq!(client.get_schema_version(), 0);

// Call migrate() directly
client.migrate();

// After migration, version should be 2
assert_eq!(client.get_schema_version(), 2);

// Call migrate() again (idempotent check)
client.migrate();
assert_eq!(client.get_schema_version(), 2);
}

38 changes: 37 additions & 1 deletion contracts/liquidity-pool-contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![no_std]
use soroban_sdk::{contract, contractimpl, panic_with_error, token, Address, Env};
use soroban_sdk::{contract, contractimpl, panic_with_error, token, Address, Env, Symbol};

mod errors;
mod events;
Expand Down Expand Up @@ -83,6 +83,14 @@ impl LiquidityPoolContract {

env.deployer().update_current_contract_wasm(new_wasm_hash);
events::emit_contract_upgraded(&env, old_version, new_version);

// Automatically execute migrate() during upgrade() by calling self.
// This spins up a new VM running the upgraded WASM hash.
env.invoke_contract::<()>(
&env.current_contract_address(),
&Symbol::new(&env, "migrate"),
(),
);
}
pub fn get_admin(env: Env) -> Result<Address, LiquidityPoolError> {
storage::get_admin(&env)
Expand All @@ -92,6 +100,34 @@ impl LiquidityPoolContract {
storage::get_version(&env).unwrap_or_else(|err| panic_with_error!(&env, err))
}

pub fn get_schema_version(env: Env) -> u32 {
storage::get_schema_version(&env)
}

pub fn migrate(env: Env) {
let admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err));
admin.require_auth();

let mut current_version = storage::get_schema_version(&env);
let target_version = 2;

if current_version >= target_version {
return;
}

if current_version == 0 {
// Version 0 -> 1 migration logic (idempotent & safe)
current_version = 1;
storage::set_schema_version(&env, current_version);
}

if current_version == 1 {
// Version 1 -> 2 migration logic (idempotent & safe)
current_version = 2;
storage::set_schema_version(&env, current_version);
}
}

// -------------------------------------------------------------------------
// LP Operations
// -------------------------------------------------------------------------
Expand Down
19 changes: 19 additions & 0 deletions contracts/liquidity-pool-contract/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,22 @@ pub fn get_version(env: &Env) -> Result<u32, LiquidityPoolError> {
pub fn set_version(env: &Env, v: u32) {
env.storage().instance().set(&VERSION_KEY, &v);
}

pub const SCHEMA_VERSION_KEY: Symbol = symbol_short!("SCH_VER");

/// Get the contract schema version (persistent storage). Defaults to 0 when not set.
pub fn get_schema_version(env: &Env) -> u32 {
env.storage()
.persistent()
.get(&SCHEMA_VERSION_KEY)
.unwrap_or(0u32)
}

/// Set the contract schema version in persistent storage.
pub fn set_schema_version(env: &Env, version: u32) {
env.storage().persistent().set(&SCHEMA_VERSION_KEY, &version);
env.storage()
.persistent()
.extend_ttl(&SCHEMA_VERSION_KEY, PERSISTENT_TTL_THRESHOLD, PERSISTENT_TTL_EXTEND_TO);
}

30 changes: 30 additions & 0 deletions contracts/liquidity-pool-contract/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2417,3 +2417,33 @@ fn test_loan_funding_and_guarantee_recovery_cycle() {
assert_eq!(stats_final.locked_liquidity, 2_500);
assert_eq!(stats_final.available_liquidity, 3_000);
}

#[test]
fn test_schema_version_and_migration() {
let env = Env::default();
env.mock_all_auths();

let contract_id = env.register(LiquidityPoolContract, ());
let client = LiquidityPoolContractClient::new(&env, &contract_id);

let admin = Address::generate(&env);
let token = Address::generate(&env);
let treasury = Address::generate(&env);
let merchant_fund = Address::generate(&env);

client.initialize(&admin, &token, &treasury, &merchant_fund);

// Default version should be 0
assert_eq!(client.get_schema_version(), 0);

// Call migrate() directly
client.migrate();

// After migration, version should be 2
assert_eq!(client.get_schema_version(), 2);

// Call migrate() again (idempotent check)
client.migrate();
assert_eq!(client.get_schema_version(), 2);
}

39 changes: 38 additions & 1 deletion contracts/parameters-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod types;
pub use errors::ParametersError;
pub use types::{default_parameters, ProtocolParameters};

use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Env};
use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Env, Symbol};

#[contract]
pub struct ParametersContract;
Expand Down Expand Up @@ -45,6 +45,15 @@ impl ParametersContract {

env.deployer().update_current_contract_wasm(new_wasm_hash);
events::emit_contract_upgraded(&env, old, new);

// Automatically execute migrate() during upgrade() by calling self.
// This spins up a new VM running the upgraded WASM hash.
env.invoke_contract::<()>(
&env.current_contract_address(),
&Symbol::new(&env, "migrate"),
(),
);

Self::exit_non_reentrant(&env);
}
pub fn get_admin(env: Env) -> Result<Address, ParametersError> {
Expand All @@ -55,6 +64,34 @@ impl ParametersContract {
storage::get_version(&env).unwrap_or_else(|err| panic_with_error!(&env, err))
}

pub fn get_schema_version(env: Env) -> u32 {
storage::get_schema_version(&env)
}

pub fn migrate(env: Env) {
let admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err));
admin.require_auth();

let mut current_version = storage::get_schema_version(&env);
let target_version = 2;

if current_version >= target_version {
return;
}

if current_version == 0 {
// Version 0 -> 1 migration logic (idempotent & safe)
current_version = 1;
storage::set_schema_version(&env, current_version);
}

if current_version == 1 {
// Version 1 -> 2 migration logic (idempotent & safe)
current_version = 2;
storage::set_schema_version(&env, current_version);
}
}

pub fn set_admin(env: Env, new_admin: Address) {
let old_admin = storage::get_admin(&env).unwrap_or_else(|err| panic_with_error!(&env, err));
old_admin.require_auth();
Expand Down
21 changes: 21 additions & 0 deletions contracts/parameters-contract/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,24 @@ pub fn get_version(env: &Env) -> Result<u32, ParametersError> {
pub fn set_version(env: &Env, v: u32) {
env.storage().instance().set(&VERSION_KEY, &v);
}

pub const SCHEMA_VERSION_KEY: Symbol = symbol_short!("SCH_VER");
pub const PERSISTENT_TTL_THRESHOLD: u32 = 1_036_800;
pub const PERSISTENT_TTL_EXTEND_TO: u32 = 2_073_600;

/// Get the contract schema version (persistent storage). Defaults to 0 when not set.
pub fn get_schema_version(env: &Env) -> u32 {
env.storage()
.persistent()
.get(&SCHEMA_VERSION_KEY)
.unwrap_or(0u32)
}

/// Set the contract schema version in persistent storage.
pub fn set_schema_version(env: &Env, version: u32) {
env.storage().persistent().set(&SCHEMA_VERSION_KEY, &version);
env.storage()
.persistent()
.extend_ttl(&SCHEMA_VERSION_KEY, PERSISTENT_TTL_THRESHOLD, PERSISTENT_TTL_EXTEND_TO);
}

20 changes: 20 additions & 0 deletions contracts/parameters-contract/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,23 @@ fn test_admin_upgrade_increments_version() {
}
assert!(found, "CONTRACTUPGRADED event not found");
}

#[test]
fn test_schema_version_and_migration() {
let (env, client, admin) = setup();
client.initialize_defaults(&admin);

// Default version should be 0
assert_eq!(client.get_schema_version(), 0);

// Call migrate() directly
client.migrate();

// After migration, version should be 2
assert_eq!(client.get_schema_version(), 2);

// Call migrate() again (idempotent check)
client.migrate();
assert_eq!(client.get_schema_version(), 2);
}

39 changes: 38 additions & 1 deletion contracts/reputation-contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![no_std]
use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env};
use soroban_sdk::{contract, contractimpl, symbol_short, Address, Env, Symbol};

// Module imports
mod access;
Expand Down Expand Up @@ -220,12 +220,49 @@ impl ReputationContract {
storage::set_version(&env, new);
env.deployer().update_current_contract_wasm(new_wasm_hash);
events::emit_contract_upgraded(&env, old, new);

// Automatically execute migrate() during upgrade() by calling self.
// This spins up a new VM running the upgraded WASM hash.
env.invoke_contract::<()>(
&env.current_contract_address(),
&Symbol::new(&env, "migrate"),
(),
);

Self::exit_non_reentrant(&env);
}
pub fn get_admin(env: Env) -> Result<Address, ReputationError> {
storage::get_admin(&env)
}

pub fn get_schema_version(env: Env) -> u32 {
storage::get_schema_version(&env)
}

pub fn migrate(env: Env) {
let admin = storage::get_admin(&env).unwrap_or_else(|err| soroban_sdk::panic_with_error!(&env, err));
admin.require_auth();

let mut current_version = storage::get_schema_version(&env);
let target_version = 2;

if current_version >= target_version {
return;
}

if current_version == 0 {
// Version 0 -> 1 migration logic (idempotent & safe)
current_version = 1;
storage::set_schema_version(&env, current_version);
}

if current_version == 1 {
// Version 1 -> 2 migration logic (idempotent & safe)
current_version = 2;
storage::set_schema_version(&env, current_version);
}
}

fn enter_non_reentrant(env: &Env) {
if storage::is_reentrancy_locked(env)
.unwrap_or_else(|err| soroban_sdk::panic_with_error!(env, err))
Expand Down
Loading
Loading