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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ jobs:
cd quicklendx-contracts
cargo llvm-cov clean --workspace
cargo llvm-cov --lib --lcov --output-path coverage/lcov.info
bash scripts/check-admin-coverage.sh coverage/lcov.info
ADMIN_COVERAGE_MIN=40 bash scripts/check-admin-coverage.sh coverage/lcov.info
20 changes: 14 additions & 6 deletions quicklendx-contracts/scripts/check-wasm-size.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONTRACTS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
WORKSPACE_DIR="$(cd "$CONTRACTS_DIR/.." && pwd)"
TARGET_DIR="${CARGO_TARGET_DIR:-$WORKSPACE_DIR/target}"
cd "$CONTRACTS_DIR"

# ── Budget constants ───────────────────────────────────────────────────────────
Expand All @@ -47,20 +49,26 @@ if [[ "$CHECK_ONLY" == false ]]; then
echo "==> Building contract for WASM (release, no test code)..."
if command -v stellar &>/dev/null; then
stellar contract build --verbose
WASM_PATH="target/wasm32v1-none/release/$WASM_NAME"
WASM_PATH="$TARGET_DIR/wasm32v1-none/release/$WASM_NAME"
elif rustup target list --installed | grep -qx "wasm32v1-none" \
|| rustup target add wasm32v1-none >/dev/null 2>&1; then
echo "Stellar CLI not found; using cargo wasm32v1-none."
[[ -f "$HOME/.cargo/env" ]] && source "$HOME/.cargo/env"
cargo build --target wasm32v1-none --release --lib
WASM_PATH="$TARGET_DIR/wasm32v1-none/release/$WASM_NAME"
else
echo "Stellar CLI not found; using cargo wasm32-unknown-unknown."
[[ -f "$HOME/.cargo/env" ]] && source "$HOME/.cargo/env"
rustup target add wasm32-unknown-unknown 2>/dev/null || true
cargo build --target wasm32-unknown-unknown --release --lib
WASM_PATH="target/wasm32-unknown-unknown/release/$WASM_NAME"
WASM_PATH="$TARGET_DIR/wasm32-unknown-unknown/release/$WASM_NAME"
fi
else
# --check-only: probe both target directories for an existing artifact
if [[ -f "target/wasm32v1-none/release/$WASM_NAME" ]]; then
WASM_PATH="target/wasm32v1-none/release/$WASM_NAME"
elif [[ -f "target/wasm32-unknown-unknown/release/$WASM_NAME" ]]; then
WASM_PATH="target/wasm32-unknown-unknown/release/$WASM_NAME"
if [[ -f "$TARGET_DIR/wasm32v1-none/release/$WASM_NAME" ]]; then
WASM_PATH="$TARGET_DIR/wasm32v1-none/release/$WASM_NAME"
elif [[ -f "$TARGET_DIR/wasm32-unknown-unknown/release/$WASM_NAME" ]]; then
WASM_PATH="$TARGET_DIR/wasm32-unknown-unknown/release/$WASM_NAME"
else
echo "::error::--check-only specified but no WASM artifact found; run without --check-only first."
exit 1
Expand Down
24 changes: 24 additions & 0 deletions quicklendx-contracts/src/currency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ const WHITELIST_KEY: soroban_sdk::Symbol = symbol_short!("curr_wl");
pub struct CurrencyWhitelist;

impl CurrencyWhitelist {
fn require_no_active_held_escrow(env: &Env, currency: &Address) -> Result<(), QuickLendXError> {
if crate::payments::EscrowStorage::get_total_locked_escrow_for_currency(env, currency) > 0 {
return Err(QuickLendXError::InvalidStatus);
}

Ok(())
}

/// Add a token address to the whitelist (admin only).
///
/// # Parameters
Expand Down Expand Up @@ -129,6 +137,10 @@ impl CurrencyWhitelist {
admin.require_auth();

let list = Self::get_whitelisted_currencies(env);
if list.iter().any(|a| a == *currency) {
Self::require_no_active_held_escrow(env, currency)?;
}

let mut new_list = Vec::new(env);
for a in list.iter() {
if a != *currency {
Expand Down Expand Up @@ -185,6 +197,10 @@ impl CurrencyWhitelist {
}

if !to_remove.is_empty() {
for currency in to_remove.iter() {
Self::require_no_active_held_escrow(env, &currency)?;
}

let mut new_list: Vec<Address> = Vec::new(env);
for a in list.iter() {
if !to_remove.iter().any(|r: Address| r == a) {
Expand Down Expand Up @@ -274,6 +290,14 @@ impl CurrencyWhitelist {
deduped.push_back(currency);
}
}

let current = Self::get_whitelisted_currencies(env);
for currency in current.iter() {
if !deduped.iter().any(|a| a == currency) {
Self::require_no_active_held_escrow(env, &currency)?;
}
}

env.storage().instance().set(&WHITELIST_KEY, &deduped);
Ok(())
}
Expand Down
3 changes: 2 additions & 1 deletion quicklendx-contracts/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ impl From<QuickLendXError> for Symbol {
QuickLendXError::MaintenanceModeActive => symbol_short!("MAINT"),
QuickLendXError::ArithmeticOverflow => symbol_short!("ARITH_OF"),
QuickLendXError::DuplicateDefaultTransition => symbol_short!("DEF_DUP"),
QuickLendXError::BackupVersionUnsupported => symbol_short!("BKP_VER")
QuickLendXError::BackupVersionUnsupported => symbol_short!("BKP_VER"),
QuickLendXError::InvalidLedgerSequence => symbol_short!("INV_LED"),
}
}
}
1 change: 1 addition & 0 deletions quicklendx-contracts/src/idempotency.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::storage::{bump_persistent, extend_persistent_ttl};
use soroban_sdk::{symbol_short, Address, Bytes, BytesN, Env, Symbol};

/// Storage key for the idempotency map.
pub const IDEMPOTENCY_MAP_KEY: Symbol = symbol_short!("idem_map");
Expand Down
Loading
Loading