Documentation
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:
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:
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:
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).
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,
});TAKE_ALL's amount is your slippage bound: the swap reverts rather than deliver less.
- Buying with HYPE: send
amountInasvalue. No approvals. - Selling, or buying with an ERC-20 quote: two grants first. See Approvals.
- Selling into HYPE:
TAKE_ALLofaddress(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.
| Swap | Fee taken in | Effect |
|---|---|---|
| Exact-in buy | tokens | you receive fewer tokens |
| Exact-in sell | quote | you receive less quote |
| Exact-out buy | quote | you pay more quote |
| Exact-out sell | tokens | you 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#
| Symptom | Cause |
|---|---|
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 revert | The 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 quoter | Selling into the floor, or buying more than the pool holds. The inner error says which |