Skip to main content
TradingClient provides liquidity to the Uniswap V3 pools on Flashnet Execution. Mint a position, grow or shrink it, collect fees, or reposition, each as one signed intent that funds from your Spark balance and routes through the Conductor.
These are the Uniswap V3 pools the Conductor wraps on Execution, managed with TradingClient. The Spark-native AMM under Markets is a separate system with its own client.

Configure for liquidity

LP needs more contract addresses than swaps. On TradingConfig: lpGasLimit is optional.
On staging, new TradingClient(execClient, "regtest") includes all of these, so you can skip the explicit config.

How positions work

A position is a Uniswap V3 concentrated-liquidity NFT held by the NonfungiblePositionManager, identified by a tokenId and bounded by two ticks. Four conventions carry across every method:
  • Pass pair tokens sorted: token0 < token1 by lowercase address.
  • The WBTC leg is denominated in wei, not sats (1 sat = 1e10 wei). Convert with satsToWei and weiToSats from @flashnet/sdk.
  • For a BTC-paired pool, use the WBTC address as the BTC leg’s token. The SDK routes to the Conductor’s BTC entry point and funds msg.value.
  • Ticks are standard Uniswap V3 ticks, where price = 1.0001^tick. V3TickMath from @flashnet/sdk converts between prices and ticks.

Funding

LP methods fund the same two ways as swaps. With useAvailableBalance: true, the SDK pulls each leg from your Spark balance and bundles the funding transfers with the Conductor call in one intent. Supply the Spark token id for each ERC20 leg (token0SparkId, token1SparkId); the BTC leg funds from the WBTC slot. ERC20 legs are pulled via Permit2, so each token needs a standing Permit2 approval from your EVM address first:
Without useAvailableBalance, the methods spend balances already on the Execution side.

Mint a position

addLiquidity mints a new position NFT.
For a BTC-paired pool, set one leg’s token to the WBTC address and its amounts in wei. That leg funds from msg.value and takes no Spark token id.

Grow or shrink

increaseLiquidity adds to a position. decreaseLiquidity removes liquidity and withdraws the recovered tokens to Spark.
decreaseLiquidity sends the recovered token0 and token1 to your Spark wallet. sparkRecipient defaults to your identity key.

Collect fees

collectFees sweeps accrued fees to Spark without touching principal.

Reposition

modifyPosition moves a position to a new tick range. It removes all liquidity from the current position, optionally adds capital, and mints a new NFT at the new range.

Read positions

getPosition and listPositions read straight from the NonfungiblePositionManager.
PositionInfo mirrors the NonfungiblePositionManager’s positions() tuple: token0, token1, fee, tickLower, tickUpper, liquidity, tokensOwed0/tokensOwed1, and the fee-growth checkpoints.

What the result tells you

The result carries submission handles and the signed-tx hash, not on-chain outputs. The minted tokenId, the liquidity added, amounts used, and fees collected are knowable only after the intent executes. Read them from the transaction receipt or the Conductor LP events (LiquidityAdded, LiquidityIncreased, LiquidityDecreased, FeesCollected, PositionModified) once the intent reaches INCLUDED_PENDING_FINALITY.

Fund recovery

When an addLiquidity, increaseLiquidity, or modifyPosition call with useAvailableBalance fails after its funding transfers commit, the SDK claws the committed transfers back to your Spark balance and throws StrandedFundingError with a clawbackSummary of what was recovered. This matches the swap round-trip’s behavior. decreaseLiquidity and collectFees have no inbound funding, so they carry no clawback.

Cross-references

  • Swaps trade through the same pools.
  • Conductor is the contract these calls route through.