Lending Canister
The protocol orchestrator managing authentication, linked accounts, positions, pool coordination, prices, and liquidation interfaces.
Responsibilities
- Account Management: Internet Identity and supported multi-chain wallet authentication with profile linking
- Position Tracking: User collateral and debt positions using share-based accounting
- Interest Accrual: Calculating and applying interest via global indices
- Health Enforcement: Validating health factors before operations
- Pool Coordination: Orchestrating deposits, withdrawals, borrows, and repayments
- Price Integration: Fetching and caching asset prices from oracles
- Liquidation API: Exposing interfaces for external liquidator bots
Production canister
The production Lending Canister is:
hyk4r-jqaaa-aaaar-qb4ca-caiArchitecture
Account Management
Authentication Paths
Users can sign in with Internet Identity or authenticate with a supported Bitcoin or Ethereum wallet. The canister can also verify Solana signatures, but the app does not offer Solana sign-in. The sequence below documents the wallet-signature path:
Wallet Abstraction
For wallet-authenticated profiles, a wallet is represented as a (Chain, Address) tuple—for example (Bitcoin, "bc1q...") or (Ethereum, "0x..."). The sequence above shows how ownership of that address is verified before it can control the profile. Internet Identity authenticates the user through an Internet Computer delegation and principal; it does not use the wallet-signature flow shown above.
Benefits:
- Use Internet Identity or existing supported wallets
- Strong cryptographic identity
- Multi-wallet support per profile
- Unified positions across wallets
Internet Identity and ICP wallets
Internet Identity is an authentication method, not a native ICP wallet connection. Supported ICP assets and ckAssets can still use compatible address-based flows where required by the selected operation.
Position Management
Each user's position in a pool is tracked using shares:
Field | Description |
|---|---|
| Principal of the user |
| Pool canister ID |
| Asset type (BTC, ETH, USDC, etc.) |
| Supply shares |
| Debt shares |
| Index at last update |
| Index at last update |
Core Operations
All operations follow the same pattern:
- Sync pool indices to current time
- Validate preconditions (caps, liquidity)
- Update shares (mint or burn)
- Validate postconditions (health factor)
- Schedule async execution if needed
Operation | Share Action | Health Check |
|---|---|---|
Deposit | Mint supply shares | No (improves health) |
Withdraw | Burn supply shares | Yes (must stay healthy) |
Borrow | Mint debt shares | Yes (must stay healthy) |
Repay | Burn debt shares | No (improves health) |
Pool Registry
The lending canister maintains a registry of all pools with their configuration:
Category | Fields |
|---|---|
Identity | Principal, asset, chain |
Caps | Supply cap, borrow cap |
Share Totals | Total supply, total debt, treasury shares |
Interest Rates | Base rate, slope before, slope after, optimal utilization |
Indices | Borrow index, lending index |
Risk Parameters | Reserve factor, liquidation threshold, liquidation bonus |
Event Handling
The lending canister receives events from pool canisters via notify_pool_event(). Events include:
DepositConfirmed- triggers supply share mintingRepaymentConfirmed- triggers debt share burning
Each event includes a ledger transaction ID for idempotency - if the same transaction ID is processed twice, the duplicate is ignored.
Background Tasks
Task | Interval | Purpose |
|---|---|---|
Price sync | 30s | Refresh each pool asset's price from the Exchange Rate Canister |
WAL scan | 30s | Retry pending async operations that are due |
Fee sync | 15s | Refresh pool ledger fees |
Cleanup | Hourly and daily | Remove old WAL entries, events, and liquidation records |
Pool indices are not updated on a timer. They are brought up to date whenever an operation touches the pool.
Price Integration
Prices come from the Internet Computer's Exchange Rate Canister (XRC, uf6dk-hyaaa-aaaaq-qaaaq-cai). The Lending Canister refreshes each pool asset's price every 30 seconds and keeps the latest value.
If a price needed for an operation is older than 120 seconds, borrows, withdrawals, and liquidations that depend on it are rejected until a fresh price arrives. Supplies and repayments do not need a price. Current prices are readable with the get_prices query.