Feat PancakeSwap V3 CLMM fixes, binCount pool-info for all CLMM connectors, extended Ethereum tx polling#646
Conversation
…(unconditional zero-liquidity skip)
|
Oh and .github/copilot-instructions.md is the same text as claude.md and the both have agent directives to keep them insync, developing in VS/VSCode with Git looks for this if you have a copilot acct even if you use Claude through copilot. It just resolved the need to reference claude.md in prompts and only affects copilot users. I did add lenses to both it for better agent POVs |
|
Since this is based on #642, please rebase this branch so that it's based on that one, not as a parallel branch. That isolates the changes you're proposing only. |
|
@fengtality It's not, those changes we brought into this branch of develop. If that was what you wanted I misunderstood and won't have time to re-write this ATM. I thought you asked me to include those changes in my new seperated branch from the orig PR. If that's wrong you can just close this |
feat: PancakeSwap V3 CLMM fixes, binCount pool-info for all CLMM connectors, extended Ethereum tx polling
Related PRs
Problems Resolved
1 — PancakeSwap V3
execute-swapcrashing with BigInt TypeErrorexecuteSwap.tsimportedencodeSqrtRatioX96from@uniswap/v3-sdkand passed it into the PancakeSwap SDK's swap router call. The two SDKs use incompatibleJSBIinstances, causing a silentBigInttype-mismatch at runtime that crashed every swap attempt.Fix: Removed the
@uniswap/v3-sdkimport entirely. SetsqrtPriceLimitX96: 0on the swap params object — the correct no-limit sentinel for V3 routers. Slippage is enforced throughamountOutMinimum/amountInMaximumas intended.2 — PancakeSwap V3
positions-ownedreturning wrong base/quote orientation for non-WETH pairsThe previous code contained a
WETHspecial-case that broke BSC pairs (e.g. USDT/WBNB) — the token whose address sorted lower was misidentified as the base, causingbaseTokenAmountandquoteTokenAmountto be swapped in the response.Fix: Replaced the WETH special-case with pure address-order comparison (
token0.address < token1.address) consistent with how Uniswap V3 forks determine token ordering in the pool contract.3 — PancakeSwap V3
quote-positionprecision loss fromMath.floorquotePosition.tscomputed token amounts withMath.floor(amount * 10^decimals). For large amounts (e.g. 1 000 USDT at 18 decimals) this loses precision at the integer boundary, producing incorrect tick-aligned liquidity quotes.Fix: Replaced all
Math.flooramount conversions withutils.parseUnits(amount.toString(), decimals)from ethers.js, which uses exact big-integer arithmetic. Also removed ~20 leftoverconsole.logdebug statements that were present in production code.4 — BUY-side price inversion on Orca and Meteora
quote-swapOn a BUY order the swap helper's input token is the quote token and the output token is the base token. The old code computed
price = outputAmount / inputAmount, which on a BUY equalsbase / quote— the inverse of the expectedquote / baseconvention. A SOL/USDC BUY returnedprice ≈ 0.005instead of≈ 200.Hummingbot Python strategies parse the
pricefield directly; this silent inversion caused bots to compute wildly wrong order sizes.Fix (Orca): Reconstructed
price = quoteAmount / baseAmountfrom first principles usinginputAmount/outputAmounttogether with thesideparameter, independent of which token was the router's input.Fix (Meteora): Applied the same
estimatedAmountIn / amountOutformula on the BUY branch (previouslyamountOut / estimatedAmountIn).5 —
binCountparameter missing from pool-info across all CLMM connectorsMeteora already supported returning a
bins[]liquidity-distribution array viabinCount. Orca, Raydium, Uniswap, and PancakeSwap did not, making cross-connector strategy code that relies on per-tick depth data unable to work uniformly.Fix: Added
binCountquery parameter (integer, 0–400, default 0) to pool-info on all four connectors. WhenbinCount > 0, abins[]array is appended to the response containing{ binId, price, baseTokenAmount, quoteTokenAmount }entries centred on the active tick. Each connector uses its own distribution helper:computeOrcaBinDistribution(new function inorca.utils.ts)computeRaydiumBinDistribution(new function inraydium.utils.ts)computeUniswapBinDistribution(existing function inuniswap.utils.ts)computeUniswapBinDistribution(PancakeSwap V3 is a Uniswap V3 fork)The base
PoolInfoSchema(src/schemas/clmm-schema.ts) was updated with an optionalbinsfield so all connectors share the same TypeBox-typed response shape.6 — Ethereum transaction execution timeout causing confirmed txs to report as failures
handleTransactionExecutionracedtx.wait(1)against a 30 s timeout. During network congestion a valid transaction could take 3–5 additional blocks (36–60 s on mainnet), causing it to be silently dropped and the caller to receivenull.Fix: After the initial timeout fires, the method now polls
getTransactionReceiptevery 5 s for an additional 90 s extended window before returningnull. All receipt-path code inapprove.tswas also audited and null-guards added at everyreceipt.statusaccess to preventTypeError: Cannot read properties of null.Swagger / OpenAPI Documentation Updates
All new and changed parameters are fully described in the auto-generated Swagger UI at
/docs.GET /connectors/pancakeswap/clmm/pool-infonetworkbscbsc)poolAddressbinCount00400bins[].0skips the extra RPC call.GET /connectors/orca/clmm/pool-infobinCount004000skips the extragetProgramAccountscall.GET /connectors/raydium/clmm/pool-infobinCount004000skips the extra tick fetch.GET /connectors/uniswap/clmm/pool-infobinCount004000skips the extraeth_call.BinLiquidityschema (shared,src/schemas/clmm-schema.ts)All connectors that return
bins[]use this schema. Fields now carry Swagger descriptions:binIdpricebaseTokenAmountquoteTokenAmountThe
binsfield onPoolInfoSchemais annotated: "Per-tick liquidity distribution around the active tick. Present only whenbinCount > 0was requested."Changed Files
Source
src/chains/ethereum/ethereum.tshandleTransactionExecution: added 90 s extended poll after initial timeoutsrc/chains/ethereum/routes/approve.tsreceipt.statusat every call sitesrc/connectors/meteora/clmm-routes/quoteSwap.tsestimatedAmountIn / amountOutsrc/connectors/orca/clmm-routes/quoteSwap.tsquoteAmount / baseAmountfrom sidesrc/connectors/orca/clmm-routes/poolInfo.tsbinCount→computeOrcaBinDistributionsrc/connectors/orca/orca.utils.tscomputeOrcaBinDistributionfunctionsrc/connectors/orca/schemas.tsbinCountfield with description and 0–400 rangesrc/connectors/pancakeswap/clmm-routes/executeSwap.ts@uniswap/v3-sdkimport;sqrtPriceLimitX96: 0src/connectors/pancakeswap/clmm-routes/poolInfo.tsbinCount→computeUniswapBinDistributionsrc/connectors/pancakeswap/clmm-routes/positionsOwned.tstoken0.address < token1.address)src/connectors/pancakeswap/clmm-routes/quotePosition.tsutils.parseUnitsprecision fix; removed allconsole.logsrc/connectors/pancakeswap/pancakeswap.contracts.tspancakeswapV3MasterchefAddressto interface and all four networks (BSC/mainnet:0x556B9306565093C855AEA9AE92A594704c2Cd59e, Arbitrum:0x5e09ACf80C0296740eC5d6F643005a4ef8DaA694, Base:0xC6A2Db661D5a5690172d8eB0a7DEA2d3008665A3); newgetPancakeswapV3MasterchefAddress()helpersrc/connectors/pancakeswap/schemas.tsbinCountfield addedsrc/connectors/raydium/clmm-routes/poolInfo.tsbinCount→computeRaydiumBinDistributionsrc/connectors/raydium/raydium.utils.tscomputeRaydiumBinDistributionfunctionsrc/connectors/raydium/schemas.tsbinCountfield with description and 0–400 rangesrc/connectors/uniswap/clmm-routes/poolInfo.tsbinCount→computeUniswapBinDistributionsrc/connectors/uniswap/uniswap.utils.tscomputeUniswapBinDistribution(used by Uniswap and PancakeSwap)src/connectors/uniswap/schemas.tsbinCountfield with description and 0–400 rangesrc/schemas/clmm-schema.tsbins[]optional onPoolInfoSchema;BinLiquidityfield descriptionsTests
test/connectors/pancakeswap/clmm-routes/pool-info.test.tsbinCount=0→ no bins;binCount=10→ 10 bins;binCount=402→ 400; pool not found → 404test/connectors/pancakeswap/clmm-routes/execute-swap.test.tstest/connectors/orca/clmm-routes/poolInfo.test.tsbinCount=0→ no bins;binCount=10→ 10 bins with correct shape;binCount=402→ 400test/connectors/orca/clmm-routes/quoteSwap.test.tsprice > 1test/connectors/uniswap/clmm-routes/pool-info.test.tsbinCount=0→ no bins;binCount=10→ 10 bins;binCount=402→ 400test/connectors/raydium/clmm-routes/poolInfo.test.tsbinCount=0→ no bins;binCount=8→ bins with correct shape;binCount=402→ 400; pool not found → 404; missingpoolAddress→ 400test/chains/ethereum/handle-transaction-execution.test.tsnullcleanly, noTypeError)Total: 49 tests across 7 suites. All passing.
Tests Performed
Result: 7 suites, 49 tests, 0 failures.
QA Testing Tips
PancakeSwap
execute-swap(BigInt fix)POST to
/connectors/pancakeswap/clmm/execute-swapwith a decimal amount (e.g.amount: 10.5). Previously crashed withTypeError: Cannot mix BigInt and other types. Should now return a transaction hash.PancakeSwap
positions-owned(address-order fix)Verify
baseTokenAddress/quoteTokenAddressare correct for a USDT/WBNB pool on BSC (not WETH-biased). The lower-address token istoken0; the endpoint now derives base/quote from that ordering rather than a WETH special-case.binCountacross connectorsExpected:
binsarray of length 20, each entry withbinId,price,baseTokenAmount,quoteTokenAmount. WithoutbinCountor withbinCount=0,binsmust be absent from the response.Passing
binCount=402must return HTTP 400 (schema maximum is 400, validated before handler).Orca / Meteora BUY price inversion
Pre-fix, the BUY result was
≈ 0.005. Confirm both sides return apricevalue in the same numeric range.Ethereum extended tx polling
On a congested network (or testnet with slow block times), submit an approve transaction and observe gateway logs. You should see:
Previously the gateway returned
nullreceipt immediately at 30 s and bots recorded the tx as failed.Swagger UI verification
Navigate to
http://localhost:15888/docs(dev mode). Confirm:pool-infoendpoints showbinCountwith min0, max400, default0, and description text.BinLiquidityschema in the Models section shows descriptions for all four fields.Developer Notes —
.github/copilot-instructions.md.github/copilot-instructions.mdwas added in this branch and contains identicalcontent to
CLAUDE.md. Both files carry the same agent directives, including anexplicit instruction to keep them in sync with each other.
Why it exists:
VS Code automatically reads
.github/copilot-instructions.mdfor any workspacewhere a GitHub Copilot subscription is active — including when Claude is accessed
via the GitHub Copilot API. This means contributors who work in VS Code get the
same agent context (lenses, coding style, architecture rules) that
CLAUDE.mdprovides to Claude directly, without needing to reference
CLAUDE.mdexplicitlyin every prompt.
How sync is maintained:
Both files contain the directive:
Any agent (Copilot, Claude, Gemini) that edits project rules will read this
directive and update both files in the same commit.
What the lenses add:
The lenses are named, focused review constraints that any AI code-review agent
applies before proposing a solution. Each lens narrows the acceptable answer space
from a specific perspective:
chain/network/chainNetworksemantics consistent; prevents wallet-scoping errorshttpErrorsusagegetSafeWalletFilePath()for all file I/O.mdfiles render-clean (headings, lists, fenced blocks, no bare URLs)descriptionfields, add Swaggerexamples, and updateCLAUDE.md/copilot-instructions.mdoperationId,summary,tags, response schemas matching handler return typesThe lenses were designed so that an agent reviewing a PR sees the same checklist
a human reviewer would apply — reducing back-and-forth on style and convention
issues before a maintainer looks at the code.