Skip to main content
AccountManager is the first contract a user or integrator calls for any margin operation. It authenticates callers, coordinates with RiskEngine and LendingPool, and delegates state mutations to the user’s SmartAccount. Testnet address: CAK2IJIO2SKZWUODY4G7ZRIUUIIMJUUAIXE3I5YTQ5QYNSS2RYJ3P4CV

Account Lifecycle

create_account

Deploys a new SmartAccount contract for trader_addr (or reuses a closed one from the inactive pool) and marks it as active. Authorization: trader_addr.require_auth() Returns: Address of the new (or reused) SmartAccount Storage written:
  • UsersList — appends trader_addr if not already present
  • SmartAccounts(trader_addr) — stores the active SmartAccount address
  • TraderAddress(smart_account) — reverse mapping from SmartAccount → trader
  • Registry is updated with the new account
Events emitted:
Reuse logic: If the user previously closed an account, the closed contract is reactivated instead of deploying a new one. Deployment cost is amortized across the account’s lifetime.

close_account

Closes an active margin account. Sweeps all collateral to the owner, deactivates the contract, and pushes it to the inactive pool for reuse. Authorization: Trader (owner of smart_account) must sign Panics if: The account has any outstanding debt (has_debt == true) Returns: true on success Events emitted:

Collateral Operations

deposit_collateral_tokens

Transfers amount (in WAD) of the token identified by symbol from the caller’s wallet to the SmartAccount. Authorization: Trader must sign; caller must approve token transfer Parameters: Events emitted:

withdraw_collateral_balance

Withdraws collateral from a SmartAccount back to the owner’s wallet. Authorization: Trader must sign Risk check: RiskEngine.is_withdraw_allowed(symbol, amount, smart_account) must return true Panics if: Health factor would drop below 1.1× after withdrawal

Borrow Operations

borrow

Borrows amount of symbol from the corresponding LendingPool into the SmartAccount. Authorization: Trader must sign Risk check: RiskEngine.is_borrow_allowed(symbol, amount, smart_account) must return true Parameters: What happens internally:
  1. RiskEngine validates the borrow
  2. LendingPool accrues interest (update_state())
  3. Origination fee is deducted and sent to treasury
  4. Borrowed amount is transferred to SmartAccount
  5. SmartAccount records the new borrow in BorrowedTokensList
Events emitted:

deposit_and_borrow

Atomically deposits collateral and borrows the same asset in a single transaction.

deposit_and_borrow_cross

Atomically deposits one asset as collateral and borrows a different asset. Useful for cross-collateral strategies (e.g., deposit XLM, borrow USDC).

deposit_borrow_and_deploy_blend

Three-step atomic operation: deposit collateral, borrow, then forward borrowed funds to Blend — all in one transaction. Minimizes round-trips for leverage strategies.

Repay

repay

Repays repay_amt of symbol debt. Caller (trader) transfers funds back to the LendingPool. If the full debt is repaid, the symbol is removed from BorrowedTokensList. Authorization: Trader must sign Events emitted:

Liquidation

liquidate

Liquidates an undercollateralized margin account. Repays all debt by drawing from the SmartAccount’s collateral, then sweeps remaining collateral back to the account owner. Authorization: None — anyone can call this function Condition: RiskEngine.is_account_healthy(collateral_usd, debt_usd) must return false What happens:
  1. Validates the account is unhealthy
  2. For each borrowed token: reads outstanding debt, calls LendingPool.collect_from() to repay it
  3. Calls SmartAccount.sweep_to(trader_address) to return remaining collateral
  4. Emits event
Liquidation incentive: Currently, the protocol repays debt directly from collateral. The trader gets back whatever collateral remains after debt is cleared. There is no explicit liquidation bonus — liquidators earn value by keeping the protocol solvent. Incentive structure may be updated in future versions. Events emitted:

settle_account

Repays all outstanding debt without closing the account. Unlike liquidate(), this is intended for voluntary debt settlement by the account owner.

External Protocol Execution

execute (via SmartAccount routing)

External protocol calls are routed through the SmartAccount’s execute() function. The AccountManager orchestrates:
  1. Auth of the trader
  2. SmartAccount executes the external call (Blend, Aquarius, Soroswap)
  3. AccountManager mints/burns TrackingTokens based on the returned token delta
See SmartAccount for the action types and routing details.

Supported Assets

| BLUSDC | Blend-wrapped USDC | LendingPoolUSDC | | AQUSDC | Aquarius-wrapped USDC | LendingPoolAquariusUSDC | | SOUSDC | Soroswap-wrapped USDC | LendingPoolSoroswapUSDC |

Error Codes


Key Storage