Skip to main content
The defindex-strategy contract is a reference vault adapter in contracts/defindex-strategy/. 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:
__constructor(asset: Address, init_args: Vec<Address>)
// init_args[0] = controller address
// Validates market is listed; stores {asset, controller, pool}

Trait API

EntrypointAuthReturnsBehavior
asset()AddressConfigured underlying asset
deposit(amount, from)from.require_auth()i128Pull tokens, supply to controller, return post-deposit balance
balance(from)i128collateral_amount_for_token(account_id, asset)
withdraw(amount, from, to)from.require_auth()i128Withdraw to to; amount = 0 closes the full position
harvest(from, data)Emits HarvestEvent with 12-decimal price_per_share
lending_account_id(vault)u64Live controller account id (reconciles stale mapping)
has_lending_account(vault)boolWhether the vault has a live account

Deposit flow

from (vault) --auth--> deposit(amount)
  1. transfer(from → strategy, amount)
  2. prepare_vault_account_for_supply()     // clears stale mapping before auth
  3. authorize_as_current_contract(transfer(strategy → pool, amount))
  4. controller.supply(strategy, stored_id_or_0, spoke_id, [(hub_asset, amount)])
  5. persist new account_id in VaultAccount(vault)
  6. return collateral_amount_for_token(account_id, asset)
prepare_vault_account_for_supply may call controller.account_exists before authorize_as_current_contract. If auth were emitted first, re-deposit after a full withdraw would fail with Auth InvalidAction.

Withdraw flow

from (vault) --auth--> withdraw(amount, from, to)
  1. reconcile vault → account_id (0 → InsufficientBalance)
  2. balance = collateral_amount_for_token(account_id, asset)
  3. reject if amount > balance (strategy-level check; stricter than controller clamp)
  4. if amount == balance → withdraw_amount = 0 (full close sentinel)
  5. controller.withdraw(strategy, account_id, [(asset, withdraw_amount)], Some(to))
  6. return remaining collateral (0 if account deleted)
Withdraw pays to directly from the pool. No pre-authorization is required on the strategy side.

Harvest and price per share

harvest emits a 12-decimal price_per_share derived from the market supply index:
price_per_share = supply_index_ray / (RAY / 1_000_000_000_000)
The value is market-wide (from supply_index_ray), not per-vault. harvest makes no on-chain state change; DeFindex vaults use the event for share accounting.

Controller integration

ConcernImplementation
Balance readscollateral_amount_for_token — oracle-free, accrues to now
Supply authPre-authorize transfer(strategy → pool)
Withdraw authNone; pool pays recipient directly
Pool addressResolved at init via controller.get_pool_address()
Stale mappingCleared on supply after full withdraw; read paths return 0 until re-deposit

Auth recipe

Supply requires the strategy to authorize its own token transfer to the pool before calling controller.supply:
env.authorize_as_current_contract(vec![
    &env,
    InvokerContractArgs {
        contract: pool_address,
        fn_name: "transfer",
        args: (strategy_address, pool_address, amount).into_val(&env),
    },
]);
Withdraw does not need a pre-authorization; the pool transfers to to on the controller’s behalf.

Strategy errors

CodeError
401NotInitialized
460AmountNotPositive
461InsufficientBalance
462ArithmeticError

Fork checklist

When adapting the reference strategy:
  • Enforce vault-side inflation guards before trusting deposit return values.
  • Extend TTL for strategy instance and vault-mapping keys.
  • Run the integration test matrix in contracts/defindex-strategy/tests/.
  • Keep one WASM per asset; do not share strategy instances 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 collateral_amount_for_token signatures.