> For the complete documentation index, see [llms.txt](https://trench-today.gitbook.io/trench-today/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://trench-today.gitbook.io/trench-today/for-developers/integration-guide.md).

# Integration Guide

## Core Concepts

### Bonding Curve Mechanism

Trench uses a **constant-product bonding curve** (xy=k) with virtual reserves:

* **Virtual Reserves**: Initial liquidity used for price calculation
* **Real Reserves**: Actual ETH and tokens held by the curve
* **Formula**: `virtualNative × virtualToken = k` (constant)

**Key Parameters by chain**:

{% tabs %}
{% tab title="Robinhood" %}

```
virtualQuote:   ~1.712 ETH  (1712328767123287671 wei)
virtualToken:   ~1.074e27   (1073972602739726027397260274 wei)
targetToken:    200,000,000 tokens  (20% of total supply)
totalSupply:    1,000,000,000 tokens (1e27 wei)
graduation:     ~5 ETH gross spend
```

Robinhood reserves are named `Quote` (not `Native`) because the curve is quote-denominated. Native ETH is the live quote token.
{% endtab %}

{% tab title="Ethereum" %}

```
virtualNative:  ~2.009 ETH  (2009158000000000000 wei)
virtualToken:   ~1.068e27   (1068000000000000000000000000 wei)
targetToken:    200,000,000 tokens  (20% of total supply)
totalSupply:    1,000,000,000 tokens (1e27 wei)
graduation:     ~6 ETH gross spend
```

{% endtab %}

{% tab title="MegaETH" %}

```
virtualNative:  ~2.027 ETH  (2026585820895522388 wei)
virtualToken:   ~1.099e27   (1098507462686567164179104478 wei)
targetToken:    200,000,000 tokens  (20% of total supply)
totalSupply:    1,000,000,000 tokens (1e27 wei)
graduation:     ~5.5 ETH gross spend
```

{% endtab %}
{% endtabs %}

**Price Evolution**:

* Initial price is determined by virtual reserves
* As users buy: ETH reserves ↑, token reserves ↓ → price increases
* As users sell: ETH reserves ↓, token reserves ↑ → price decreases

### Token Lifecycle

{% tabs %}
{% tab title="Robinhood" %}

```
Created → Trading (Bonding Curve) → Migrating (Target Reached) → Listed (Uniswap V4)
```

| Stage     | Condition              | Transfer Mode                             |
| --------- | ---------------------- | ----------------------------------------- |
| Created   | Token deployed         | `restricted` (1) — only via TrenchManager |
| Trading   | Buying/selling active  | `restricted` (1)                          |
| Migrating | 200M tokens sold       | `restricted` (1)                          |
| Listed    | Migrated to Uniswap V4 | `free` (0) — free transfers               |

Robinhood tokens use a **two-state** mode (`0 = free`, `1 = restricted`) rather than MegaETH/Ethereum's three-state model. A restricted transfer reverts with `"Token: restricted"`.

Since the **V4 upgrade (2026-07-13)**, new tokens graduate to **Uniswap V4**; the graduation LP is locked in TrenchPositionLocker and post-graduation swap fees are taken by the V4 fee hook. Tokens that graduated earlier remain listed on Uniswap V3.
{% endtab %}

{% tab title="Ethereum" %}

```
Created → Trading (Bonding Curve) → Migrating (Target Reached) → Listed (Uniswap V2)
```

| Stage        | Condition              | Transfer Mode                                       |
| ------------ | ---------------------- | --------------------------------------------------- |
| Created      | Token deployed         | `MODE_TRANSFER_CONTROLLED` (2) — only TrenchManager |
| Trading      | Buying/selling active  | `MODE_TRANSFER_CONTROLLED` (2)                      |
| Migrating    | 200M tokens sold       | `MODE_TRANSFER_CONTROLLED` (2)                      |
| Listed       | Migrated to Uniswap V2 | `MODE_NORMAL` (0) — free transfers                  |
| {% endtab %} |                        |                                                     |

{% tab title="MegaETH" %}

```
Created → Trading (Bonding Curve) → Migrating (Target Reached) → Listed (Kumbaya V3)
```

| Stage         | Condition              | Transfer Mode                                       |
| ------------- | ---------------------- | --------------------------------------------------- |
| Created       | Token deployed         | `MODE_TRANSFER_CONTROLLED` (2) — only TrenchManager |
| Trading       | Buying/selling active  | `MODE_TRANSFER_CONTROLLED` (2)                      |
| Migrating     | 200M tokens sold       | `MODE_TRANSFER_CONTROLLED` (2)                      |
| Listed        | Migrated to Kumbaya V3 | `MODE_NORMAL` (0) — free transfers                  |
| {% endtab %}  |                        |                                                     |
| {% endtabs %} |                        |                                                     |

### Fee Model

**Protocol fee (fixed)**: 1.25% on every trade. Split 24% to token creator, 76% to protocol.

**Platform fee (optional)**: Available via `buyWithFee` / `sellWithFee`. Up to 5%. Paid to an address you specify.

**Buy flow**:

```
Platform fee  = amountIn × buyFeeRate / feeDenominator  → buyFeeReceiver
Protocol fee  = (amountIn − platform fee) × 1.25%  → FeeVault
Curve input   = amountIn − platform fee − protocol fee
```

**Sell flow**:

```
Curve output  = calculated from bonding curve
Protocol fee  = curve output × 1.25%  → FeeVault
Platform fee  = curve output × sellFeeRate / feeDenominator  → sellFeeReceiver
User receives = curve output − protocol fee − platform fee
```

{% hint style="info" %}
The fee denominator differs by chain: Ethereum and Robinhood use `10,000`; MegaETH uses `1,000,000,000` (1e9). A 0.5% platform fee is `50` on Ethereum/Robinhood and `5,000,000` on MegaETH. On Robinhood the protocol trade fee is **1%** (not 1.25%) and the platform-fee parameter is named `extraFeeRate` / `extraFeeReceiver`.
{% endhint %}

### Math Model

The bonding curve uses the **constant-product** formula:

```
k = virtualNative × virtualToken  (constant)
```

**Buy** — purchasing with `amountIn` ETH:

```
newReserveIn  = virtualNative + amountIn
newReserveOut = ceil(k / newReserveIn)
amountOut     = virtualToken − newReserveOut
```

**Sell** — selling `amountIn` tokens:

```
newReserveOut = virtualToken + amountIn
newReserveIn  = ceil(k / newReserveOut)
amountOut     = virtualNative − newReserveIn
```

**Current price** (ETH per token):

```
price = virtualNative / virtualToken
```

***

## Integration Patterns

### Simple Buy/Sell

{% tabs %}
{% tab title="Robinhood" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20 {
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

interface ITrenchManager {
    function buy(uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline)
        external payable returns (uint256);
    function sell(uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline)
        external returns (uint256);
    function previewBuy(address token, uint256 amountIn)
        external view returns (uint256 amountOut, uint256 fee);
}

contract SimpleTradingBot {
    // Robinhood uses a single TrenchManager (no V2/V3 suffix)
    ITrenchManager constant MANAGER =
        ITrenchManager(0x77dC6f6361b7b99456FC3761ce5b7ddA80d83f9d);

    function buyWithSlippage(address token, uint256 ethAmount) external payable {
        require(msg.value == ethAmount, "ETH mismatch");

        (uint256 expectedTokens, ) = MANAGER.previewBuy(token, ethAmount);
        uint256 minTokens = expectedTokens * 99 / 100; // 1% slippage

        MANAGER.buy{value: ethAmount}(
            ethAmount,
            minTokens,
            token,
            msg.sender,
            block.timestamp + 300
        );
    }

    function sellWithSlippage(address token, uint256 tokenAmount) external {
        // meme token is `restricted` pre-graduation — must approve MANAGER and route through sell()
        IERC20(token).transferFrom(msg.sender, address(this), tokenAmount);
        IERC20(token).approve(address(MANAGER), tokenAmount);

        MANAGER.sell(
            tokenAmount,
            0, // set proper minOut in production
            token,
            msg.sender,
            block.timestamp + 300
        );
    }
}
```

{% hint style="info" %}
Robinhood quotes buys with `previewBuy(token, amountIn) → (amountOut, fee)` — a two-return helper — rather than MegaETH/Ethereum's `quoteBuyWithFee`. Tokens are quoted in native ETH, funded via `msg.value`.
{% endhint %}
{% endtab %}

{% tab title="Ethereum" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20 {
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

interface ITrenchManagerV2 {
    function buy(uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline)
        external payable returns (uint256);
    function sell(uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline)
        external returns (uint256);
    function quoteBuyWithFee(uint256 amountIn, address token, uint256 buyFeeRate)
        external view returns (uint256, uint256, uint256, uint256, uint256, uint256);
}

contract SimpleTradingBot {
    ITrenchManagerV2 constant MANAGER =
        ITrenchManagerV2(0x974B2d86d6353c62f19110127aF1A5df4c6370f0);

    function buyWithSlippage(address token, uint256 ethAmount) external payable {
        require(msg.value == ethAmount, "ETH mismatch");

        (uint256 expectedTokens, , , , ,) = MANAGER.quoteBuyWithFee(ethAmount, token, 0);
        uint256 minTokens = expectedTokens * 99 / 100; // 1% slippage

        MANAGER.buy{value: ethAmount}(
            ethAmount,
            minTokens,
            token,
            msg.sender,
            block.timestamp + 300
        );
    }

    function sellWithSlippage(address token, uint256 tokenAmount) external {
        IERC20(token).transferFrom(msg.sender, address(this), tokenAmount);
        IERC20(token).approve(address(MANAGER), tokenAmount);

        MANAGER.sell(
            tokenAmount,
            0, // set proper minOut in production
            token,
            msg.sender,
            block.timestamp + 300
        );
    }
}
```

{% endtab %}

{% tab title="MegaETH" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20 {
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function balanceOf(address account) external view returns (uint256);
}

interface ITrenchManagerV3 {
    function buy(uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline)
        external payable returns (uint256);
    function sell(uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline)
        external returns (uint256);
    function quoteBuyWithFee(uint256 amountIn, address token, uint256 buyFeeRate)
        external view returns (uint256, uint256, uint256, uint256, uint256, uint256);
}

contract SimpleTradingBot {
    ITrenchManagerV3 constant MANAGER =
        ITrenchManagerV3(0x2978E15501C792152602eC85c299083aa61b1bd4);

    function buyWithSlippage(address token, uint256 ethAmount) external payable {
        require(msg.value == ethAmount, "ETH mismatch");

        (uint256 expectedTokens, , , , ,) = MANAGER.quoteBuyWithFee(ethAmount, token, 0);
        uint256 minTokens = expectedTokens * 99 / 100; // 1% slippage

        MANAGER.buy{value: ethAmount}(
            ethAmount,
            minTokens,
            token,
            msg.sender,
            block.timestamp + 300
        );
    }

    function sellWithSlippage(address token, uint256 tokenAmount) external {
        IERC20(token).transferFrom(msg.sender, address(this), tokenAmount);
        IERC20(token).approve(address(MANAGER), tokenAmount);

        MANAGER.sell(
            tokenAmount,
            0, // set proper minOut in production
            token,
            msg.sender,
            block.timestamp + 300
        );
    }
}
```

{% endtab %}
{% endtabs %}

### Platform Fee Integration

Collect a fee on every trade routed through your platform.

{% tabs %}
{% tab title="Robinhood" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface ITrenchManager {
    function buyWithFee(
        uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline,
        uint256 extraFeeRate, address extraFeeReceiver
    ) external payable returns (uint256);

    function sellWithFee(
        uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline,
        uint256 extraFeeRate, address extraFeeReceiver
    ) external returns (uint256);
}

contract PlatformIntegration {
    ITrenchManager constant MANAGER =
        ITrenchManager(0x77dC6f6361b7b99456FC3761ce5b7ddA80d83f9d);

    address public platformTreasury;
    // Robinhood fee denominator is 10,000; 0.5% = 50 (max 500 = 5%)
    uint256 public constant PLATFORM_FEE_RATE = 50;

    constructor(address _treasury) {
        platformTreasury = _treasury;
    }

    function platformBuy(address token, uint256 minTokens) external payable returns (uint256) {
        return MANAGER.buyWithFee{value: msg.value}(
            msg.value, minTokens, token, msg.sender,
            block.timestamp + 300,
            PLATFORM_FEE_RATE, platformTreasury
        );
    }

    function platformSell(address token, uint256 tokenAmount, uint256 minETH) external returns (uint256) {
        IERC20(token).transferFrom(msg.sender, address(this), tokenAmount);
        IERC20(token).approve(address(MANAGER), tokenAmount);
        return MANAGER.sellWithFee(
            tokenAmount, minETH, token, msg.sender,
            block.timestamp + 300,
            PLATFORM_FEE_RATE, platformTreasury
        );
    }
}
```

Fee breakdown for a 1 ETH buy with 0.5% extra fee (Robinhood protocol fee is **1%**):

```
Extra fee (0.5%):     0.005 ETH  → platformTreasury
Protocol fee:         0.00995 ETH → FeeVault (1% of 0.995 ETH)
Curve input:          0.98505 ETH → BondingCurve
```

{% endtab %}

{% tab title="Ethereum" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface ITrenchManagerV2 {
    function buyWithFee(
        uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline,
        uint256 buyFeeRate, address buyFeeReceiver
    ) external payable returns (uint256);

    function sellWithFee(
        uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline,
        uint256 sellFeeRate, address sellFeeReceiver
    ) external returns (uint256);
}

contract PlatformIntegration {
    ITrenchManagerV2 constant MANAGER =
        ITrenchManagerV2(0x974B2d86d6353c62f19110127aF1A5df4c6370f0);

    address public platformTreasury;
    uint256 public constant PLATFORM_FEE_RATE = 50; // 0.5% (50/10000)

    constructor(address _treasury) {
        platformTreasury = _treasury;
    }

    function platformBuy(address token, uint256 minTokens) external payable returns (uint256) {
        return MANAGER.buyWithFee{value: msg.value}(
            msg.value, minTokens, token, msg.sender,
            block.timestamp + 300,
            PLATFORM_FEE_RATE, platformTreasury
        );
    }

    function platformSell(address token, uint256 tokenAmount, uint256 minETH) external returns (uint256) {
        IERC20(token).transferFrom(msg.sender, address(this), tokenAmount);
        IERC20(token).approve(address(MANAGER), tokenAmount);
        return MANAGER.sellWithFee(
            tokenAmount, minETH, token, msg.sender,
            block.timestamp + 300,
            PLATFORM_FEE_RATE, platformTreasury
        );
    }
}
```

Fee breakdown for a 1 ETH buy with 0.5% platform fee:

```
Platform fee (0.5%):  0.005 ETH  → platformTreasury
Protocol fee:         0.012 ETH  → FeeVault (1.25% of 0.995 ETH)
Curve input:          0.983 ETH  → BondingCurve
```

{% endtab %}

{% tab title="MegaETH" %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface ITrenchManagerV3 {
    function buyWithFee(
        uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline,
        uint256 buyFeeRate, address buyFeeReceiver
    ) external payable returns (uint256);

    function sellWithFee(
        uint256 amountIn, uint256 amountOutMin, address token, address to, uint256 deadline,
        uint256 sellFeeRate, address sellFeeReceiver
    ) external returns (uint256);
}

contract PlatformIntegration {
    ITrenchManagerV3 constant MANAGER =
        ITrenchManagerV3(0x2978E15501C792152602eC85c299083aa61b1bd4);

    address public platformTreasury;
    // MegaETH fee denominator is 1e9; 0.5% = 5,000,000
    uint256 public constant PLATFORM_FEE_RATE = 5_000_000;

    constructor(address _treasury) {
        platformTreasury = _treasury;
    }

    function platformBuy(address token, uint256 minTokens) external payable returns (uint256) {
        return MANAGER.buyWithFee{value: msg.value}(
            msg.value, minTokens, token, msg.sender,
            block.timestamp + 300,
            PLATFORM_FEE_RATE, platformTreasury
        );
    }

    function platformSell(address token, uint256 tokenAmount, uint256 minETH) external returns (uint256) {
        IERC20(token).transferFrom(msg.sender, address(this), tokenAmount);
        IERC20(token).approve(address(MANAGER), tokenAmount);
        return MANAGER.sellWithFee(
            tokenAmount, minETH, token, msg.sender,
            block.timestamp + 300,
            PLATFORM_FEE_RATE, platformTreasury
        );
    }
}
```

Fee breakdown for a 1 ETH buy with 0.5% platform fee:

```
Platform fee (0.5%):  0.005 ETH  → platformTreasury
Protocol fee:         0.012 ETH  → FeeVault (1.25% of 0.995 ETH)
Curve input:          0.983 ETH  → BondingCurve
```

{% endtab %}
{% endtabs %}

### Batch Price Query

```solidity
interface IBondingCurve {
    function getVirtualReserves() external view returns (uint256, uint256);
    function realNativeReserves() external view returns (uint256);
    function realTokenReserves()  external view returns (uint256);
    function migrating()          external view returns (bool);
}

interface ITrenchManager {
    function curves(address token) external view returns (address);
}

contract PriceAggregator {
    ITrenchManager public immutable manager;

    constructor(address _manager) {
        manager = ITrenchManager(_manager);
    }

    struct TokenPrice {
        address token;
        uint256 pricePerToken; // wei per token (1e18 = 1 ETH/token)
        uint256 realNative;
        uint256 realToken;
        uint256 virtualNative;
        uint256 virtualToken;
        bool migrating;
    }

    function getBatchPrices(address[] calldata tokens)
        external view returns (TokenPrice[] memory prices)
    {
        prices = new TokenPrice[](tokens.length);
        for (uint256 i = 0; i < tokens.length; i++) {
            address curveAddr = manager.curves(tokens[i]);
            if (curveAddr == address(0)) continue;

            IBondingCurve curve = IBondingCurve(curveAddr);
            (uint256 vNative, uint256 vToken) = curve.getVirtualReserves();

            prices[i] = TokenPrice({
                token: tokens[i],
                pricePerToken: (vNative * 1e18) / vToken,
                realNative: curve.realNativeReserves(),
                realToken: curve.realTokenReserves(),
                virtualNative: vNative,
                virtualToken: vToken,
                migrating: curve.migrating()
            });
        }
    }
}
```

Deploy this with the appropriate `TrenchManager` address for the chain you're targeting.

### Event Monitoring (Off-Chain)

{% tabs %}
{% tab title="Robinhood" %}

```javascript
const { ethers } = require("ethers");

const MANAGER_ADDRESS = "0x77dC6f6361b7b99456FC3761ce5b7ddA80d83f9d";
const provider = new ethers.JsonRpcProvider(RPC_URL); // request RPC from the team
const manager = new ethers.Contract(MANAGER_ADDRESS, ABI, provider);

// New token launches — note the `quote` field (address(0) = ETH)
manager.on("TokenCreate", (creator, curve, token, quote, name, symbol, timestamp, tokenURI) => {
    console.log(`New token: ${name} (${symbol}) at ${token}, quote ${quote}`);
});

// Migration target reached
manager.on("LimitReach", (token) => {
    console.log(`${token} ready for Uniswap V4 migration`);
});

// Migration to Uniswap V4 complete — pool identified by poolId (bytes32), not a pool address
manager.on("V4Listing", (token, poolId, positionIds, quoteAmount, tokenAmount, listingFee) => {
    console.log(`${token} migrated to Uniswap V4 pool ${poolId}`);
});

// Real-time price from Sync events (capital S; quote-denominated reserves)
manager.on("Sync", (token, realQuote, realToken, virtualQuote, virtualToken) => {
    // reserves are in ETH wei (18 decimals)
    const price = (BigInt(virtualQuote) * BigInt(1e18)) / BigInt(virtualToken);
    console.log(`Price update for ${token}: ${ethers.formatEther(price)} ETH/token`);
});

// Post-graduation swap fees settle per swap via the V4 fee hook (no claim step)
const HOOK_ADDRESS = "0x31200554eCA1EFf6d130dbeC7975aFA1234b60CC";
const hook = new ethers.Contract(HOOK_ADDRESS, HOOK_ABI, provider);
hook.on("SwapFeeCharged", (token, poolId, quoteToken, feeBase, totalFee, devShare) => {
    console.log(`${token} swap fee ${totalFee}, paid to dev ${devShare}`);
});
```

{% hint style="info" %}
Robinhood event names and fields differ: the price event is `Sync` (capital S) with `Quote`-named reserves, `TokenCreate` carries an extra `quote` field, and — since the V4 upgrade — graduation emits **`V4Listing`** (pool identified by `poolId`, a `bytes32`) rather than `Listing`. Tokens graduated before the upgrade emitted the old `Listing` (Uniswap V3) event.
{% endhint %}
{% endtab %}

{% tab title="Ethereum" %}

```javascript
const { ethers } = require("ethers");

const MANAGER_ADDRESS = "0x974B2d86d6353c62f19110127aF1A5df4c6370f0";
const manager = new ethers.Contract(MANAGER_ADDRESS, ABI, provider);

// New token launches
manager.on("TokenCreate", (creator, curve, token, name, symbol) => {
    console.log(`New token: ${name} (${symbol}) at ${token}`);
});

// Migration target reached
manager.on("LimitReach", (token) => {
    console.log(`${token} ready for Uniswap V2 migration`);
});

// Real-time price from sync events
manager.on("sync", (token, realNative, realToken, virtualNative, virtualToken) => {
    const price = (BigInt(virtualNative) * BigInt(1e18)) / BigInt(virtualToken);
    console.log(`Price update for ${token}: ${ethers.formatEther(price)} ETH/token`);
});

// Query historical events
const currentBlock = await provider.getBlockNumber();
const events = await manager.queryFilter(
    manager.filters.TokenCreate(),
    currentBlock - 7200, // ~24 hours
    currentBlock
);
```

{% endtab %}

{% tab title="MegaETH" %}

```javascript
const { ethers } = require("ethers");

const MANAGER_ADDRESS = "0x2978E15501C792152602eC85c299083aa61b1bd4";
const RPC_URL = "https://mainnet.megaeth.com/rpc";
const provider = new ethers.JsonRpcProvider(RPC_URL);
const manager = new ethers.Contract(MANAGER_ADDRESS, ABI, provider);

// New token launches
manager.on("TokenCreate", (creator, curve, token, name, symbol, launchTime, tokenURI) => {
    console.log(`New token: ${name} (${symbol}) at ${token}`);
});

// Migration target reached
manager.on("LimitReach", (token) => {
    console.log(`${token} ready for Kumbaya V3 migration`);
});

// Full migration complete (V3)
manager.on("V3Listing", (curve, token, pool, tokenId) => {
    console.log(`${token} migrated to Kumbaya V3 pool ${pool}`);
});

// Real-time price from sync events
manager.on("sync", (token, realNative, realToken, virtualNative, virtualToken) => {
    const price = (BigInt(virtualNative) * BigInt(1e18)) / BigInt(virtualToken);
    console.log(`Price update for ${token}: ${ethers.formatEther(price)} ETH/token`);
});
```

{% endtab %}
{% endtabs %}

***

## Security Checklist

### Slippage protection

Always set `amountOutMin`. Quote first, then apply tolerance.

```solidity
(uint256 expected, , , , ,) = manager.quoteBuyWithFee(amountIn, token, feeRate);
uint256 minOut = expected * 99 / 100; // 1% tolerance
manager.buy{value: amountIn}(amountIn, minOut, token, msg.sender, deadline);
```

### Deadline

Always set a deadline. `0` means no expiry — a stuck transaction could execute at an unexpected price.

```solidity
block.timestamp + 300 // 5-minute deadline
```

### Gwei alignment (sell only — Ethereum & MegaETH)

On Ethereum and MegaETH, sell `amountIn` must satisfy `amountIn % 1e9 == 0`. Round down before selling. Robinhood has no such requirement.

```solidity
uint256 aligned = (amount / 1e9) * 1e9;
```

### Approval management

Approve the exact amount, not `type(uint256).max`.

```solidity
IERC20(token).approve(address(MANAGER), amountToSell);
```

### Migration check

After migration, the bonding curve is closed. Check before acting.

```solidity
address curve = manager.curves(token);
require(!IBondingCurve(curve).migrated(), "Token already graduated");
```

### Token mode

Pre-graduation tokens cannot be moved directly between EOAs — only TrenchManager can. Do not attempt direct transfers before graduation. The mode encoding differs by chain: Ethereum/MegaETH use `MODE_TRANSFER_CONTROLLED` (2); Robinhood uses `restricted` (1) and reverts with `"Token: restricted"`.

***

## Gas Estimates

| Operation                        | Gas    | ETH at 20 Gwei |
| -------------------------------- | ------ | -------------- |
| `createCurve`                    | \~500k | \~0.010 ETH    |
| `buy`                            | \~150k | \~0.003 ETH    |
| `buyWithFee`                     | \~180k | \~0.0036 ETH   |
| `sell`                           | \~120k | \~0.0024 ETH   |
| `sellWithFee`                    | \~150k | \~0.003 ETH    |
| `quoteBuyWithFee` / `previewBuy` | \~50k  | free (view)    |

*Estimates vary with network conditions and token state. On MegaETH, gas costs are significantly lower due to the chain's architecture. Robinhood is an Arbitrum Orbit L2 — gas is priced in ETH and typically far below Ethereum mainnet.*

***

## FAQ

**Can I buy directly from the BondingCurve contract?** No. All trades must go through TrenchManager (V2 on Ethereum, V3 on MegaETH, the single `TrenchManager` on Robinhood).

**What happens if I send ETH directly to TrenchManager?** It will revert. ETH must arrive via `buy()` or `buyWithFee()`.

**How is Robinhood different from the other chains?** Robinhood is a single-layer launchpad — users call `TrenchManager` directly, with no aggregation or vault layer. Tokens are quoted in native ETH; curve reserves are named `Quote` rather than `Native`, and factory reads take a `quote` argument (`getConfig(quote)` — pass `address(0)` for ETH). The protocol trade fee is **1%** (dev 30% / protocol 70%), the listing fee is **2%**, buy quoting uses `previewBuy`, and there is no Gwei-alignment requirement on sells.

**Can I remove liquidity after graduation?** On Ethereum: no — LP tokens are burned to `address(0)`, liquidity is permanently locked, and no one collects LP fees. On MegaETH: the LP NFT (Kumbaya V3 full-range position) is held by the protocol's LP receiver wallet. Liquidity cannot be removed by token creators or traders. The Kumbaya V3 pool charges a **0.01% fee** on every post-graduation swap; those fees accrue to the LP position held by the protocol. On Robinhood (V4): graduation creates a Uniswap **V4** full-range position whose LP NFT is locked in the **TrenchPositionLocker** (1-year timelock); liquidity cannot be removed by creators or traders. The V4 pool's own LP fee is `0` — instead the fee hook takes **1%** on the quote side of every swap and splits it (see below). Legacy graduates (pre-2026-07-13) remain on Uniswap V3 (fee tier 1%) with their LP NFT held by the LPFeeSplitter.

**Do devs earn after graduation on Robinhood?** Yes. On the V4 pools, the **TrenchV4FeeHook** takes 1% on the quote side of every swap and pays the dev share (default **60%**, in `devShareRate`) **directly to the creator on each swap — there is no claim step**; the remaining 40% goes to the treasury. This is separate from the on-curve `FeeVault` (dev 30% of the 1% trade fee, claimed via `devClaim`). A dev earns from both. (Legacy V3 graduates still use the older `LPFeeSplitter.claim(creator)` model — booked credits plus uncollected pending × `devShareBps`; that path is unchanged for those tokens.)

**Why does sell require Gwei alignment?** Internal precision requirement on Ethereum and MegaETH. Round down: `(amount / 1e9) * 1e9`. Robinhood has no such requirement.

**What is the maximum platform fee?** 5% on all chains. Exceeding it reverts with `ERR_BUY_FEE_RATE` / `ERR_SELL_FEE_RATE` (Ethereum/MegaETH), or the `extraFeeRate` bound on Robinhood.

**How do I detect when a token graduates?** Listen for the `LimitReach` event, or poll `IBondingCurve(curve).migrating()`. On MegaETH, listen for `V3Listing`; on Robinhood, listen for **`V4Listing`** to confirm migration to Uniswap V4 (legacy graduates emitted `Listing` for their V3 migration).

**What DEX does graduation target?** Ethereum → Uniswap V2. MegaETH → Kumbaya V3 (full-range position, fee tier 0.01%). Robinhood → Uniswap **V4** for new tokens (full-range position, LP fee 0, 1% quote-side hook fee); tokens graduated before 2026-07-13 remain on Uniswap V3 (fee tier 1%).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://trench-today.gitbook.io/trench-today/for-developers/integration-guide.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
