feat(redemption-controller): implement initialize and update functions for redemption rate feedback controller

- Added `initialize_redemption_controller` and `update_redemption_controller` functions to manage redemption rate feedback.
- Introduced `RedemptionController` struct to maintain state for redemption rates.
- Updated `Cargo.toml` and `Cargo.lock` to include `twap_oracle_core` dependency.
- Modified integration tests to cover new redemption controller functionality.
This commit is contained in:
Ricardo Guilherme Schmidt
2026-07-03 09:42:45 -03:00
parent 4a6192d84f
commit d2f3e1d8fb
9 changed files with 1032 additions and 4 deletions
+1
View File
@@ -2712,6 +2712,7 @@ dependencies = [
"lee_core",
"stablecoin_core",
"token_core",
"twap_oracle_core",
]
[[package]]
@@ -1,8 +1,7 @@
#![cfg_attr(not(test), no_main)]
use nssa_core::account::AccountWithMetadata;
use spel_framework::context::ProgramContext;
use spel_framework::prelude::*;
use nssa_core::account::{AccountId, AccountWithMetadata};
use spel_framework::{context::ProgramContext, prelude::*};
#[cfg(not(test))]
risc0_zkvm::guest::entry!(main);
@@ -114,4 +113,80 @@ mod stablecoin {
chained_calls,
))
}
/// Initialize redemption-rate feedback controller state for one stablecoin/feed pair.
///
/// # Errors
/// Returns the host program's panic-converted error if any precondition
/// fails (see
/// [`stablecoin_program::redemption_controller::initialize_redemption_controller`]
/// for the full list).
#[expect(
clippy::too_many_arguments,
reason = "instruction interface exposes controller configuration explicitly"
)]
#[instruction]
pub fn initialize_redemption_controller(
ctx: ProgramContext,
controller: AccountWithMetadata,
stablecoin_definition: AccountWithMetadata,
price_feed: AccountWithMetadata,
reference_asset_id: AccountId,
initial_redemption_price: u128,
proportional_gain: u128,
integral_gain: u128,
max_integral_error: u128,
max_redemption_rate: u128,
max_price_feed_age: u64,
current_timestamp: u64,
) -> SpelResult {
let post_states =
stablecoin_program::redemption_controller::initialize_redemption_controller(
controller,
stablecoin_definition,
price_feed,
ctx.self_program_id,
reference_asset_id,
initial_redemption_price,
proportional_gain,
integral_gain,
max_integral_error,
max_redemption_rate,
max_price_feed_age,
current_timestamp,
);
let validity_end = current_timestamp
.checked_add(1)
.expect("current_timestamp must allow an exact validity window");
Ok(spel_framework::SpelOutput::execute(post_states, vec![])
.try_with_timestamp_validity_window(current_timestamp..validity_end)
.expect("exact timestamp validity window must be non-empty"))
}
/// Update redemption price and redemption rate from the configured price feed.
///
/// # Errors
/// Returns the host program's panic-converted error if controller state
/// validation fails. Stale or unavailable price feeds pause updates by
/// emitting the controller state unchanged.
#[instruction]
pub fn update_redemption_controller(
ctx: ProgramContext,
controller: AccountWithMetadata,
price_feed: AccountWithMetadata,
current_timestamp: u64,
) -> SpelResult {
let post_states = stablecoin_program::redemption_controller::update_redemption_controller(
controller,
price_feed,
ctx.self_program_id,
current_timestamp,
);
let validity_end = current_timestamp
.checked_add(1)
.expect("current_timestamp must allow an exact validity window");
Ok(spel_framework::SpelOutput::execute(post_states, vec![])
.try_with_timestamp_validity_window(current_timestamp..validity_end)
.expect("exact timestamp validity window must be non-empty"))
}
}