Concrete — Complete GuideIndependent guide, unofficial

02

Accounting & yield math

Level: Advanced · Models below are for understanding. The exact contract math is private; use on-chain preview*/convert* for real values.

Core identities

sharePrice   = totalAssets / totalSupply
sharesOut    = assets × (totalSupply + 1) / (totalAssets + 1)      // deposit, floor
assetsOut    = shares × (totalAssets + 1) / (totalSupply + 1)      // redeem, floor

Rounding floors in the vault's favour, so a deposit→redeem round trip can never return more than you put in (verified by a unit test in examples/python).

Accrual algorithm (documented order)

On every deposit / mint / withdraw / redeem / allocate:

  1. For each active strategy read totalAllocatedValue() and diff against last recorded value → yield (+) or loss (−).
  2. Update cachedTotalAssets.
  3. Accrue management fee on updated assets, pro-rata to elapsed time.
  4. Accrue performance fee on net positive yield (gains − losses), subject to any hurdle.
  5. Execute the user's operation at the reconciled price.

Why a cached snapshot? Donation / inflation attacks

Classic ERC-4626 attack: attacker deposits a tiny amount, then donates tokens directly to the vault to inflate totalAssets, making the next depositor's shares round to zero. Concrete's defences (as documented): (1) conversions inside guarded operations use the cached total, refreshed in a controlled way; (2) the +1 virtual terms in the share formula; (3) accrual before conversion.

Fees as dilution

To pay a fee worth F assets, the vault mints s new shares to the recipient so that their claim equals F:

s / (supply + s) × totalAssets = F   ⇒   s = F × supply / (totalAssets − F)

Every other holder is diluted proportionally. See examples/python/fee_dilution_model.py.

Hurdle rates

perfFee = perfRate × max(0, yield − hurdle), where the hurdle is a fixed APY (compounds), fixed APR (simple), or a dynamic rate tracking an external benchmark. Yield up to the hurdle goes entirely to depositors.

APR ↔ APY

APY = (1 + APR/n)^n − 1        (n = compounding periods per year)

8% APR, daily compounding → 8.328% APY.

Losses & marks

With async accounting, an operator can reduce reported total assets (adjustTotalAssets-style flow) after a loss or an unwind cost; the next accrual reconciles the strategy's tracked value. All holders take the loss pro rata via the exchange rate.

Async accounting timeline

t0  operator pushes signed valuation V0 (valid for accountingValidityPeriod)
t1  users deposit/withdraw → vault reads V0 → OK
t2  validity window expires with no new push → strategy value reverts → vault halts
t3  admin unpauseAndAdjustTotalAssets OR strategy toggled inactive → resumes

Reconciling numbers yourself

QuestionHow
Current share priceconvertToAssets(10**decimals) on the vault, or subgraph Vault.sharePrice
Historical pricesubgraph vaultStats(interval: day)
Fees paid to datesubgraph vaultFeesStats cumulative fields
Strategy allocationsubgraph Strategy.allocatedValue or on-chain totalAllocatedValue()