Repository navigation
Releases: Conrad-sudo/langchain-uniswap-v2
Release list
v0.5.1 — Badge update
Release v0.5.1
What's Changed
- Documentation & PyPI Improvements: Added status badges to the
README.mdand PyPI project description to display supported Python versions and project licensing.
Badges Added
Full Changelog: https://github.com/Conrad-sudo/langchain-uniswap-v2/commits/v0.5.1
v0.5.0 — gas_estimated moves onto the plan
One shape change, in the EOA path only. calls mode is untouched.
Breaking
gas_estimatedno longer appears inside each transaction dict. It reaches you as
plan["gas_estimated"]— a list of one bool per transaction, index for index with
plan["transactions"], andNonein calls mode, where nothing is estimated.
Why
A transaction dict now holds transaction fields and nothing else, so it signs exactly as
returned. Previously eth_account rejected it outright:
plan = tools["swap_exact_tokens_for_tokens"].invoke({...})
acct.sign_transaction(plan["transactions"][0])
# 0.4.0: TypeError: Unknown kwargs: ['gas_estimated']
# 0.5.0: signsThat broke the first thing every EOA consumer does, and the traceback pointed at
eth_account rather than at this package. The README worked around it in prose, telling
callers to pop the key before signing. "Did this limit come from a live estimate" is
provenance about the plan, not a field an Ethereum transaction has, so it now travels
beside the transactions instead of inside them.
Migrating
| behaviour | 0.4.0 | 0.5.0 |
|---|---|---|
acct.sign_transaction(plan["transactions"][0]) |
TypeError: Unknown kwargs |
signs |
| reading the flag | plan["transactions"][i]["gas_estimated"] |
plan["gas_estimated"][i] |
tx.pop("gas_estimated") in a signing loop |
required | KeyError — delete the line |
| calls mode | unaffected | unaffected |
The tolerant tx.pop("gas_estimated", None) keeps working as written; the strict form now
raises and the line should simply be removed.
Verification
Checked against a mainnet fork with an [approve, swap] plan, which exercises both flag
states: gas_estimated == [True, False], both transactions signed unmodified, and both
executed — approve 55,558 gas against a 69,921 limit, swap 127,760 against the 300,000
DEFAULT_GAS fallback. The fallback that a False flag reports is comfortably sufficient
in practice. 222 tests.
v0.4.0 — native_wrapped on every chain, quote-based route selection
No API change: nothing renamed, no signature removed, no return shape altered. Existing code keeps working as written.
Added
native_wrappedis now populated for all supported chains (previouslyNoneon 10 of 13), enabling the native-asset swap and liquidity tools and wrapped-native multi-hop routing on Optimism, Polygon, Base, Arbitrum, Avalanche, Unichain, Monad, X Layer, World Chain and Zora. Every value is verified equal to the chain router's ownWETH().scripts/verify_native_wrapped.pyre-checks the whole registry against the live chains — router bytecode,WETH(),factory(), plus each wrapped native's symbol and decimals. Runs weekly in CI; unreachable endpoints skip, mismatches fail.
Fixed
for_chain()no longer raisesTypeErrorwhen a caller overridesrouter_address,factory_addressornative_wrapped_address.- Route selection no longer prefers a direct pair holding negligible reserves over a wrapped-native route that quotes better. Both candidates are quoted and the better fill wins; ties go to the direct pool. Previously this could select a materially worse price with no error — measured at 34% worse on a live Avalanche USDC/USDT pair holding under $1 a side, and silent, because
amount_out_minderives from the same quote.
Behaviour changes for existing callers
| 0.3.0 | 0.4.0 | |
|---|---|---|
| eight native-asset tools on 10 of 13 chains | raise ToolException |
build plans |
| token→token pairs with no direct pool, on those chains | raise "no liquidity path" | route through the wrapped native |
| direct pool holding dust, better route available | silently takes the dust pool | takes the better route |
for_chain(cid, native_wrapped_address=...) |
TypeError |
override applied |
v0.3.0 — Write tools now return execution plans, for EOAs and smart-contract wallets
Breaking change
Every write tool now returns an execution plan instead of a bare unsigned transaction dict:
{
"calls": [...], # ordered, account-agnostic (to, value, data) list
"transactions": [...] | None, # EOA mode only; same calls, signable, nonces assigned
"chain_id": 1,
"summary": {...}, # amounts in whole units, safe to show a user
}calls works directly with an ERC-4337/ERC-7579 smart-contract wallet's own batch executor. transactions (rendered by default, tx_mode="eoa") is the same calls as unsigned, signable EOA transactions with sequential nonces already assigned. tx_mode="calls" returns calls only, with zero nonce/gas/fee RPC calls.
Fixed
- The core defect this release exists for: every allowance-dependent write tool used to fail at build time, because
eth_estimateGasreverts when the approval it depends on isn't mined yet. Plans now build fine — the call that can't be simulated falls back to a static per-role gas limit (gas_estimated: False) instead of raising. _build_pathused to always route token→token swaps through the wrapped-native token, even when a liquid direct pair existed (paying the 0.3% fee twice). Direct pairs are now preferred when they have liquidity.approve_token's "pass a very large number for unlimited" advice could raise a raw, unformatted web3 exception for amounts that overflowuint256. Replaced withunlimited=True, which approves2**256 - 1exactly.
Added
tx_mode,estimate_gas,gas_buffer,default_gas,reset_residual_approvals,preflightconstructor options.- Every write tool includes its own approval call(s) automatically — no more manual
approve_token-first flow. A trailing zero-approval reset is appended where the router may pull less than approved (governed byreset_residual_approvals). recipientparameter on all ten swap/liquidity tools, defaulting tofrom_address.preflightbalance checks (on by default) run before building, raisingToolExceptionnaming the shortfall.DEFAULT_GASexported from the package.
Migration
See the README's Migration section for the full 0.2.0 → 0.3.0 diff.
v0.2.0 — Write tools (unsigned transactions) and balance-sufficiency checks
This release adds write-side capability to the toolkit for the first time, without introducing a signer, session key, or any wallet state — every write tool builds and returns a plain unsigned transaction dict for the caller to sign and submit with their own wallet infrastructure. Nothing in this package ever touches key material. All 5 original read-only tools are unchanged; this is a fully backward-compatible, additive release.
Added — Write tools (11)
Every write tool takes an explicit from_address, derives amountOutMin/amountInMax/equivalent from a live on-chain quote via slippage_bps (default 50 bps), takes deadline_secs (default 600) for on-chain expiry, and accepts an optional nonce override for sequencing multiple unsigned transactions before submitting any of them.
approve_token— unsigned ERC20approve. Always a separate transaction from the swap/deposit it precedes; there's no session-key-style atomic batching to lean on here.swap_exact_tokens_for_tokens,swap_tokens_for_exact_tokensswap_exact_eth_for_tokens,swap_eth_for_exact_tokensswap_exact_tokens_for_eth,swap_tokens_for_exact_ethadd_liquidity,add_liquidity_eth— the paired-token amount is derived from live pool reserves so the deposit matches the current ratioremove_liquidity,remove_liquidity_eth
Added — Balance-sufficiency checks (7)
Read-only tools that answer "does this address hold enough" before a write tool would actually be called, given an explicit owner_address — useful for an agent to check before spending gas building/submitting a transaction that would just revert.
is_token_balance_sufficient,is_native_balance_sufficientis_derived_token_input_sufficient,is_derived_native_input_sufficientis_liquidity_sufficient,is_liquidity_sufficient_ethis_liquidity_removal_sufficient
Changed
UniswapV2Toolkit.get_tools()now returns 23 tools (up from 5), unconditionally — no gating, no constructor changes required for existing callers.pyproject.tomldescription updated to reflect write capability.ruffpinned to an exact version (==0.16.1) in thedevextra, after an unpinnedruff>=0.15caused a CI failure when Ruff 0.16 made Markdown-embedded code-block formatting a stable default — the formatter, unlike the linter, isn't guaranteed stable across versions.
Not included in this release
- No signer, no
signers.py, no wallet abstraction of any kind — deliberately out of scope for this design; see the README's Scope section. - No live/testnet verification of
build_transaction()output yet — write tools are covered by an extensive mocked test suite (138 tests total) but have not yet been exercised against a real chain the way the read-only tools were before v0.1.0.
Full docs: see the README for the complete tool reference and usage examples.
PyPI: https://pypi.org/project/langchain-uniswap-v2/0.2.0/
v0.1.0 — Initial release
Initial public release.
Read-only LangChain tools for querying Uniswap V2 (and Uniswap-V2-shaped fork,
e.g. PancakeSwap) pools — no wallet or ticker registry required.
Tools: get_quote_in, get_quote_out, get_pool_quote, get_lp_amounts,
get_liquidity_token_balance
Built-in chain registry: 13 EVM chains (Ethereum, Arbitrum, Base,
Optimism, Polygon, Avalanche, BSC via PancakeSwap, Unichain, Zora,
World Chain, Monad, X Layer, Sepolia).
📦 PyPI: https://pypi.org/project/langchain-uniswap-v2/0.1.0/