> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inkyswap.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration Guide

> End to end V2 integration. Setup, launching, trading, listening for events.

This guide walks through integrating the InkyPump V2 hook into a JavaScript or TypeScript application. Examples use viem. The same calls work with ethers, web3.js, or any other library.

## Setup

```javascript theme={null}
import { createPublicClient, createWalletClient, http, parseEther } from "viem"
import { privateKeyToAccount } from "viem/accounts"

const INK_MAINNET = {
  id: 57073,
  name: "Ink",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: { default: { http: ["https://rpc-gel.inkonchain.com"] } },
}

const HOOK = "0x4cC8F6d5B7cE150CCC0A9B7664532B1283b96AC4"

const publicClient = createPublicClient({ chain: INK_MAINNET, transport: http() })
const account = privateKeyToAccount(process.env.PRIVATE_KEY)
const walletClient = createWalletClient({ account, chain: INK_MAINNET, transport: http() })
```

The hook ABI is published as part of the InkyPump SDK or can be pulled from the [ABI page](/api-reference/contracts/abi).

## Read launch state

```javascript theme={null}
const state = await publicClient.readContract({
  address: HOOK,
  abi: INKY_PUMP_HOOK_ABI,
  functionName: "getLaunchState",
  args: [launchId],
})

console.log("Finalized:", state.finalized)
console.log("Target raise:", state.targetRaise)
console.log("Tokens remaining on curve:", state.tokensRemaining)
```

If `state.finalized` is true, the token has bonded. Route trades through the V4 pool instead.

## Preview a buy

Previews use the `LaunchViewModule` at `0xce83E3659251116d114Ec1CA729ffB49B99403c3` with state read from `getLaunchState`. The hook also exposes wrapper preview functions, but the working path used by the InkyPump frontend is the view module call below.

```javascript theme={null}
const LAUNCH_VIEW_MODULE = "0xce83E3659251116d114Ec1CA729ffB49B99403c3"

const state = await publicClient.readContract({
  address: HOOK,
  abi: INKY_PUMP_HOOK_ABI,
  functionName: "getLaunchState",
  args: [launchId],
})

const { tokensOut, cost, refund, tokensRemaining } = await publicClient.readContract({
  address: LAUNCH_VIEW_MODULE,
  abi: LAUNCH_VIEW_MODULE_ABI,
  functionName: "previewBuyLocal",
  args: [
    state.saleSupply,
    state.targetRaise,
    state.gainBps,
    state.sold,
    state.saleSupply - state.sold,   // remaining
    parseEther("0.1"),                // ethIn
  ],
})

const minTokensOut = (tokensOut * 99n) / 100n  // 1 percent slippage
```

## Execute a buy

```javascript theme={null}
const captcha = await fetchCaptchaFromBackend({ launchId, account: account.address })

const hash = await walletClient.writeContract({
  address: HOOK,
  abi: INKY_PUMP_HOOK_ABI,
  functionName: "buy",
  args: [launchId, minTokensOut, captcha],
  value: parseEther("0.1"),
})

const receipt = await publicClient.waitForTransactionReceipt({ hash })
```

For trades after the anti-snipe window has passed, the captcha argument can be empty:

```javascript theme={null}
const emptyCaptcha = { deadline: 0n, signature: "0x" }
```

## Listen for events

```javascript theme={null}
import { parseAbiItem } from "viem"

const tradeEvent = parseAbiItem(
  "event Trade(uint256 indexed launchId, address indexed trader, uint8 tradeType, (uint256 priceAfter, uint256 marketCap) priceData, (uint256 ethAmount, uint256 tokenAmount, uint256 fee) tradeData, uint256 refund)"
)

const unwatch = publicClient.watchEvent({
  address: HOOK,
  event: tradeEvent,
  onLogs: (logs) => {
    for (const log of logs) {
      console.log("Trade:", log.args)
    }
  },
})
```

For referral events:

```javascript theme={null}
const referralEvent = parseAbiItem(
  "event Referral(uint256 indexed launchId, address indexed trader, string referralCode)"
)
```

## Create a launch

```javascript theme={null}
const params = {
  name: "My Token",
  ticker: "MINE",
  description: "...",
  imageUrl: "https://...",
  telegram: "",
  twitter: "",
  website: "",
  creatorFeeSplitBps: 7000,
  gainBps: 50_000,
  targetRaise: parseEther("3"),
  antiSnipeDuration: 40,
  startTime: 0n,
}
// To prebuy, pass `value: parseEther("0.1")` (or any amount) on the writeContract call below.

const hash = await walletClient.writeContract({
  address: HOOK,
  abi: INKY_PUMP_HOOK_ABI,
  functionName: "createLaunch",
  args: [params],
  value: 0n,
})

const receipt = await publicClient.waitForTransactionReceipt({ hash })

// Parse the LaunchCreated event from receipt.logs to get the launchId and token address
```

## Withdraw creator fees

```javascript theme={null}
const hash = await walletClient.writeContract({
  address: HOOK,
  abi: INKY_PUMP_HOOK_ABI,
  functionName: "withdrawFees",
})
```

The hook sends your accrued ETH balance to the caller.

## After bonding

Once `getLaunchState` returns `finalized: true`, trade through the Uniswap Universal Router at `0x551134e92e537cEAa217c2ef63210Af3CE96a065`. The pool fee is 0.1 percent. Use the V4 Quoter for previews.

For the pool key, derive it from the token and WETH:

```javascript theme={null}
const poolKey = {
  currency0: tokenAddress < WETH ? tokenAddress : WETH,
  currency1: tokenAddress < WETH ? WETH : tokenAddress,
  fee: 1_000,
  tickSpacing: 60,
  hooks: HOOK,
}
```

The Universal Router takes a path encoded against this pool key. See the [Uniswap V4 router docs](https://docs.uniswap.org/contracts/v4/overview) for the full encoding.

## Where to test

For a quick read-only test against the live system, read a launch state:

```bash theme={null}
cast call 0x4cC8F6d5B7cE150CCC0A9B7664532B1283b96AC4 \
  "getLaunchState(uint256)" \
  $LAUNCH_ID \
  --rpc-url https://rpc-gel.inkonchain.com
```

If the call returns a hex blob (the encoded `LaunchConfig`) without reverting, your setup is talking to the live hook correctly.

## Doing this from your editor

The [InkyPump MCP server](/api-reference/mcp) wraps the hook so you can call these functions through Claude Code or Codex without writing the integration yourself. Useful for one off launches and testing.
