Bonding Curve Plugin
Status: Stable – available on Solana devnet.
Import identifier in policy expressions:
@BondingCurvePlugin.*
The Bonding Curve Plugin exposes pure, read‑only helpers that let Tarobase policies perform constant‑product AMM math entirely on‑chain, without requiring custom Rust code.
Use it to verify that a trade meets slippage constraints or honours locked liquidity before you allow a create
on a buy/sell operation.
No transactional (state‑changing) functions are provided. All helpers may be used anywhere an expression expects a numeric value: rules.*
, hooks.*
, or LLM prompts.
Function reference
Function | Signature | Returns | Description |
---|---|---|---|
getTokensOutProduct | @BondingCurvePlugin.getTokensOutProduct(tokenAmount, currentSolReserves, currentTokenReserves, initialSolReserves, initialTokenReserves) | UInt | Calculates tokens a buyer receives when they provide tokenAmount of SOL to the curve (i.e., a buy). All parameters are lamports / smallest‑unit tokens. |
getSolOutProduct | @BondingCurvePlugin.getSolOutProduct(solAmount, currentSolReserves, currentTokenReserves, initialSolReserves, initialTokenReserves) | UInt | Calculates lamports a seller receives when they provide solAmount of tokens to the curve (i.e., a sell). All parameters are lamports / smallest‑unit tokens. |
Formula – Both helpers implement the classic x · y = k constant‑product invariant, accounting for the supplied amount and the initial virtual reserves. The results are rounded down to the nearest integer to guarantee conservativeness.
Quick‑start examples
1. Enforcing minimum tokens received on a buy
"operations/$agentId/buy/$buyId": {
"fields": {
"solIn": "UInt", // lamports user intends to spend
"minTokens": "UInt" // desired minimum token amount (smallest units)
},
"rules": {
"create": "@BondingCurvePlugin.getTokensOutProduct(@newData.solIn, @TokenPlugin.getBalance($agentId, @TokenPlugin.SOL), @TokenPlugin.getBalance($agentId, @TokenPlugin.getTokenMintAddress($agentId, get(/agents/$agentId).tokenName, get(/agents/$agentId).tokenSymbol)), INITIAL_SOL, INITIAL_TOKENS) >= @newData.minTokens"
}
}
Replace INITIAL_SOL
/ INITIAL_TOKENS
with constants or stored fields.
2. Respecting locked liquidity on a sell
"operations/$agentId/sell/$sellId": {
"fields": { "tokenIn": "UInt", "minLamports": "UInt" },
"rules": {
"create": "@BondingCurvePlugin.getSolOutProduct(@newData.tokenIn, @TokenPlugin.getBalance($agentId, @TokenPlugin.SOL), @TokenPlugin.getBalance($agentId, TOKEN_MINT), INITIAL_SOL, INITIAL_TOKENS) >= @newData.minLamports && (@TokenPlugin.getBalance($agentId, @TokenPlugin.SOL) - get(/agents/$agentId).lockedLiquidity) >= @BondingCurvePlugin.getSolOutProduct(@newData.tokenIn, …)"
}
}
This pattern prevents draining SOL below lockedLiquidity
while still honouring the curve price.
Best practices
- All inputs are integers – use lamports and smallest‑unit tokens, never floats.
- Cache
currentSolReserves
/currentTokenReserves
with@TokenPlugin.getBalance
to avoid double calculation inside complex expressions. - Store initial virtual reserves in the parent
agents/$agentId
document or as constants; they must match the values used when the curve was bootstrapped. - Use cross‑multiplication (or the helper itself) rather than division for slippage checks to avoid precision loss.
- Because the helpers are pure, calling them has zero compute‑unit cost on the transaction beyond basic arithmetic.