Skip to content
Lattice

CurveStableSwapAdapterLib

Git Source

Title: CurveStableSwapAdapterLib

Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from Curve (https://github.com/curvefi/curve-contract)

Logic for a single-asset, single-sided Curve StableSwap LP strategy. Deposits the configured asset into one side of a 2-coin pool, holds (or stakes) the LP, and values the position in asset units via get_virtual_price. Reentrancy-gated, pause/emergency-aware, shortfall-honest. CRV/extra rewards forwarded RAW (no swap) and NOT counted in NAV.

Pool shape is pinned to N == 2 by ICurveStableSwapPool (Curve pools are generated per-N; the coins array is fixed-size). The adapter supplies one side via _coinIndex and leaves the other at zero.

Functions

curveStableSwapAdapterStorage

function curveStableSwapAdapterStorage() internal pure returns (CurveStableSwapAdapterStorage storage $);

Returns

NameTypeDescription
$CurveStableSwapAdapterStorage

__CurveStableSwapAdapter_init

function __CurveStableSwapAdapter_init(
        address pool_,
        address lpToken_,
        address gauge_,
        address asset_,
        int128 coinIndex_,
        address vault_,
        address recipient_,
        uint256 slippageBps_
    ) internal;

Parameters

NameTypeDescription
pool_address
lpToken_address
gauge_address
asset_address
coinIndex_int128
vault_address
recipient_address
slippageBps_uint256

registerInterface

function registerInterface() internal;

asset

function asset() internal view returns (address);

Returns

NameTypeDescription
<none>address

vault

function vault() internal view returns (address);

Returns

NameTypeDescription
<none>address

pool

function pool() internal view returns (address);

Returns

NameTypeDescription
<none>address

lpToken

function lpToken() internal view returns (address);

Returns

NameTypeDescription
<none>address

gauge

function gauge() internal view returns (address);

Returns

NameTypeDescription
<none>address

crvToken

function crvToken() internal view returns (address);

Returns

NameTypeDescription
<none>address

coinIndex

function coinIndex() internal view returns (int128);

Returns

NameTypeDescription
<none>int128

slippageBps

function slippageBps() internal view returns (uint256);

Returns

NameTypeDescription
<none>uint256

rewardRecipient

function rewardRecipient() internal view returns (address);

Returns

NameTypeDescription
<none>address

operator

function operator() internal view returns (address);

Returns

NameTypeDescription
<none>address

_checkOperator

Reverts ProtocolAdapterUnauthorized unless the caller is the wired operator. Placed at the very top of deploy/withdraw/harvest — BEFORE the reentrancy guard — so an unauthorized call never leaves the guard latched. Zero operator ⇒ always reverts.

function _checkOperator() private view;

minHealthFactor

function minHealthFactor() internal pure returns (uint256);

Returns

NameTypeDescription
<none>uint256

healthFactor

function healthFactor() internal pure returns (uint256);

Returns

NameTypeDescription
<none>uint256

isPaused

function isPaused() internal view returns (bool);

Returns

NameTypeDescription
<none>bool

_lpHeld

Total LP controlled by this adapter = staked-in-gauge + held loose.

Counts both so that LP acquired before a gauge was wired (or left loose) is never undercounted in valuation.

function _lpHeld(CurveStableSwapAdapterStorage storage $) private view returns (uint256);

Parameters

NameTypeDescription
$CurveStableSwapAdapterStorage

Returns

NameTypeDescription
<none>uint256

totalAssetsManaged

Position value in asset units = lpHeld * get_virtual_price() / 1e18.

Read-only reentrancy: get_virtual_price() is read-only-reentrancy-exposed on real Curve pools (its value can be skewed mid-callback). This adapter never reads it inside a foreign external interaction it does not control: deploy/withdraw/emergencyWithdraw are all nonReentrant, and VaultCore/StrategyManager block share-price-sensitive vault entries while a rebalance is in flight (they consult reentrancyGuardEntered). This view is therefore only consumed outside the adapter's own state-changing calls, so we do NOT add a self-reentrant valuation. get_virtual_price is monotone non-decreasing as the pool earns fees, so lp * vp / 1e18 is a safe lower bound on the single-coin redeemable value of an over-collateralized stable pool.

Idle leg (NAV-gap fix): adds the adapter's idle underlying-asset balance to the LP-valued position. IVaultCore.allocateToStrategy pushes funds here with a bare transfer that does NOT add liquidity, so undeployed funds sit idle until deploy() (and lp can be 0 while idle is non-zero — exactly the allocate-before-deploy state). Counting that idle keeps the vault's share price flat across the allocate→deploy window. No double-count: the idle is in neither the vault's idle nor the LP position, and after deploy() idle→~0 while LP grows by the same value, so the sum is invariant across deploy. The idle asset is held loose by the adapter (not in the pool), so reading it is free of the get_virtual_price read-only-reentrancy concern.

UNSUPPORTED in 0.5.0: unsafe as a share-pricing source. VaultCore vaults price ERC-4626 shares on their full NAV, which includes this value. The guards above cover only Lattice's own mutators and the rebalance flag; an outsider re-entering the vault from a pool's ETH callback runs no Lattice code, passes them, and deposits or redeems against a skewed get_virtual_price(). No read-only-reentrancy probe ships in this release (#221), so do not wire this adapter into a vault's StrategyManager.

function totalAssetsManaged() internal view returns (uint256);

Returns

NameTypeDescription
<none>uint256

setGauge

function setGauge(address gauge_) internal;

Parameters

NameTypeDescription
gauge_address

setCrvToken

function setCrvToken(address token) internal;

Parameters

NameTypeDescription
tokenaddress

setSlippageBps

function setSlippageBps(uint256 slippageBps_) internal;

Parameters

NameTypeDescription
slippageBps_uint256

setRewardRecipient

function setRewardRecipient(address recipient) internal;

Parameters

NameTypeDescription
recipientaddress

setOperator

Sets the authorized operator for deploy/withdraw/harvest (admin-only). Rejects address(0) so the trio cannot be opened to an unauthenticated default.

function setOperator(address operator_) internal;

Parameters

NameTypeDescription
operator_address

deploy

function deploy() internal returns (uint256 deployed);

Returns

NameTypeDescription
deployeduint256

withdraw

function withdraw(uint256 amount, address to) internal returns (uint256 withdrawn);

Parameters

NameTypeDescription
amountuint256
toaddress

Returns

NameTypeDescription
withdrawnuint256

harvest

function harvest() internal;

emergencyWithdraw

function emergencyWithdraw() internal returns (uint256 recovered);

Returns

NameTypeDescription
recovereduint256

_removeLiquidityFor

Burns the LP worth amount of the asset (single-coin exit into this adapter), capped at the LP held. The single-coin exit fee means the asset received can fall short of amount.

function _removeLiquidityFor(CurveStableSwapAdapterStorage storage $, uint256 amount) private;

Parameters

NameTypeDescription
$CurveStableSwapAdapterStorage
amountuint256

_ensureLooseLp

Ensures at least need LP is held loose, unstaking the shortfall from the gauge.

function _ensureLooseLp(CurveStableSwapAdapterStorage storage $, uint256 need) private;

Parameters

NameTypeDescription
$CurveStableSwapAdapterStorage
needuint256