Some functionality will be degraded until the official mainnet launch on the 9th.
Documentation
Guides

Trading

Every Tartarus token trades in an ordinary Uniswap V4 pool, so any V4-aware router or aggregator can reach it. There is one path for a token's whole life. This page uses UniversalRouter, which is what the Tartarus site uses.

The pool key#

Read it, do not rebuild it:

$ ts
const key = await client.readContract({
  address: FACTORY, abi: factoryAbi, functionName: "poolKeyFor", args: [token],
});
// { currency0, currency1, fee: 0, tickSpacing: 200, hooks: <the Tartarus hook> }

V4 sorts currencies by address. Native HYPE is address(0), so on a HYPE pool it is always currency0 and a buy is zeroForOne: true. With an ERC-20 quote the token can sort either way, so the rule is: a buy is zeroForOne exactly when the quote is currency0.

Quoting#

There are two options, and both simulate through the real hook, so the figure is net of fees.

From the API, which also applies slippage and returns everything you need to build the swap:

$ bash
curl "https://api.tartarus.world/v1/tokens/$TOKEN/quote?side=buy&amount=1&slippageBps=100"

amount is in whole units of what you are spending: quote on a buy, tokens on a sell. The response carries amountRaw, outRaw, minOutRaw, zeroForOne, poolKey, the fee split and priceImpactBps. Pass minOutRaw, not outRaw, as the swap's minimum.

From the chain, with Uniswap's V4Quoter. It is not a view function, so call it with simulateContract:

$ ts
const { result } = await client.simulateContract({
  address: QUOTER, abi: quoterAbi, functionName: "quoteExactInputSingle",
  args: [{ poolKey: key, zeroForOne: true, exactAmount: amountIn, hookData: "0x" }],
});
const [amountOut] = result;

Blocks arrive every few hundred milliseconds, so quote again right before signing.

Swapping#

The router program is V4_SWAP (0x10) running three actions: SWAP_EXACT_IN_SINGLE (0x06), SETTLE_ALL (0x0c) and TAKE_ALL (0x0f).

$ ts
const swapParams = encodeAbiParameters(
  parseAbiParameters("((address,address,uint24,int24,address),bool,uint128,uint128,uint256,bytes)"),
  [[[key.currency0, key.currency1, key.fee, key.tickSpacing, key.hooks],
    zeroForOne, amountIn, minOut, 0n, "0x"]],
);
const settle = encodeAbiParameters(parseAbiParameters("address, uint256"), [inputCurrency, amountIn]);
const take = encodeAbiParameters(parseAbiParameters("address, uint256"), [outputCurrency, minOut]);
const v4Input = encodeAbiParameters(parseAbiParameters("bytes, bytes[]"), ["0x060c0f", [swapParams, settle, take]]);

await wallet.writeContract({
  address: ROUTER, abi: routerAbi, functionName: "execute",
  args: ["0x10", [v4Input], deadline],
  value: inputCurrency === zeroAddress ? amountIn : 0n,
});
Warning
This router build's ExactInputSingleParams has an extra uint256, minHopPriceX36, before hookData. Encoding the older five-field struct fails. Pass 0n. hookData stays empty: the Tartarus hook reads nothing from it.

TAKE_ALL's amount is your slippage bound: the swap reverts rather than deliver less.

  • Buying with HYPE: send amountIn as value. No approvals.
  • Selling, or buying with an ERC-20 quote: two grants first. See Approvals.
  • Selling into HYPE: TAKE_ALL of address(0) pays you native HYPE. There is no wrapping step.

Where the fee comes from#

The hook takes its fee from the unspecified leg of each swap, the side you did not fix.

SwapFee taken inEffect
Exact-in buytokensyou receive fewer tokens
Exact-in sellquoteyou receive less quote
Exact-out buyquoteyou pay more quote
Exact-out selltokensyou pay more tokens

The rate is the same in every case: on exact-out the fee is grossed up, so it is exactly the pool's rate of what you hand over. V4Quoter and the API already account for it. The API's feeCurrency tells you which side it was taken in.

Selling at the floor#

The protocol's liquidity ends at the launch price. If the price is already at the floor, there is no quote to sell into. The API returns fillsNothing: true with an output of zero. V4Quoter reverts with UnexpectedRevertBytes (0x6190b2b0), wrapping NotEnoughLiquidity (0x7a5ed734): the quoter works by reverting on purpose, so its real errors arrive inside that wrapper. Treat this as a normal state and show it to the user instead of an error.

Failure cases#

SymptomCause
AllowanceExpired (0xd81b2f2e)The Permit2 grant is missing, or has expired
InsufficientAllowance (0xf96fb071)The Permit2 grant is smaller than the swap, or was used up by an earlier one
A bare ERC-20 transfer revertThe token never approved Permit2
V4TooLittleReceived (0x8b063d73)Price moved past your minOut. Quote again
TransactionDeadlinePassed (0x5bf6f916)The deadline passed, or your wallet sat on the prompt too long
UnexpectedRevertBytes (0x6190b2b0) from the quoterSelling into the floor, or buying more than the pool holds. The inner error says which
POLLINGElysium · 99901 · Mainnet
--:--:-- UTC