Use eth_call for quotes
quoteBuy and quoteSell are not declared view. With ethers v6, use .staticCall(...) explicitly so that quoting does not send a transaction. Quote from the intended sender at a consistent recent block. The returned out is the expected output, and fee is the reported total trading fee; do not subtract it from out a second time.
| State | Buy quote | Sell quote |
|---|---|---|
| Bonding curve | quoteBuy.staticCall(grossEth, overrides) | quoteSell.staticCall(tokensIn, overrides) |
| Graduated V4 | quoteV4Buy.staticCall({from, value: grossEth, blockTag}) | quoteSell.staticCall(tokensIn, overrides) |
Prepare a buy
import {parseEther} from 'ethers';
import {prepareBuy} from './littlejohn-v10-example.mjs';
const owner = await signer.getAddress();
const plan = await prepareBuy(rpc, {
factoryIndex: 0n, owner, value: parseEther('0.001'), slippageBps: 50
});
// Display token address, input, out, minOut, fee, deadline and network.
// Only AFTER the user authorizes this exact transaction:
// const gas = await signer.estimateGas(plan.request);
// const tx = await signer.sendTransaction(plan.request);
// const receipt = await tx.wait(confirmations);Bonding limits and graduation races
Before graduation, respect publicBuyOpensAt() and remainingBondGross(). Oversized buys revert; the example does not silently split them or alter the amount. Graduation is based on actual curve reserve and can occur inside the last curve buy. If market state changes after quoting, obtain a fresh quote and approval from the user when its terms change. A minimum-output check limits execution output, but does not freeze the market stage.
Prepare a sell and approval
import {parseUnits} from 'ethers';
import {prepareSell} from './littlejohn-v10-example.mjs';
const input = {factoryIndex: 0n, owner: await signer.getAddress(),
amount: parseUnits('1000', 18), slippageBps: 50};
let plan = await prepareSell(rpc, input);
if (plan.approval) {
// Ask separately before sending the exact-amount token approval.
// const approvalTx = await signer.sendTransaction(plan.approval);
// await approvalTx.wait(confirmations);
// Then call prepareSell(rpc, input) again for a fresh sell quote.
} else {
// Present the sell review, then authorize/send plan.request.
}What your application must supply
- An authenticated, authorized signer on chain 4663; matching the owner used in the quote. Never select a backend signing account from an untrusted chat message alone.
- Gas estimation, sufficient native ETH for gas, and a clear transaction review.
- A confirmation policy, replacement/cancellation handling and canonical receipt verification.
- Nonce coordination for concurrent sends, persistent pending-transaction records, and bounded retries. Never blindly resend after an HTTP timeout.
- Fresh quotes after approvals or expired deadlines. The example uses 120 seconds from the quoted block timestamp and a configurable minimum output; it is not a guaranteed execution price.
After Uniswap V4 graduation
The curve buy/sell entrypoints continue to route through its V4 integration. V4 buy quoting requires payable eth_call simulation; provider capability must be tested. Direct external pool routing is a separate integration with the Little John hook. Do not assume generic V4 support includes that hook. See the graduation explanation and reference.