This document describes the public interface for the StellarKraal Soroban smart contract in contracts/stellarkraal/src/lib.rs.
It covers contract functions, parameters, return values, error codes, on-chain state changes, and invocation examples using stellar-cli.
See also: DataKey Enum Reference β storage key documentation generated from rustdoc comments.
The contract manages livestock-backed loans with the following responsibilities:
- Register livestock as collateral.
- Accept loan requests against collateral value.
- Process loan repayments and liquidations.
- Enforce admin-controlled protocol parameters (fees, pause state, oracle configuration).
- Validate recipient-price updates from an external oracle and maintain TWAP pricing data.
- Description: Set initial protocol parameters and default fee, treasury, loan, and price state.
- Parameters:
adminβ admin address with permission to update protocol settings. Must not be the all-zeros Stellar account.oracleβ authorized oracle address for price submissions.tokenβ token address used for SAC disbursements and repayments.treasuryβ fee recipient address.ltv_bpsβ loan-to-value ratio in basis points (e.g.6000= 60%). Must be in the range 1β9000 inclusive.liquidation_threshold_bpsβ liquidation health threshold in basis points. Must be β₯ltv_bps.
- Returns:
Result<(), Error>. - State changes: stores admin, oracle, token, treasury, LTV, liquidation threshold, fee rates, close factor, interest rate model, liquidity tracking, TWAP defaults, and oracle validation parameters.
- Errors:
AlreadyInitialized(#2) if called more than once.Unauthorized(#3) ifadminis the all-zeros account (GAAAβ¦WHF).InvalidAmount(#8) ifltv_bpsis 0 or > 9000, or ifliquidation_threshold_bps<ltv_bps.
- Description: Query whether the contract is currently paused.
- Parameters: none.
- Returns:
bool. - State changes: none.
- Description: Pause contract write operations until expiry.
- Parameters:
adminβ must match the stored admin address. - Returns:
Result<(), Error>. - State changes: sets pause flag and expiry timestamp, emits a pause event.
- Description: Resume contract operations.
- Parameters:
adminβ must match the stored admin address. - Returns:
Result<(), Error>. - State changes: clears pause state and expiry timestamp, emits an unpause event.
- Description: Update the default pause duration used by
pause(). - Parameters:
adminβ admin address.durationβ duration in seconds.
- Returns:
Result<(), Error>. - State changes: updates
PAUSE_DUR.
- Description: Update the authorized oracle address.
- Parameters:
adminβ admin address.new_oracleβ new oracle address.
- Returns:
Result<(), Error>. - State changes: updates
ORACLE, emits an oracle update event.
- Description: Set the maximum accepted appraised value for a livestock type.
- Parameters:
adminβ admin address.animal_typeβ short symbol for livestock type.max_valueβ maximum accepted appraised value in base units.
- Returns:
Result<(), Error>. - State changes: stores the cap for
animal_type, emits an admin cap update event. - Compatibility: animal types without a configured cap behave as if the cap is
u128::MAX, so existing deployments remain unrestricted until the admin sets a cap.
- Description: Return the current liquidation threshold in basis points. This is a read-only query β no authentication required.
- Parameters: none.
- Returns:
Result<u32, Error>β the currentLIQ_THRvalue (e.g.8000= 80%). - State changes: none.
- Errors:
NotInitializedif the contract has not been initialized.
- Description: Update the liquidation threshold.
- Parameters:
adminβ admin address.threshold_bpsβ new threshold in basis points.
- Returns:
Result<(), Error>. - State changes: updates
LIQ_THR, emits a threshold update event.
- Description: Start admin transfer by proposing a new admin address.
- Parameters:
adminβ current admin address.new_adminβ proposed admin address.
- Returns:
Result<(), Error>. - State changes: stores
PENDING_ADMIN, emits a proposal event.
- Description: Accept admin role after it has been proposed.
- Parameters:
new_adminβ address that must match the pending admin. - Returns:
Result<(), Error>. - State changes: replaces
ADMINwithPENDING_ADMIN, clearsPENDING_ADMIN, emits an admin update event.
- Description: Register a new collateral record for livestock.
- Parameters:
ownerβ collateral owner address.animal_typeβ short symbol for livestock type.countβ number of animals.appraised_valueβ oracle-appraised collateral value in base units.
- Returns:
Result<u64, Error>β newly assigned collateral ID. - State changes: creates
CollateralRecordand stores it as unlocked collateral, emits a livestock registration event.
- Description: Request a new loan secured by one or more collateral records.
- Parameters:
borrowerβ borrower address.collateral_idsβ list of collateral record IDs.amountβ requested gross loan amount in token base units.loan_duration_ledgersβ optional duration in seconds from now. When provided the storeddue_ledgeris set tonow + loan_duration_ledgers. PassNonefor open-ended loans with no repayment deadline.
- Returns:
Result<u64, Error>β newly assigned loan ID. - State changes: validates collateral ownership, locks collaterals, stores
LoanRecord(with optionaldue_ledger), transfers origination fee to treasury, disburses net amount to borrower, emits loan requested event.amountβ requested gross loan amount in token base units (stroops). Must satisfyMIN_LOAN β€ amount β€ MAX_LOAN.
- Returns:
Result<u64, Error>β newly assigned loan ID. - State changes: validates collateral ownership, locks collaterals, stores
LoanRecord, transfers origination fee to treasury, disburses net amount to borrower, emits loan requested event. - Errors:
InvalidAmount(#8) ifamount β€ 0,amount < MIN_LOAN, oramount > MAX_LOAN.InsufficientCollateral(#4) ifamount > total_collateral_value Γ LTV / 10000.CollateralNotFound(#6) ifcollateral_idsis empty or contains an unknown ID.Unauthorized(#3) if any collateral is owned by a different address.
| Constant | Default value | XLM equivalent | Storage key |
|---|---|---|---|
DEFAULT_MIN_LOAN |
10_000_000 stroops |
1 XLM | MIN_LOAN (instance) |
DEFAULT_MAX_LOAN |
1_000_000_000_000 stroops |
100,000 XLM | MAX_LOAN (instance) |
Both limits are configurable at runtime by the admin via set_loan_limits(admin, min_loan, max_loan).
- Description: Repay part or all of an active loan.
- Parameters:
borrowerβ loan borrower address.loan_idβ loan identifier.amountβ repayment amount.
- Returns:
Result<(), Error>. - State changes: transfers repayment into contract, deducts interest fee to treasury, reduces outstanding balance, updates status to
Repaidwhen completed, emitsloan_repaidevent.
- Description: Liquidate a loan whose health factor is below 1.
- Parameters:
liquidatorβ liquidator address.loan_idβ loan identifier.repay_amountβ amount to repay subject to close-factor cap.
- Returns:
Result<(), Error>. - State changes: transfers repayment into contract, reduces outstanding balance, updates loan status to
Liquidatedif fully repaid, emits loan liquidated event. - Whitelist behaviour: when the liquidator whitelist is empty any address may call this function (backward-compatible open mode). When at least one address has been added via
add_liquidator, only whitelisted addresses are permitted; others receiveLiquidatorNotWhitelisted.
- Description: Add an address to the approved liquidator whitelist. Idempotent β adding the same address twice has no effect.
- Parameters:
adminβ must match the stored admin address.liquidatorβ address to approve as a liquidator.
- Returns:
Result<(), Error>. - State changes: stores a
WhitelistEntryin persistent storage, increments the whitelist count, emits awhitelist/addedevent.
- Description: Remove an address from the approved liquidator whitelist. Idempotent β removing an address that is not on the list is a no-op.
- Parameters:
adminβ must match the stored admin address.liquidatorβ address to remove from the whitelist.
- Returns:
Result<(), Error>. - State changes: removes the
WhitelistEntryfrom persistent storage, decrements the whitelist count, emits awhitelist/removedevent.
- Description: Query whether an address is permitted to liquidate. Returns
truewhen the whitelist is empty (open mode) or when the address has been added viaadd_liquidator. - Parameters:
liquidatorβ address to check.
- Returns:
bool. - State changes: none.
- Description: Update the maximum liquidation repayment percentage.
- Parameters:
adminβ admin address.close_factor_bpsβ close factor in basis points.
- Returns:
Result<(), Error>. - State changes: updates
CLOSE_FACTOR.
- Description: Read the current close factor.
- Parameters: none.
- Returns:
Result<u32, Error>. - State changes: none.
- Description: Compute the health factor scaled by 10,000 for a loan. Rejects with
Error::InvalidPriceif the latest oracle price is older than the configured staleness threshold (STALE_THR). Past-due loans (wheredue_ledgeris set and the current ledger timestamp exceeds it) return0regardless of collateral, making them immediately liquidatable. - Parameters:
loan_idβ loan identifier.
- Returns:
Result<i128, Error>. - State changes: none.
- Description: Read a loan record.
- Parameters:
loan_idβ loan identifier.
- Returns:
Result<LoanRecord, Error>. - State changes: none.
- Description: Read a collateral record.
- Parameters:
collateral_idβ collateral record identifier.
- Returns:
Result<CollateralRecord, Error>. - State changes: none.
- Description: Return all collateral records backing a loan.
- Parameters:
loan_idβ loan identifier.
- Returns:
Result<Vec<CollateralRecord>, Error>. - State changes: none.
- Description: Get the number of non-liquidated collaterals registered by an owner.
- Parameters:
ownerβ owner address.
- Returns:
u32β count of non-liquidated collaterals. Returns 0 if none. - State changes: none.
- Description: Get the number of active loans for a borrower.
- Parameters:
borrowerβ borrower address.
- Returns:
u32β count of active loans. Returns 0 if none. - State changes: none.
- Description: Update the price staleness threshold (in ledgers/seconds).
- Parameters:
adminβ admin address.thresholdβ staleness threshold in ledgers (default 3600).
- Returns:
Result<(), Error>. - State changes: updates
STALE_THR, emitsStaleThrevent.
- Description: Read the current price staleness threshold.
- Parameters: none.
- Returns:
u64. - State changes: none.
- Description: Update origination and interest fee rates.
- Parameters:
adminβ admin address.origination_fee_bpsβ origination fee in basis points.interest_fee_bpsβ interest fee in basis points.
- Returns:
Result<(), Error>. - State changes: updates
ORIG_FEEandINT_FEE.
- Description: Read the current fee configuration. This is a read-only query that does not modify contract state.
- Parameters: none.
- Returns:
Result<FeeConfig, Error>. - Return type fields:
origination_fee_bps: u32β origination fee in basis points (e.g. 50 = 0.5%). Deducted from loan disbursement at origination and sent to the treasury.interest_fee_bps: u32β interest fee in basis points (e.g. 1000 = 10%). Applied to the interest portion of repayments and sent to the treasury.
- State changes: none.
- Errors:
NotInitializedif the contract has not been initialized.
- Description: Emergency withdrawal of all token reserves held by the contract. Only callable by admin when the contract is paused.
- Parameters:
adminβ must match the stored admin address.recipientβ address to receive the withdrawn tokens.
- Returns:
Result<(), Error>. - State changes: transfers entire token balance to
recipient, emits anemergencyevent with the recipient address and withdrawn amount. - Errors:
NotInitializedif the contract has not been initialized.Unauthorizedif the caller is not admin.NotPausedif the contract is not currently paused.
- Description: Update the loan-to-value ratio used for new loan requests.
- Parameters:
adminβ must match the stored admin address.ltv_bpsβ new LTV in basis points. Must be between 1000 (10%) and 9000 (90%).
- Returns:
Result<(), Error>. - State changes: updates
LTV, emits an(Admin, LtvUpd)event with old and new values. - Errors:
NotInitializedif the contract has not been initialized.Unauthorizedif the caller is not admin.InvalidAmountifltv_bpsis outside the 1000β9000 range.
- Description: Return an admin-only operational summary of key contract state.
- Parameters:
adminβ admin address.
- Returns:
Result<ContractState, Error>. - State changes: none.
- Security: requires authorization from the stored admin address.
- Return type:
pub struct ContractState {
pub admin: Address,
pub token: Address,
pub ltv_bps: u32,
pub liq_threshold_bps: u32,
pub is_paused: bool,
pub oracle_count: u32,
pub total_loans: u64,
pub total_collaterals: u64,
}- Description: Update the jump-rate interest model.
- Parameters:
adminβ admin address.base_rate_bpsβ base interest rate in basis points.slope1_bpsβ slope below the kink.slope2_bpsβ slope above the kink.kink_bpsβ utilization kink point in basis points.
- Returns:
Result<(), Error>. - State changes: updates
BASE_RATE,SLOPE1,SLOPE2, andKINK.
- Description: Read the current interest rate model.
- Parameters: none.
- Returns:
Result<InterestRateModel, Error>. - State changes: none.
- Description: Compute the current interest rate from utilization.
- Parameters: none.
- Returns:
Result<u32, Error>. - State changes: none.
Oracle design: The protocol supports multiple registered oracles with on-chain median aggregation and a configurable quorum (
add_oracle,remove_oracle,get_oracles,submit_oracle_prices), in addition to the single-oraclesubmit_price+ TWAP path documented below. For the trust model, dispute handling, the relationship to the off-chain appraisal cache (backend/src/utils/appraisalCache.ts), and rationale, see ADR-006: Oracle design.
- Description: Return the current list of registered oracle addresses. If the multi-oracle
ORACLESstore has not been written yet (i.e. only the legacy singleORACLEkey exists), it falls back to returning a one-element Vec containing that address. - Parameters: none.
- Returns:
Vec<Address>β ordered list of registered oracle addresses (0β5 entries). - State changes: none.
- Example:
stellar contract invoke \ --id "$CONTRACT_ID" \ --fn get_oracles \ --network "$NETWORK" \ --rpc-url "$RPC_URL"
- Description: Register an additional oracle address. Maximum of 5 oracles allowed.
- Parameters:
adminβ must match the stored admin address.oracleβ oracle address to add.
- Returns:
Result<(), Error>. - State changes: appends address to
ORACLES, emits no event. - Errors:
Unauthorized(non-admin),OracleAlreadyRegistered(#16),OracleLimitReached(#17 when count β₯ 5).
- Description: Deregister an existing oracle address.
- Parameters:
adminβ must match the stored admin address.oracleβ oracle address to remove.
- Returns:
Result<(), Error>. - State changes: removes address from
ORACLES. - Errors:
Unauthorized(non-admin),OracleNotFound(#16 when address not present).
- Description: Submit a price vector (one price per registered oracle) and compute the on-chain median. Prices equal to zero are treated as non-responses. A minimum quorum of 3 responses is required when 3 or more oracles are registered; otherwise the quorum equals the oracle count.
- Parameters:
submitterβ any authenticated address.pricesβVec<i128>whose length must equal the number of registered oracles. A zero entry indicates that oracle did not respond.
- Returns:
Result<OracleReport, Error>whereOracleReportcontains:median: i128β median of non-zero prices after sorting.responses: u32β count of non-zero prices.flagged_count: u32β count of prices deviating >50% from the median.
- State changes: none (read-only aggregation; the caller decides how to use the result).
- Errors:
InvalidPrice(#18) ifprices.len() != oracles.len(),InsufficientOracleQuorum(#17) if non-zero responses < quorum.
- Description: Configure price bounds and freshness validation.
- Parameters:
adminβ admin address.price_minβ minimum accepted price (0 disables lower bound).price_maxβ maximum accepted price (0 disables upper bound).staleness_thresholdβ maximum age of a price update in seconds.max_deviation_bpsβ maximum allowable deviation from the last price.
- Returns:
Result<(), Error>. - State changes: updates oracle validation settings.
- Description: Read the current oracle validation settings.
- Parameters: none.
- Returns:
Result<OracleConfig, Error>. - State changes: none.
- Description: Submit a new oracle price with validation and TWAP tracking.
- Parameters:
oracleβ authorized oracle address.priceβ new price in base units.price_timestampβ timestamp associated with the price.
- Returns:
Result<(), Error>. - State changes: updates latest price, TWAP accumulators, and publish price state.
- Description: Read current TWAP pricing state.
- Parameters: none.
- Returns:
Result<TWAPData, Error>. - State changes: none.
- Description: Update the TWAP averaging window.
- Parameters:
adminβ admin address.window_secondsβ window length in seconds.
- Returns:
Result<(), Error>. - State changes: updates
TWAP_WINDOW.
| Code | Error | Meaning |
|---|---|---|
| 1 | NotInitialized |
Contract has not been initialized. |
| 2 | AlreadyInitialized |
initialize() already executed. |
| 3 | Unauthorized |
Caller is not authorized for the operation. |
| 4 | InsufficientCollateral |
Requested loan exceeds LTV-backed collateral. |
| 5 | LoanNotFound |
Loan ID does not exist. |
| 6 | CollateralNotFound |
Collateral ID does not exist. |
| 7 | HealthFactorSafe |
Loan health factor is healthy; liquidation not allowed. |
| 8 | InvalidAmount |
Numeric argument is zero, negative, or overflows. |
| 9 | LoanAlreadyClosed |
Loan is already repaid or liquidated. |
| 10 | InvalidFeeRate |
Fee rate exceeds protocol maximum. |
| 11 | ExceedsCloseFactor |
Liquidation repayment exceeds close factor cap. |
| 12 | InvalidCloseFactor |
Close factor is out of bounds. |
| 13 | ContractPaused |
Contract is paused and write operations are blocked. |
| 14 | AlreadyInProgress |
Reentrancy guard prevented nested execution. |
| 15 | NotPaused |
Attempted unpause while contract is not paused. |
| 16 | AlreadyPaused |
Attempted pause while contract is already paused. |
| 17 | PriceBelowMin |
Oracle price below configured minimum. |
| 18 | PriceAboveMax |
Oracle price above configured maximum. |
| 19 | PriceStale |
Submitted price is too old. |
| 20 | AlreadyInProgress |
Reentrancy guard prevented nested execution. |
| 21 | AlreadyPaused |
Contract is already paused. |
| 22 | ArithmeticOverflow |
Arithmetic overflow detected. |
| 23 | LiquidatorNotWhitelisted |
Caller is not on the approved liquidator whitelist. |
Key contract storage state used by the interface:
ADMIN,PENDING_ADMINβ admin authority and pending admin transfer.ORACLEβ authorized oracle address.AnimalCap(animal_type)β optional per-animal-type maximum appraised value.TOKEN,TREASURYβ token and treasury addresses.LTV,LIQ_THR,ORIG_FEE,INT_FEE,CLOSE_FACTORβ protocol parameters.PAUSED,PAUSE_EXP,PAUSE_DURβ pause control state.CollateralRecordandLoanRecordpersistent storage keyed by IDs.LoanRecordincludes an optionaldue_ledger: Option<u64>timestamp representing the repayment deadline.BASE_RATE,SLOPE1,SLOPE2,KINKβ interest rate model parameters.TOTAL_BORROWED,TOTAL_LIQUIDITYβ liquidity tracking state.LAST_PRICE,LAST_PRICE_TIME,TWAP_PRICE,TWAP_SUM,TWAP_COUNT,TWAP_WINDOWβ oracle price and TWAP state.PRICE_MIN,PRICE_MAX,STALE_THR,DEV_BPSβ oracle validation configuration.WL_COUNTβ instance storage count of whitelisted liquidators (0 = open mode).WhitelistEntry(Address)β persistent storage flag per approved liquidator address.
Examples assume a deployed contract ID and Soroban testnet environment.
Replace the placeholder G... addresses with real Stellar public keys.
export CONTRACT_ID=GCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM
export RPC_URL=https://soroban-testnet.stellar.org
export NETWORK=testnetSets up the protocol with a 60 % LTV, 80 % liquidation threshold, and minimum oracle quorum of 1.
stellar contract invoke \
--id "$CONTRACT_ID" \
--fn initialize \
--arg address:GADMIN000000000000000000000000000000000000000000000ADMIN \
--arg address:GORACLE000000000000000000000000000000000000000000ORACLE \
--arg address:GTOKEN000000000000000000000000000000000000000000TOKEN0 \
--arg address:GTREASURY0000000000000000000000000000000000000TREASURY \
--arg 6000 \
--arg 8000 \
--arg 1 \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GADMIN000000000000000000000000000000000000000000000ADMIN
# Expected output: null (unit return on success)
# Errors:
# #2 AlreadyInitialized β contract was already initialized.
# #3 Unauthorized β admin address is the all-zeros account.
# #8 InvalidAmount β ltv_bps out of range [1,9000] or liq_thr < ltv.stellar contract invoke \
--id "$CONTRACT_ID" \
--fn register_livestock \
--arg address:GOWNER000000000000000000000000000000000000000000000OWNER \
--arg cattle \
--arg 5 \
--arg 1000000 \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GOWNER000000000000000000000000000000000000000000000OWNER
# Expected output: 1 (newly assigned collateral ID)Request a loan against two collateral records with a 30-day repayment deadline
(30 days β 2 592 000 seconds). Pass null as the last argument for an open-ended
loan with no deadline.
stellar contract invoke \
--id "$CONTRACT_ID" \
--fn request_loan \
--arg address:GBORROWER000000000000000000000000000000000000000000000WL \
--arg "[1,2]" \
--arg 500000 \
--arg 2592000 \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GBORROWER000000000000000000000000000000000000000000000WL
# Expected output: 1 (the new loan ID)Open-ended loan (no deadline):
stellar contract invoke \
--id "$CONTRACT_ID" \
--fn request_loan \
--arg address:GBORROWER000000000000000000000000000000000000000000000WL \
--arg "[1,2]" \
--arg 500000 \
--arg null \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GBORROWER000000000000000000000000000000000000000000000WL
# Expected output: 2 (the new loan ID)stellar contract invoke \
--id "$CONTRACT_ID" \
--fn repay_loan \
--arg address:GBORROWER000000000000000000000000000000000000000000000WL \
--arg 1 \
--arg 200000 \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GBORROWER000000000000000000000000000000000000000000000WL
# Expected output: null (unit return on success)
# Repays 200 000 base-units toward loan #1; outstanding balance is reduced accordingly.Full repayment (loan status transitions to Repaid):
stellar contract invoke \
--id "$CONTRACT_ID" \
--fn repay_loan \
--arg address:GBORROWER000000000000000000000000000000000000000000000WL \
--arg 1 \
--arg 9999999999 \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GBORROWER000000000000000000000000000000000000000000000WL
# The contract caps repayment at the outstanding + accrued interest balance,
# so passing a very large amount is a safe way to fully close the loan.Liquidation is only possible when the health factor is below 10 000 (i.e. < 1.0).
The repay_amount must not exceed the close-factor cap (default 50 % of outstanding).
stellar contract invoke \
--id "$CONTRACT_ID" \
--fn liquidate \
--arg address:GLIQUIDATOR00000000000000000000000000000000000000000LQ \
--arg 1 \
--arg 250000 \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GLIQUIDATOR00000000000000000000000000000000000000000LQ
# Expected output: null (unit return on success)
# Errors:
# #7 HealthFactorSafe β loan is still healthy; not liquidatable.
# #11 ExceedsCloseFactor β repay_amount > close_factor * outstanding.
# #23 LiquidatorNotWhitelisted β caller is not on the liquidator whitelist.Returns the current LIQ_THR value in basis points. No authentication required.
stellar contract invoke \
--id "$CONTRACT_ID" \
--fn get_liquidation_threshold \
--network "$NETWORK" \
--rpc-url "$RPC_URL"
# Expected output: 8000 (80 % threshold after default initialization)stellar contract invoke \
--id "$CONTRACT_ID" \
--fn submit_price \
--arg address:GORACLE000000000000000000000000000000000000000000ORACLE \
--arg 125000 \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GORACLE000000000000000000000000000000000000000000ORACLE
# Expected output: null (unit return on success)stellar contract invoke \
--id "$CONTRACT_ID" \
--fn get_loan \
--arg 1 \
--network "$NETWORK" \
--rpc-url "$RPC_URL"
# Expected output (example):
# {
# "id": 1,
# "borrower": "GBORROWER...",
# "collateral_ids": [1, 2],
# "total_collateral_value": "1000000",
# "principal": "500000",
# "outstanding": "300000",
# "interest_accrued": "0",
# "last_interest_time": 1721836200,
# "status": "active",
# "due_ledger": 1724428200
# }stellar contract invoke \
--id "$CONTRACT_ID" \
--fn transfer_collateral \
--arg address:GOWNER000000000000000000000000000000000000000000000OWNER \
--arg 1 \
--arg address:GNEWOWNER0000000000000000000000000000000000000000NEWOWN \
--network "$NETWORK" \
--rpc-url "$RPC_URL" \
--source GOWNER000000000000000000000000000000000000000000000OWNER
# Expected output: null (unit return on success)- The contract uses
submit_priceto validate oracle updates before they affect TWAP state. - Repayments are allowed even when the contract is paused, while new loans and liquidations are blocked.
- Liquidations are only permitted when
health_factoris below 10,000 and the repay amount does not exceedCLOSE_FACTOR.
Soroban persistent storage entries expire after a configurable number of ledgers. Loan and collateral records are long-lived (active for the duration of a loan, potentially months), so every write to a Loan or Collateral entry is followed by an extend_ttl call.
| Constant | Value | Approximate duration |
|---|---|---|
PERSISTENT_TTL_THRESHOLD |
100,000 ledgers | ~5.7 days |
PERSISTENT_TTL_LEDGERS |
518,400 ledgers | ~30 days |
Behaviour: On each write the entry's TTL is extended to PERSISTENT_TTL_LEDGERS only when its current TTL has fallen below PERSISTENT_TTL_THRESHOLD. This means:
- A freshly created or recently updated entry will not incur a redundant extend ledger write.
- An entry that hasn't been touched for ~24 days will be extended back to 30 days on the next interaction.
- Both constants are compile-time values (
pub const) inlib.rsand can be adjusted for different network configurations without changing contract logic.
Off-chain responsibility: The TTL extension inside the contract only fires on writes triggered by contract invocations. Callers (backend or keeper bots) should additionally invoke ExtendFootprintTTLOp for dormant entries (loans where no repayment has occurred for an extended period) to prevent archival. See Stellar docs β state archival.