espace-uniswap-lib
v0.2.0
Published
Reusable Uniswap V2/V3 helper library for Conflux eSpace
Maintainers
Readme
espace-uniswap-lib
Utility library for Swappi V2 and vSwap (WallFreeX) V3 on Conflux eSpace.
Chinese documentation: README_ZH.md
Upgrade Notes (0.1.x → 0.2.0)
Breaking changes:
client.v2.SwappiPair(the@uniswap/v2-sdkPairclass) is removed. Useclient.v2.createSwappiPair(tokenA, tokenB, reserve0Raw, reserve1Raw)for the factory equivalent.client.v2.getPair(...)now returns a Pair-shaped object (token0/token1/reserve0/reserve1/liquidityToken/reserveOf/priceOf/token0Price/token1Price/involvesToken) instead of an@uniswap/v2-sdkPairinstance. Methods likegetOutputAmount/getInputAmountare not provided; reimplement them locally if you relied on them.@uniswap/v2-sdk'sPair.getAddressis no longer monkey-patched. If your code depended on that global side effect, switch tocomputePairAddress(...)from this library.AlphaRouteris now constructed with a customv2PoolProvider. If you callclient.v3.findRoute(...)withprotocols: ['V2']or'MIXED', you must also inject a customv2SubgraphProvider— the default one still depends onPair.getAddressand will fail on Conflux.- Testnet
client.v3.findRoute(...)now works (previously failed inside the gas model). Testnetclient.v2.*still fails fast because Swappi V2 is not deployed there.
Migration for most consumers is a no-op — the common paths (findRoute, swapExactInputMulticall, getPair) work as before, just with corrected behavior under npm / yarn / nested-dep installs.
What It Covers
V2/V3exact-in swapsV2path quoting and pair queriesV3routing, quoting, and pool state readsV3liquidity position creation, increase, decrease, and fee collection- ERC20 approvals, balance polling, and multicall helpers
Modules
createClient: builds the current networkprovider, addresses, tokens, and V2/V3 helpersclient.v2:Swappi V2swaps, path search, and pair queriesclient.v3:V3routing, swaps, pool reads, and LP/NFT position helpersclient.utils: approvals, balance queries, multicall helpers, and utility methodsethersProvider: helpers to createprovider/signerconsts: network-agnostic constants and pure helpers
Installation
pnpm add espace-uniswap-libOr:
npm install espace-uniswap-libRequirements:
Node.js >= 20ESM
Quick Start
The example below creates a client, auto-detects mainnet or testnet from the RPC, and swaps 0.01 WCFX to USDT0.
1. Create a client and signer
import {
createClient,
createEthersSigner,
} from "espace-uniswap-lib";
const rpcUrl = process.env.ESPACE_RPC_URL;
const privateKey = process.env.PRIVATE_KEY;
const client = await createClient({
...(rpcUrl ? { rpcUrl } : {}),
logger: console,
});
const signer = createEthersSigner(privateKey, client.provider);2. Execute a V3 multicall swap
import {
parseEther,
} from "espace-uniswap-lib";
const amountInRaw = parseEther("0.01");
const receipt = await client.v3.swapExactInputMulticall(
client.tokens.WCFX9,
client.tokens.USDT0,
amountInRaw,
signer
);
console.log("network:", client.network);
console.log("tx:", receipt.transactionHash);Notes:
createClient(...)acceptsrpcUrl, notprovider- if
rpcUrlis omitted, mainnet is used by default - when
rpcUrlis provided, the library detects mainnet or testnet from on-chainchainId - if
networkis explicitly provided and does not match the actual RPC chain, the call throws - create the signer from
client.providerto avoid network mismatch - swap methods use
50 bpsslippage by default, which means0.5%
If you want to use 1% slippage explicitly, pass options as the last argument:
const receipt = await client.v3.swapExactInputMulticall(
client.tokens.WCFX9,
client.tokens.USDT0,
amountInRaw,
signer,
{ slippageBps: 100 }
);Common APIs
Initialization
createClient(options): create a client bound to a single networkclient.getConfig(): read the full client config snapshotclient.network: current network,mainnetortestnetclient.chainId: current chain IDclient.provider: theethersprovider used by the clientclient.tokens: prebuiltTokeninstances for the current network, such asWCFX9andUSDT0
V2
client.v2.swapToken(tokenIn, tokenOut, amountInRaw, signer, options?): execute an exact-in swap throughSwappi V2client.v2.getBestPath(tokenInAddress, tokenOutAddress, amountInRaw, providerOrSigner): evaluate candidate V2 paths and return the one with the highest quoted outputclient.v2.getPair(tokenA, tokenB, provider): read reserves for a V2 pair and return a Pair-shaped object (token0/token1/reserve0/reserve1/liquidityToken/reserveOf/priceOf/token0Price/token1Price/involvesToken)client.v2.createSwappiPair(tokenA, tokenB, reserve0Raw, reserve1Raw): build the same Pair-shaped object from known reserves without any RPC callclient.v2.getSwappiPairs(provider): scan all pairs from the factory
V3
client.v3.findRoute(tokenIn, tokenOut, amountInRaw, recipient, options?): search aV3route withAlphaRouterclient.v3.swapExactInputSingle(tokenIn, tokenOut, fee, amountInRaw, signer, options?): single-hop swap when the fee tier is already knownclient.v3.swapExactInput(tokenIn, tokenOut, fee, amountInRaw, signer, options?): search a route and callrouter.exactInputclient.v3.swapExactInputMulticall(tokenIn, tokenOut, amountInRaw, signer, options?): search a route and execute withrouter.multicallclient.v3.getPoolInfo(poolContract): read core pool stateclient.v3.getPoolReserveAmounts(pool, provider): query current token balances for a pool
V3 Liquidity
client.v3.mintPosition(tokenA, tokenB, fee, amount0, amount1, tickLower, tickUpper, signer): create a new V3 liquidity positionclient.v3.getPositions(address, provider): read all V3 NFT positions owned by an addressclient.v3.findPosition(tokenA, tokenB, fee, signer): find an existing position by token pair and fee tierclient.v3.addLiquidity(tokenA, tokenB, fee, amount0, amount1, signer): add liquidity to an existing positionclient.v3.removeLiquidity(tokenA, tokenB, fee, signer): remove liquidity from an existing positionclient.v3.collectFees(tokenA, tokenB, fee, signer): collect fees for a position
Utilities
client.utils.approveIfNeeded(token, spender, amount, signer): approve automatically when allowance is insufficientclient.utils.batchErc20Balances(tokens, addresses, provider): query ERC20 balances in batch through multicallclient.utils.batchNativeBalances(addresses, provider): query native balances in batch through multicallfromReadableAmount(amount, decimals): convert a human-readable amount into the on-chain smallest unitparseEther/formatEther/parseUnits/formatUnits: commonethersamount helpers
createClient Options
createClient(...) supports:
network: optional,mainnetortestnetrpcUrl: optional, custom RPC URLaddresses: optional, override the current network address presetbases: optional, override V2 routing base tokenslogger: optional, injectinfo/error/debughooks.onTxMined: optional, async callback after a transaction is mined
Swap Options
Swap-related methods and client.v3.findRoute(...) accept an extra trailing options argument:
slippageBps: optional integer inbps;50means0.5%,100means1%
Notes:
- the default is
50 - the accepted range is
0to9999 - if you want route preview and the actual swap to use the same slippage boundary, pass the same
slippageBpsvalue to both
Current Limitations
swapExactInputMulticalldoes not auto-approve ERC20 input tokens; approveWFX_ROUTERbefore calling ituniswapV2.addLiquidityanduniswapV2.removeLiquidityare exported but not implemented yet- the library no longer monkey-patches
@uniswap/v2-sdk'sPair.getAddress; all V2 pair addresses go throughcomputePairAddress(...)andcreateSwappiPair(...), so the library is safe under nested / duplicated@uniswap/v2-sdkinstalls (npm / yarn / pnpm) getPair()and the injected V2 pool provider return duck-typed Pair-shaped objects instead of@uniswap/v2-sdkPairinstances; methods that the SDKPairclass provides but this object does not (getOutputAmount/getInputAmount) are intentionally out of scope- testnet does not currently provide a complete
Swappi V2preset;client.v2.*fails fast on testnet.client.v3.findRoute(...)on testnet works (the custom V2 pool provider returns an empty accessor, and the gas model falls back to V3 pools) - if you ever need
protocols: ['V2']or'MIXED'for AlphaRouter, you must also inject a customv2SubgraphProvider; the default one still callsPair.getAddressand will fail on Conflux - by default, testnet only switches
RPC,WCFX9,USDT0, andMulticall3; if your environment has matching protocol addresses and you want to enable them, override throughaddressesand validate compatibility yourself
