mod storage;
#[cfg(test)]
mod test;
use soroban_sdk::{
contracterror, contractevent, contracttrait, Address, BytesN, Env, Symbol, Val, Vec,
};
pub use crate::timelock::storage::{
cancel_operation, execute_operation, get_min_delay, get_operation_ledger, get_operation_state,
hash_operation, is_operation_done, is_operation_pending, is_operation_ready, operation_exists,
schedule_operation, set_execute_operation, set_min_delay, Operation, OperationState,
TimelockStorageKey,
};
#[contracttrait]
pub trait Timelock {
fn get_min_delay(e: &Env) -> u32 {
storage::get_min_delay(e)
}
fn hash_operation(
e: &Env,
target: Address,
function: Symbol,
args: Vec<Val>,
predecessor: BytesN<32>,
salt: BytesN<32>,
) -> BytesN<32> {
let operation = Operation { target, function, args, predecessor, salt };
storage::hash_operation(e, &operation)
}
fn get_operation_ledger(e: &Env, operation_id: BytesN<32>) -> u32 {
storage::get_operation_ledger(e, &operation_id)
}
fn get_operation_state(e: &Env, operation_id: BytesN<32>) -> OperationState {
storage::get_operation_state(e, &operation_id)
}
#[allow(clippy::too_many_arguments)]
fn schedule(
e: &Env,
target: Address,
function: Symbol,
args: Vec<Val>,
predecessor: BytesN<32>,
salt: BytesN<32>,
delay: u32,
proposer: Address,
) -> BytesN<32>;
fn execute(
e: &Env,
target: Address,
function: Symbol,
args: Vec<Val>,
predecessor: BytesN<32>,
salt: BytesN<32>,
executor: Option<Address>,
) -> Val;
fn cancel(e: &Env, operation_id: BytesN<32>, canceller: Address);
fn update_delay(e: &Env, new_delay: u32, operator: Address);
}
#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[repr(u32)]
pub enum TimelockError {
OperationAlreadyScheduled = 4000,
InsufficientDelay = 4001,
InvalidOperationState = 4002,
UnexecutedPredecessor = 4003,
Unauthorized = 4004,
MinDelayNotSet = 4005,
OperationNotScheduled = 4006,
}
const DAY_IN_LEDGERS: u32 = 17280;
pub const TIMELOCK_EXTEND_AMOUNT: u32 = 30 * DAY_IN_LEDGERS;
pub const TIMELOCK_TTL_THRESHOLD: u32 = TIMELOCK_EXTEND_AMOUNT - DAY_IN_LEDGERS;
pub const UNSET_LEDGER: u32 = 0;
pub const DONE_LEDGER: u32 = 1;
#[contractevent]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MinDelayChanged {
pub old_delay: u32,
pub new_delay: u32,
}
pub fn emit_min_delay_changed(e: &Env, old_delay: u32, new_delay: u32) {
MinDelayChanged { old_delay, new_delay }.publish(e);
}
#[contractevent]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OperationScheduled {
#[topic]
pub id: BytesN<32>,
#[topic]
pub target: Address,
pub function: Symbol,
pub args: Vec<Val>,
pub predecessor: BytesN<32>,
pub salt: BytesN<32>,
pub delay: u32,
}
#[allow(clippy::too_many_arguments)]
pub fn emit_operation_scheduled(
e: &Env,
id: &BytesN<32>,
target: &Address,
function: &Symbol,
args: &Vec<Val>,
predecessor: &BytesN<32>,
salt: &BytesN<32>,
delay: u32,
) {
OperationScheduled {
id: id.clone(),
target: target.clone(),
function: function.clone(),
args: args.clone(),
predecessor: predecessor.clone(),
salt: salt.clone(),
delay,
}
.publish(e);
}
#[contractevent]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OperationExecuted {
#[topic]
pub id: BytesN<32>,
#[topic]
pub target: Address,
pub function: Symbol,
pub args: Vec<Val>,
pub predecessor: BytesN<32>,
pub salt: BytesN<32>,
}
pub fn emit_operation_executed(
e: &Env,
id: &BytesN<32>,
target: &Address,
function: &Symbol,
args: &Vec<Val>,
predecessor: &BytesN<32>,
salt: &BytesN<32>,
) {
OperationExecuted {
id: id.clone(),
target: target.clone(),
function: function.clone(),
args: args.clone(),
predecessor: predecessor.clone(),
salt: salt.clone(),
}
.publish(e);
}
#[contractevent]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OperationCancelled {
#[topic]
pub id: BytesN<32>,
}
pub fn emit_operation_cancelled(e: &Env, id: &BytesN<32>) {
OperationCancelled { id: id.clone() }.publish(e);
}