# trade programmatically

Submit buys and sells directly from code. Works for trading bots, aggregators, or backends that trade on behalf of users.

{% hint style="warning" %}
**You need a funded KUB wallet with a private key (or signer).** Never commit private keys. Use env vars or a secret manager.
{% endhint %}

## Setup

```javascript
import { JsonRpcProvider, Wallet, Contract, parseEther } from "ethers";

const provider = new JsonRpcProvider("https://rpc.bitkubchain.io");
const signer = new Wallet(process.env.PRIVATE_KEY, provider);
```

## Buy tokens on the bonding curve

```javascript
const MARKET_ABI = [
  "function buyToken(uint256 minTokensOut) payable returns ()",
  "function getTokensOut(uint256 kubIn) view returns (uint256)",
  "function graduated() view returns (bool)",
];

const market = new Contract(tokenInfo.market, MARKET_ABI, signer);

// 1. Check if graduated
if (await market.graduated()) {
  throw new Error("Already graduated — use AMM instead");
}

// 2. Quote expected output
const kubIn = parseEther("0.5"); // 0.5 KUB
const expectedOut = await market.getTokensOut(kubIn);

// 3. Slippage protection (1% = 99/100)
const minOut = expectedOut * 99n / 100n;

// 4. Submit buy
const tx = await market.buyToken(minOut, { value: kubIn });
console.log("buy tx:", tx.hash);
await tx.wait();
```

## Sell tokens back to the curve

```javascript
const MARKET_ABI = [
  "function sellToken(uint256 tokenAmountIn, uint256 minKubOut)",
  "function getKubOut(uint256 tokenIn) view returns (uint256)",
];

const ERC20_ABI = [
  "function approve(address spender, uint256 amount) returns (bool)",
  "function allowance(address owner, address spender) view returns (uint256)",
];

// 1. Approve (one-time)
const token = new Contract(tokenInfo.token, ERC20_ABI, signer);
const tokenAmount = parseEther("1000");

const currentAllowance = await token.allowance(signer.address, tokenInfo.market);
if (currentAllowance < tokenAmount) {
  const approveTx = await token.approve(tokenInfo.market, tokenAmount);
  await approveTx.wait();
}

// 2. Quote
const market = new Contract(tokenInfo.market, MARKET_ABI, signer);
const expectedKub = await market.getKubOut(tokenAmount);
const minKubOut = expectedKub * 99n / 100n;

// 3. Sell
const sellTx = await market.sellToken(tokenAmount, minKubOut);
await sellTx.wait();
```

## Trade on the post-graduation AMM

Exactly the same pattern as the market, but pointing at the `ammPool` address and using the AMM ABI:

```javascript
const AMM_ABI = [
  "function swapKubForToken(uint256 minTokensOut) payable",
  "function swapTokenForKub(uint256 tokenAmountIn, uint256 minKubOut)",
  "function getTokensOut(uint256 kubIn) view returns (uint256)",
  "function getKubOut(uint256 tokenIn) view returns (uint256)",
  "function isCooldownActive() view returns (bool)",
];

const amm = new Contract(ammAddress, AMM_ABI, signer);

// Check cooldown (10 blocks after graduation)
if (await amm.isCooldownActive()) {
  throw new Error("AMM in cooldown — wait a few blocks");
}

// Buy
const kubIn = parseEther("1");
const expectedOut = await amm.getTokensOut(kubIn);
const minOut = expectedOut * 99n / 100n;
await amm.swapKubForToken(minOut, { value: kubIn });
```

## Unified quote router (handles both phases)

```javascript
async function quote(tokenInfo, kubIn) {
  const market = new Contract(tokenInfo.market, MARKET_ABI, provider);
  if (await market.graduated()) {
    const ammAddr = await market.ammPool();
    const amm = new Contract(ammAddr, AMM_ABI, provider);
    return { venue: "amm", address: ammAddr, tokensOut: await amm.getTokensOut(kubIn) };
  }
  return { venue: "curve", address: tokenInfo.market, tokensOut: await market.getTokensOut(kubIn) };
}
```

## Error handling

Common reverts you'll see:

| Error                      | Meaning                                                    |
| -------------------------- | ---------------------------------------------------------- |
| `BCM__SlippageExceeded`    | Output less than `minOut` — raise slippage or reduce trade |
| `BCM__MarketGraduated`     | Already graduated — use AMM                                |
| `BCM__ZeroAmount`          | Input was 0 or rounds to 0                                 |
| `AMM__CooldownActive`      | Post-graduation 10-block cooldown — wait                   |
| `Factory__InsufficientKUB` | Create-token tx sent less than 0.1 KUB                     |
| `INSUFFICIENT_FUNDS`       | Your wallet doesn't have enough KUB for value + gas        |

## Gas estimates

| Operation                 | Gas         |
| ------------------------- | ----------- |
| Create token              | \~3,000,000 |
| Buy (normal)              | \~150,000   |
| Buy (triggers graduation) | \~3,500,000 |
| Sell                      | \~100,000   |
| AMM swap                  | \~80,000    |

Set `gasLimit` conservatively — especially for the buy that might trigger graduation (can't always tell ahead of time).

## Example: trading bot skeleton

```javascript
import { JsonRpcProvider, Wallet, Contract, parseEther } from "ethers";

const provider = new JsonRpcProvider("https://rpc.bitkubchain.io");
const signer = new Wallet(process.env.PRIVATE_KEY, provider);
const factory = new Contract(FACTORY, FACTORY_ABI, provider);

// Watch for new launches
factory.on("TokenCreated", async (token, market, creator, name, symbol) => {
  console.log(`📢 New launch: ${symbol} by ${creator}`);
  // your strategy: auto-buy small amount? wait? analyze?
});

// Watch a specific token's trades
const market = new Contract(marketAddress, MARKET_ABI, provider);
market.on("TokensBought", (buyer, kubIn, tokensOut, fee, raised, price) => {
  console.log(`💹 ${symbol}: ${buyer} bought for ${kubIn} KUB at ${price}`);
});
```


---

# 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:

```
GET https://durianandfun.gitbook.io/durianfun/durian-launchpad/integration/trade-programmatically.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
