What Weir is

Weir is a page, not a protocol. It builds standard Uniswap v3 transactions in your browser for the tokenized-stock pools on Robinhood Chain, and your wallet sends them. Weir has no contract, no admin key, no fee and no custody: every position is minted straight to your address as a Uniswap v3 NFT, and the whole transaction builder is one file you can read, js/uni.js.

The transactions

Deposit: one call to SwapRouter02

multicall(deadline, [...]) on Uniswap's SwapRouter02 at 0xCaf681a66D020601342297493863E78C959E5cb2, with these steps in order:

exactInputSingle(USDG → stock, amountIn = the part to swap, recipient = the router itself, amountOutMinimum)
pull(USDG, the rest)
approveMax(token0) · approveMax(token1)          // lets the position manager take the router's balances
mint(token0, token1, fee, tickLower, tickUpper, amount0Min, amount1Min, recipient = you)
sweepToken(token0, 0, you) · sweepToken(token1, 0, you)   // any change comes straight back

How much to swap is solved from the band and the pool fee, so that what is left is in the proportion the band needs at today's price. Before you sign, the app runs this exact transaction against the live pool and sets the floors from that run: the swap must return at least 99.5% of it, and the position must take at least 99% of each amount, or Uniswap refuses the whole thing.

Collect fees

NonfungiblePositionManager.collect(tokenId, recipient = you, max, max)

Withdraw

NonfungiblePositionManager.multicall([
  decreaseLiquidity(tokenId, all of it, amount0Min, amount1Min, deadline),
  collect(tokenId, recipient = you, max, max)
])

Sell the stock

SwapRouter02.multicall(deadline, [exactInputSingle(stock → USDG, amountIn, recipient = you, amountOutMinimum)])

The bands

  • Narrow, ±5%: roughly twice the fee rate of the balanced band, and the price leaves it soonest.
  • Balanced, ±10%: the band every fee rate on this site is measured on.
  • Wide, ±25%: under half the balanced rate, rarely left.
  • Full: every price there is. It never needs moving and earns a few percent of the balanced rate on these pools, because the other liquidity in them is concentrated near the price.

Each band is rounded out to the pool's tick spacing. A position earns only while the price is inside its band; out of it, it holds just one of the two tokens and waits.

Addresses

NonfungiblePositionManager ("Uniswap V3 Positions NFT-V1"): 0x73991a25C818Bf1f1128dEAaB1492D45638DE0D3, 859,253 positions minted.
SwapRouter02: 0xCaf681a66D020601342297493863E78C959E5cb2. Its factory() and positionManager() are checked on every build.
Uniswap v3 factory: 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA, which created every stock/USDG pool listed here.

Tests

tools/e2e.mjs builds every transaction with the same js/uni.js the page ships and runs it against live Robinhood Chain with eth_simulateV1: a funded test wallet deposits $10,000 into the real pool, other traders trade through it, and the wallet collects, withdraws and sells. Each check computes what it expects from balances and the pool, never from the code under test. Nothing is broadcast.

PoolChecksResultWhat the run did
NVDA29passDeposited $10,000; $9,991.22 went into the position; collected, withdrew and sold at block 71334130.
SPCX29passDeposited $10,000; $9,979.68 went into the position; collected, withdrew and sold at block 71334130.
CRCL29passDeposited $10,000; $9,913.41 went into the position; collected, withdrew and sold at block 71334130.

Deliberate bugs

A suite is only worth something if it fails when the code is wrong. Each row is a bug planted in a copy of js/uni.js; the suite must go red on it, on the check named for it. 13/13 caught.

BugWhat it breaksResult
no-sweepleftover stock stays in the router for the next callercaught
nft-to-routerthe position NFT is minted to the router, not the usercaught
swap-everythingthe whole deposit is swapped and most of it handed backcaught
swap-wrong-waythe zap swaps in the wrong directioncaught
band-off-centrethe band is not centred on the pricecaught
withdraw-no-collectwithdraw leaves the tokens and fees owed inside the position managercaught
withdraw-fees-only-onewithdraw collects only token0caught
amount0-rounds-upthe JS position maths overstates token0caught
sale-to-routerthe sale pays the router instead of the usercaught
no-deadlinea deposit that sat in a queue for hours still executescaught
swap-floor-ignoredthe page's swap slippage floor is droppedcaught
mint-floor-ignoredthe page's position slippage floors are droppedcaught
tick-maths-offtwo of TickMath's constants are swappedcaught

Risks

  • Price moves. A position sells the stock as it rises and buys it as it falls; after a large move it is worth less than the two tokens would have been, and the fees may not make up the difference.
  • Out of band. Earns nothing until you move it.
  • The stock tokens. Robinhood can pause any stock token, block an address or burn from it.
  • This page. Uniswap's contracts are long-proven; the code that builds your transactions is new and unaudited. Your wallet shows every call before you sign.