Build
Router and swaps
The swap box finds the best price across Gully Core pools and other venues on the chain. Put it on your page with one line of HTML, or quote and swap from your own code. Everything here trades on the chains where Gully Core is deployed. Gully Chain Testnet trades testnet tokens. See Chains.
One line: the swap box
Paste this into any page. It is the same swap box as the Swap screen, with its own wallet connect. Nothing to install, no key, no React.
<iframe src="https://app.gullycore.xyz/embed/swap" title="Swap on Gully Core" width="420" height="640" style="border:0"></iframe>It opens on a pool with liquidity. To open on your own pair, add ?in=0x…&out=0x… to the address. The zero address is the native coin. A pair with no pool is ignored. theme=light or theme=dark sets the look. The same two addresses work on the Swap screen, so a link can open the app on your market.
The API needs no package and no key to read. Each pool comes back with its full key, its live price and its fee: GET /v1/chains/<chainId>/pools?limit=50&offset=0.
Best price
Every quote compares Gully Core's own pools with the other venues the router covers on that chain, after gas, and shows where the trade will fill. A trade on a Gully Core pool goes through the UniversalRouter. A trade on another venue goes through GullyCoreFillRouter, which fills it there in the same transaction and returns the output to you.
The same swap box is on Trade, on every token page, on every hosted DEX and in the widget.
What a trade costs
| Part | Who sets it | Amount |
|---|---|---|
| Pool fee | The pool (or its hook, on a dynamic-fee pool) | Shown on the quote |
| Core protocol fee | Governance, per pool | at most 0.4% |
| Routing fee | GullyCoreFillRouter, on fills at another venue only | read from the contract |
| On a Gully Core pool | GullyCoreFillRouter | 0 |
| Launch fee and creator tax | The launch, inside the guard's limits | See Launch a token |
The routing fee is read from the contract and is zero on a Gully Core pool so that a Gully Core pool is the cheaper venue when the prices are equal. It is a governed value inside an immutable cap. A decrease is immediate, and nothing applies to a quote already given. The cap and notice period are read from GullyCoreFillRouter (feeBps(), maxFeeBps(), feeNoticeSeconds()).
The fee is charged on what the trade actually spends, never on the output, so an exact-output trade does not fill worse than quoted. Price impact and the fee are shown as separate numbers.
What you pay as a builder
Build on Gully Core from outside Gully Labs and Gully takes a flat 0.30% of every trade on the pools you create, and nothing else. There is no kit split and no share of creator tax. You and your launchpad decide how the rest is shared.
| What | Gully takes |
|---|---|
| Every trade on your pools | 0.30%, set by the fee controller on the shared core |
| Kit split on your launches | None |
| Creator tax on your launches | None |
| The most the fee can ever be | 0.40%, the cap in the core. The Safe may lower a pool's fee, never raise it past the cap |
Gully Core is built on PancakeSwap Infinity's audited core. More on the fee model in Fees.
Approvals and Permit2
- Once per token: an ERC-20 approval of
Permit2, the canonical permit contract at the same address on every chain. - Each swap: a signature that authorises that swap's amount for that router, with a deadline. No new on-chain approval.
- Selling the native coin needs no approval at all.
Paying with the native coin
You can pay with, or receive, the native coin in a pool quoted in its wrapped form (WHYPE, WBNB, WETH). The router wraps and unwraps inside the same transaction. You never hold the wrapped token unless you choose it. The native coin is currency 0x0000…0000 and the wrapped native is an ERC-20. A pool in one is not a pool in the other.
On Anubis the gas coin pays gas only and cannot be sent as a value, so pools there quote in DAI.
Quote
A quote runs the real swap against current state, the pool's hook included, and reverts with the answer. Call it with eth_call. It costs nothing and sends nothing.
getSlot0(poolId) on the pool manager gives a pool's spot state (CL: sqrtPriceX96, tick, protocolFee, lpFee. Bin: activeId, protocolFee, lpFee). For an amount, quote through CLQuoter or BinQuoter. The quoter runs the real swap, hook included, and reverts with the result, so the answer already accounts for whatever the pool's hook takes.
Swap through the UniversalRouter
Swaps on Gully Core pools execute through the UniversalRouter: one INFI_SWAP command carrying the swap action, a settle of the input from the caller and a take of the output. Encode the swap, simulate the exact bytes, then send them.
- The router pulls ERC-20 input through Permit2. The caller approves the token to Permit2 once and grants the router an allowance in Permit2, or signs a permit the plan applies first.
- Native input is sent as
value. - The SDK's
buildSwapCallalso encodes multi-hop routes, Bin pools, wrap and unwrap of the native coin, and an integrator fee. - The SDK's
verifySwapCalldatadecodes router calldata from any source and refuses anything but the swap you asked for.
Router API
Gully Core's Router API quotes across Gully Core pools and the third-party venues it covers on a chain and returns the calldata to sign. A route through a Gully Core pool pays no routing fee. A fill at another venue goes through GullyCoreFillRouter, whose fee is read from the contract on every quote and shown on its own line. It has its own rate limit. Anonymous callers get a small per-IP allowance, and a server sends an API key with the router:quote scope in the X-API-Key header. A chain the router does not serve answers 404.
| Method | Path | Returns |
|---|---|---|
| GET | /v1/chains/:chainId/quote?tokenIn=&tokenOut=&amount=&slippageBps= | The best route, amount out, minimum out, price impact, gas and the routing fee |
| POST | /v1/chains/:chainId/swap | The transaction to sign. Nothing is signed or sent |
| POST | /v1/chains/:chainId/simulate | A transaction simulated, with the fill it would make |
| GET | /v1/chains/:chainId/sources | The venues the router covers on the chain |
| GET | /v1/chains/:chainId/fee-config | The routing fee in force, its cap and notice, read from the contract |
Trading a launch
- The trade fee and any creator tax are taken in the quote currency on buys and sells, and shown on the quote.
- In a launch's first seconds the fee is high and falling: the anti-snipe fee decays over at least 60 seconds.
- While a maximum buy is in force, larger buys and exact-output buys are refused.
- A buy that would run past the end of a CL launch range reverts (
SwapNotFilled). The app sizes buys from a quote.
Details on Launch a token.
What is checked before you sign
- Every transaction is simulated against the current block first. One that would revert is not offered for signing.
- When a route comes from the router API, the app decodes the returned calldata and refuses it unless it is exactly the swap you asked for: your tokens, at most your amount in, the output only to you, your minimum and deadline (
verifySwapCalldatain the SDK). - The minimum you receive is the quote less your slippage tolerance. A fill below it reverts.
What to handle in an integration
- Hooks change the cost of a trade. A pool's hook is
poolKey.hooks. Always price a hooked pool with the quoter, never fromgetSlot0and the fee alone. - Launch pools. A launch pool's guard charges its trade fee and any creator tax itself, in the pool's quote currency, as a hook delta. The pool's own LP fee understates the cost. Read the fee from the guard (
currentFeeParts(poolId),currentTaxRates(poolId)) or from the API'slaunchFeeandlaunchTaxfields. - Dynamic-fee pools. A
feeof0x800000in the key means the hook sets the LP fee. Quote, do not compute. - No fee-on-transfer or rebasing tokens. The Vault credits what it is told was paid. A token that delivers less leaves the settlement short.
Wrong or missing? Tell us at @Gully_Labs.