Skip to main content
A vault integration supplies an asset through a contract-owned lending account, reads its accrued balance, and withdraws to a recipient. The vault implements its own share accounting. This model supports DeFindex strategies and tokenized vault wrappers such as SEP-56 or OpenZeppelin FungibleVault. Read Supply and Withdraw for controller transaction semantics. The DeFindex strategy provides a concrete adapter using one account per vault.

Track the lending balance

Supply positions are stored on account_id as scaled shares keyed by HubAssetKey. They are not transferable supply tokens. The strategy contract holds the account’s position NFT, which determines account ownership. Underlying balances derive from RAY-normalized shares and the supply index. Use controller views to perform this conversion and include accrued interest: These views do not read oracle prices. Interest is reflected in the index, so reporting lending yield requires no harvest or index-maintenance update. See Interest and revenue. Balance reads round half-up, while full withdrawal pays a floor-valued balance. The payout can be one native unit below the displayed balance. Supply mints shares with floor rounding; partial withdrawal burns shares with ceiling rounding. Use returned payouts and reread balances after mutations.

Authorize supply

Pull the deposit tokens into the strategy and measure its receipt before calling this helper. Authenticate the depositor in the surrounding entrypoint. Use the measured amount, then persist the returned account id before issuing vault shares. account_id = 0 opens an account on the selected spoke_id. This complete helper uses the repository’s controller-interface and common crates. It supplies tokens already held by the invoking strategy contract:
Resolve the account before creating this transfer authorization. Keep the controller address in trusted contract configuration. The strategy’s direct controller call satisfies caller authorization as the invoking contract. The explicit entry above authorizes the deeper token transfer to the pool. Read get_collateral_amount(account_id, hub_asset) for the accrued underlying balance. For withdrawal, call the controller with the strategy as caller and the eligible recipient as to. The pool pays that recipient directly, so the strategy needs no token-transfer authorization for the payout. Controller amount = 0 closes the selected position; an excessive request clamps to full withdrawal. The returned vector reports the actual amounts paid.

Size and simulate vault actions

The controller exposes no max_withdraw or max_supply view. Read the relevant state and simulate the proposed transaction: Withdrawals also face the market utilization limit. Supply caps (#311), position limits (#109), cash shortages (#112), or utilization limits (#127) can reject an action. While debt remains, withdrawal must pass LTV coverage, health factor, and the configured USD collateral floor. Each collateral position with fewer than three decimals must also retain at least two base units after floor conversion. Simulation reflects one ledger state. Cash, interest, prices, and cap usage can change before execution.

Handle account lifecycle

A full withdrawal of the final position from a debt-free account removes the account and burns its NFT. Clear the stored id and use account_id = 0 for the next supply. A stale id raises #24 AccountNotFound. Missing-account balance views return zero, position maps are empty, and health factor is i128::MAX. Global protocol pause blocks supply but permits withdrawal, repayment, renew_account, and recapitalization. A paused spoke listing also blocks its ordinary withdrawals and repayments; a frozen listing permits those exits. Debt-free supply and withdrawal do not need oracle valuation. Repayment and native balance reads are also oracle-free. With debt, withdrawal needs valid prices, and supply can need them for a less favorable liquidation-parameter refresh. Account strategies fetch prices before funding or callbacks. Account keys renew when read or written: a remaining lifetime below 30 days is extended to 120 days. Touch dormant positions periodically with renew_account(caller, account_id), including during pause. Archived entries require RestoreFootprint before use. The vault must also maintain its own mapping and share-accounting storage.

Protect vault share accounting

An external caller can supply into a market the account already holds, even without owner or delegate authority. This raises the lending balance without a vault deposit. It cannot add a new supply-position slot to that account.
Account for unsolicited deposits when minting vault shares. The vault must implement first-deposit inflation protection; the reference DeFindex adapter contains no vault share accounting or inflation guard.
Keep the account NFT under the strategy’s control. Transferring it changes the authority over all account collateral and debt.

Verify the integration

Cover deposit, balance, and withdrawal round trips; direct payment to a third party; interest accrual without index maintenance; and account recreation after a full exit. Also check storage renewal and externally added collateral against the vault’s accounting rules. Use the Controller ABI for exact signatures and DeFindex strategy for the reference adapter’s implementation contract.