Skip to main content
The defindex-strategy contract is a reference vault adapter. It maps each DeFindex vault to one controller supply account for a single underlying asset. Share accounting lives in the DeFindex vault contract; the strategy holds only a vault-to-account mapping.

Deployment model

  • One WASM per underlying asset. Deploy a separate strategy instance per listed market.
  • One controller account_id per vault. Vaults never share a lending account.
  • Strategy is the caller on all controller mutations (supply, withdraw).
Constructor:
A missing or wrongly-typed argument panics with #401 NotInitialized. The constructor then checks that a market index exists for asset on hub_id, resolves the pool address from the controller, and stores this in instance storage:
The one other storage key is VaultAccount(vault_address) -> u64, which maps a vault to the controller account holding its collateral.

Trait API

The contract implements DeFindexStrategyTrait and exposes exactly these five entrypoints — there is no account-id lookup view.

Deposit flow

Step 2 runs before authorize_as_current_contract, and that ordering is load-bearing: it reconciles the stored mapping against controller.account_exists first, so a re-deposit after a full withdraw does not fail with Auth InvalidAction. Step 1 is a measured transfer — the amount actually received is what gets supplied, not the amount requested.

Withdraw flow

Withdraw pays to directly from the pool. No pre-authorization is required on the strategy side.

Harvest and price per share

harvest emits HarvestEvent (["strategy", "harvest"]) with a 12-decimal price_per_share (PPS_DECIMALS = 12). It reads the controller’s get_market_index(hub_asset).supply_index and floor-rescales it from RAY:
The value is market-wide, not per-vault. harvest moves no funds — the event’s amount field is always 0 — and makes no on-chain state change; DeFindex vaults use the event for share accounting.

Controller integration

Auth recipe

Supply requires the strategy to authorize its own token transfer to the pool before calling controller.supply:
Withdraw does not need a pre-authorization; the pool transfers to to on the controller’s behalf.

Strategy errors

These are the adapter’s own enum, independent of the protocol error codes.

The vault-to-account mapping is one-way

VaultAccount(vault) is the only route back to a vault’s collateral, and there is no entry point to re-point it. If you clear it while the account is still alive, that collateral becomes unreachable through the adapter. resolve_vault_account is written around that. It calls controller.try_account_exists(stored) and treats the three outcomes differently: That third row is the important one. A lookup that merely failed to answer is not evidence the account is gone. Treating it as gone would clear the only pointer to live collateral.
If you fork this adapter, keep that distinction. “I could not reach the controller” and “the controller says the account no longer exists” must not collapse into the same branch.

Fork checklist

When adapting the reference strategy:
  • Keep the three-way lookup above. Only an explicit “gone” may clear a mapping.
  • Enforce vault-side inflation guards before trusting deposit return values.
  • Extend TTL for the strategy instance and the vault-mapping keys.
  • Cover deposit, balance, and withdraw round trips; third-party payout; interest accrual with no index maintenance; and account recreation after a full exit.
  • Keep one WASM per asset. Do not share a strategy instance across underlyings.

Next

Vault integrations

Generic vault integration model, lifecycle rules, and auth patterns.

Supply and borrow

Underlying controller supply and withdraw semantics.

Interest and revenue

How supply indexes accrue and how price_per_share tracks yield.

Controller ABI

supply, withdraw, and get_collateral_amount signatures.