Skip to content
Open
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
2 changes: 1 addition & 1 deletion contracts/invoice-escrow/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,4 @@ pub enum Error {
InsufficientRepayment = 44,
/// New funding deadline must be greater than the current deadline.
DeadlineNotExtended = 45,
}
}
2 changes: 1 addition & 1 deletion contracts/invoice-escrow/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,4 @@ pub fn settlement_paid(
(Symbol::new(env, "settlement_paid"),),
(investor.clone(), invoice_id.clone(), payout_amount, yield_earned),
);
}
}
19 changes: 17 additions & 2 deletions contracts/invoice-escrow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,24 @@ impl InvoiceEscrow {
paused: false,
whitelist_enabled: false,
min_investment: 0,
grace_period_seconds: 0,
};
storage::set_config(&env, &config);
Ok(())
}

/// Admin-only: set the grace period window for overdue invoice settlement.
pub fn set_grace_period(env: Env, admin: Address, grace_period_seconds: u64) -> Result<(), Error> {
admin.require_auth();
let mut config = storage::get_config(&env).ok_or(Error::NotInit)?;
if config.admin != admin {
return Err(Error::Unauthorized);
}
config.grace_period_seconds = grace_period_seconds;
storage::set_config(&env, &config);
Ok(())
}

/// Admin-only: set the minimum investment amount for `fund_escrow`.
/// Pass `0` to disable the floor (deposits must still be strictly positive).
pub fn set_min_investment(env: Env, admin: Address, min_investment: i128) -> Result<(), Error> {
Expand Down Expand Up @@ -734,8 +747,9 @@ impl InvoiceEscrow {
return Err(Error::RefundNotAllowed);
}
let ledger_ts = env.ledger().timestamp();
if ledger_ts < data.due_dt {
return Err(Error::RefundNotAllowed);
let final_deadline = data.due_dt.checked_add(config.grace_period_seconds).unwrap_or(u64::MAX);
if ledger_ts <= final_deadline {
return Err(Error::EscrowNotOverdue);
}

// Refund the remaining collateral (purchase_price minus already released partial payments)
Expand Down Expand Up @@ -805,6 +819,7 @@ impl InvoiceEscrow {
soroban_sdk::vec![&env, contract.to_val(), false.into_val(&env)],
);

events::grace_period_expired(&env, invoice_id.clone());
events::escrow_refunded(&env, invoice_id.clone(), amount_to_refund);
events::escrow_status_changed(
&env,
Expand Down
2 changes: 2 additions & 0 deletions contracts/invoice-escrow/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub struct Config {
/// `0` disables the floor (only `amount > 0` is required). Completing the
/// remaining capacity below this floor is always allowed.
pub min_investment: i128,
/// Grace period in seconds for overdue invoice settlement.
pub grace_period_seconds: u64,
}

/// Lifecycle status of an escrow.
Expand Down