Curve projects typically feature many interesting details in their implementations. Let's discuss some of them.
Vault and controller track underlying tokens balances directly. As we've seen in the Euler V2
article, some protocols choose to maintain their own internal copy of underlying token balances instead of simply using
balanceOf(). Both approaches work: the "balance copy" is more resistant to "donation" attacks but is more expensive and can have potential problems with keeping two copies of the same balance. The direct
balanceOf() approach is simpler and cheaper for users but may be more susceptible to "donation" attacks.
User ticks, holding information about shares in each tick, are stored as 128-bit values. Reading user ticks is implemented
here, and user positions are
stored as a mapping
address => struct UserTicks, where
userTicks holds the ticks range (as
2x128 = 256 variable) and an array with shares in each tick in the range.
The
users_to_liquidate() function in Controller returns the list of users who can be "hard-liquidated". Such functions are not usually present in the protocols with liquidations and bot creators typically track positions to liquidate by themselves. This function helps them, but not signficantly, as liquidation bots mostly look at "future" liquidations, intercepting price changes and attempting to perform the liquidation via MEV first.
LLAMMA can also incentivize pools by attaching a special liquidity mining gauge contract with rewards for liquidity miners. This is done by
registering self.liquidity_mining_callback here and calling it in many functions, for example in
deposit_range() here. This feature comes from the first Curve pools and plays an important role for the projects, boosting the utilization of their tokens.
LLAMMA uses the
precalculated sqrt and
log values of expressions with parameter
A, provided by the deployer, to avoid calculations of these expressions in contracts.