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

# Protocol Examples

> V5 contract interaction examples for LFG.RICH using Ethers, Viem, Web3.js, and Python Web3.py.

These examples follow the same V5 pattern used by the LFG.RICH application:

<CardGroup cols={2}>
  <Card title="Ethers.js" icon="code">
    Includes shared setup, estimates, buy, sell, borrow, borrowMore, and repay examples.
  </Card>

  <Card title="Viem" icon="terminal">
    Shows typed public/wallet client reads and writes for the V5 flow.
  </Card>

  <Card title="Web3.js" icon="brackets-curly">
    Provides examples for integrations still using Web3.js.
  </Card>

  <Card title="Python Web3.py" icon="python">
    Covers backend scripts, bots, and analytics workers that need direct V5 contract calls.
  </Card>
</CardGroup>

<Steps>
  <Step title="Resolve the token's poolId">
    Use API data when available, then fall back to `hook.tokenToPoolId(tokenAddress)`.
  </Step>

  <Step title="Resolve or build the PoolKey">
    Prefer `factory.getPoolKey(tokenAddress)` and only build manually when constants are known.
  </Step>

  <Step title="Quote through the Hook">
    V5 estimate functions include the user wallet address because referral routing can affect fee recipients.
  </Step>

  <Step title="Execute buys and sells through the Swap Router">
    Swap execution uses the token-specific PoolKey.
  </Step>

  <Step title="Execute borrow, borrow more, and repay through the Hook">
    Lending actions use `poolId`, and collateral approvals go to the Hook.
  </Step>
</Steps>

<Warning>
  Do not use old V3 examples for V5 tokens. In V5, `estimateBuy` and `estimateSell` include the user address, `createToken` takes `devBuyEth`, and token trades must be routed with the correct `PoolKey`.
</Warning>

## Shared V5 concepts

```ts theme={null}
type PoolKey = {
  currency0: `0x${string}`; // native BNB represented as address(0)
  currency1: `0x${string}`; // token address
  fee: number;              // usually 3000
  tickSpacing: number;      // usually 60
  hooks: `0x${string}`;     // Hook contract
};
```

The app can use `token.pool_id` from the API, but integrations should also know the fallback:

```txt theme={null}
poolId = token.pool_id || token.poolId || hook.tokenToPoolId(tokenAddress)
```

For swaps, prefer `factory.getPoolKey(tokenAddress)` when available. If you already know the network constants, the same PoolKey can be built as:

```js theme={null}
{
  currency0: '0x0000000000000000000000000000000000000000',
  currency1: tokenAddress,
  fee: 3000,
  tickSpacing: 60,
  hooks: hookAddress
}
```

## Ethers.js v5

### Shared setup

```js theme={null}
import { ethers } from 'ethers';

const API_BASE = 'https://lfg.rich/api/bsc/tokens';
const ZERO = ethers.constants.AddressZero;

async function loadContractsConfig() {
  const res = await fetch(`${API_BASE}/config/contracts`);
  const json = await res.json();
  if (!json.success) throw new Error(json.error || 'Failed to load contract config');
  return json.data;
}

async function loadToken(tokenAddress) {
  const res = await fetch(`${API_BASE}/${tokenAddress}`);
  const json = await res.json();
  if (!json.success) throw new Error(json.error || 'Failed to load token');
  return json.data;
}

async function getPoolContext({ tokenAddress, provider }) {
  const cfg = await loadContractsConfig();
  const token = await loadToken(tokenAddress);

  const factory = new ethers.Contract(cfg.factoryAddress, cfg.factoryABI, provider);
  const hook = new ethers.Contract(cfg.hookAddress, cfg.hookABI, provider);

  let poolId = token.pool_id || token.poolId;
  if (!poolId || poolId === '0x') {
    poolId = await hook.tokenToPoolId(tokenAddress);
  }

  let poolKey;
  try {
    poolKey = await factory.getPoolKey(tokenAddress);
  } catch {
    poolKey = {
      currency0: ZERO,
      currency1: tokenAddress,
      fee: 3000,
      tickSpacing: 60,
      hooks: cfg.hookAddress
    };
  }

  return { cfg, token, poolId, poolKey, factory, hook };
}

function applySlippage(value, slippagePct = 5) {
  return ethers.BigNumber.from(value).mul(100 - slippagePct).div(100);
}
```

### Estimate buy

```js theme={null}
async function estimateBuy({ tokenAddress, bnbAmount, walletAddress, provider }) {
  const { hook, poolId } = await getPoolContext({ tokenAddress, provider });
  const ethWei = ethers.utils.parseEther(bnbAmount);

  const quote = await hook.estimateBuy(
    poolId,
    ethWei,
    walletAddress || ethers.constants.AddressZero
  );

  return {
    tokensOut: quote.tokensOut.toString(),
    platformFee: quote.platformFee.toString(),
    inviterFee: quote.inviterFee.toString(),
    totalFee: quote.platformFee.add(quote.inviterFee || 0).toString()
  };
}
```

### Buy tokens

```js theme={null}
async function buyToken({ tokenAddress, bnbAmount, slippagePct = 5, signer }) {
  const provider = signer.provider;
  const walletAddress = await signer.getAddress();
  const { cfg, hook, poolId, poolKey } = await getPoolContext({ tokenAddress, provider });

  const router = new ethers.Contract(cfg.swapRouterAddress, cfg.swapRouterABI, signer);
  const value = ethers.utils.parseEther(bnbAmount);

  const quote = await hook.estimateBuy(poolId, value, walletAddress);
  const minTokensOut = applySlippage(quote.tokensOut, slippagePct);

  const tx = await router.buy(poolKey, minTokensOut, { value });
  return await tx.wait();
}
```

### Estimate sell

```js theme={null}
async function estimateSell({ tokenAddress, tokenAmount, walletAddress, provider }) {
  const { hook, poolId } = await getPoolContext({ tokenAddress, provider });
  const tokenWei = ethers.utils.parseEther(tokenAmount);

  const quote = await hook.estimateSell(
    poolId,
    tokenWei,
    walletAddress || ethers.constants.AddressZero
  );

  return {
    ethOut: quote.ethOut.toString(),
    platformFee: quote.platformFee.toString(),
    inviterFee: quote.inviterFee.toString(),
    totalFee: quote.platformFee.add(quote.inviterFee || 0).toString()
  };
}
```

### Sell tokens

```js theme={null}
async function sellToken({ tokenAddress, tokenAmount, slippagePct = 5, signer }) {
  const provider = signer.provider;
  const walletAddress = await signer.getAddress();
  const { cfg, hook, poolId, poolKey } = await getPoolContext({ tokenAddress, provider });

  const token = new ethers.Contract(tokenAddress, cfg.tokenABI, signer);
  const router = new ethers.Contract(cfg.swapRouterAddress, cfg.swapRouterABI, signer);

  const amountWei = ethers.utils.parseEther(tokenAmount);

  const allowance = await token.allowance(walletAddress, cfg.swapRouterAddress);
  if (allowance.lt(amountWei)) {
    const approveTx = await token.approve(cfg.swapRouterAddress, ethers.constants.MaxUint256);
    await approveTx.wait();
  }

  const quote = await hook.estimateSell(poolId, amountWei, walletAddress);
  const minEthOut = applySlippage(quote.ethOut, slippagePct);

  const tx = await router.sell(poolKey, amountWei, minEthOut);
  return await tx.wait();
}
```

### Borrow

```js theme={null}
async function borrowAgainstToken({ tokenAddress, tokenAmount, signer }) {
  const provider = signer.provider;
  const walletAddress = await signer.getAddress();
  const { cfg, poolId } = await getPoolContext({ tokenAddress, provider });

  const hook = new ethers.Contract(cfg.hookAddress, cfg.hookABI, signer);
  const token = new ethers.Contract(tokenAddress, cfg.tokenABI, signer);
  const amountWei = ethers.utils.parseEther(tokenAmount);

  const allowance = await token.allowance(walletAddress, cfg.hookAddress);
  if (allowance.lt(amountWei)) {
    const approveTx = await token.approve(cfg.hookAddress, ethers.constants.MaxUint256);
    await approveTx.wait();
  }

  const tx = await hook.borrow(poolId, amountWei);
  return await tx.wait();
}
```

### Borrow more

```js theme={null}
async function borrowMore({ tokenAddress, signer }) {
  const { cfg, poolId } = await getPoolContext({
    tokenAddress,
    provider: signer.provider
  });

  const hook = new ethers.Contract(cfg.hookAddress, cfg.hookABI, signer);
  const tx = await hook.borrowMore(poolId);
  return await tx.wait();
}
```

### Repay

```js theme={null}
async function repayBorrow({ tokenAddress, bnbAmount, signer }) {
  const { cfg, poolId } = await getPoolContext({
    tokenAddress,
    provider: signer.provider
  });

  const hook = new ethers.Contract(cfg.hookAddress, cfg.hookABI, signer);
  const value = ethers.utils.parseEther(bnbAmount);

  const tx = await hook.repay(poolId, { value });
  return await tx.wait();
}
```

### Read user borrow state

```js theme={null}
async function getBorrowState({ tokenAddress, walletAddress, provider }) {
  const { hook, poolId } = await getPoolContext({ tokenAddress, provider });

  const [borrowedETH, collateralBalance, borrowMoreEstimate] = await Promise.all([
    hook.borrowedETH(poolId, walletAddress),
    hook.collateralBalance(poolId, walletAddress),
    hook.estimateBorrowMore(poolId, walletAddress).catch(() => null)
  ]);

  return {
    poolId,
    borrowedETH: borrowedETH.toString(),
    collateralBalance: collateralBalance.toString(),
    borrowMoreEstimate: borrowMoreEstimate
      ? {
          additionalEth: borrowMoreEstimate.additionalEth.toString(),
          fee: borrowMoreEstimate.fee.toString()
        }
      : null
  };
}
```

## Viem

```ts theme={null}
import { createPublicClient, createWalletClient, custom, http, parseAbi, parseEther, zeroAddress } from 'viem';
import { bsc } from 'viem/chains';

const API_BASE = 'https://lfg.rich/api/bsc/tokens';

async function getConfig() {
  const res = await fetch(`${API_BASE}/config/contracts`);
  const json = await res.json();
  if (!json.success) throw new Error(json.error || 'Failed to load config');
  return {
    ...json.data,
    factoryABI: parseAbi(json.data.factoryABI),
    hookABI: parseAbi(json.data.hookABI),
    swapRouterABI: parseAbi(json.data.swapRouterABI),
    tokenABI: parseAbi(json.data.tokenABI),
  };
}

async function getPoolId(publicClient, cfg, tokenAddress, apiToken) {
  return apiToken.pool_id || apiToken.poolId || await publicClient.readContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'tokenToPoolId',
    args: [tokenAddress],
  });
}

function poolKey(tokenAddress, hookAddress) {
  return {
    currency0: zeroAddress,
    currency1: tokenAddress,
    fee: 3000,
    tickSpacing: 60,
    hooks: hookAddress,
  };
}
```

### Buy with Viem

```ts theme={null}
async function viemBuy(tokenAddress, bnbAmount, account) {
  const cfg = await getConfig();
  const apiToken = await fetch(`${API_BASE}/${tokenAddress}`).then(r => r.json()).then(j => j.data);

  const publicClient = createPublicClient({ chain: bsc, transport: http(cfg.rpcUrl) });
  const walletClient = createWalletClient({ account, chain: bsc, transport: custom(window.ethereum) });

  const poolId = await getPoolId(publicClient, cfg, tokenAddress, apiToken);
  const value = parseEther(bnbAmount);

  const quote = await publicClient.readContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'estimateBuy',
    args: [poolId, value, account],
  });

  const minTokensOut = quote[0] * 95n / 100n;

  return walletClient.writeContract({
    address: cfg.swapRouterAddress,
    abi: cfg.swapRouterABI,
    functionName: 'buy',
    args: [poolKey(tokenAddress, cfg.hookAddress), minTokensOut],
    value,
  });
}
```

### Sell with Viem

```ts theme={null}
async function viemSell(tokenAddress, tokenAmount, account) {
  const cfg = await getConfig();
  const apiToken = await fetch(`${API_BASE}/${tokenAddress}`).then(r => r.json()).then(j => j.data);

  const publicClient = createPublicClient({ chain: bsc, transport: http(cfg.rpcUrl) });
  const walletClient = createWalletClient({ account, chain: bsc, transport: custom(window.ethereum) });

  const amount = parseEther(tokenAmount);
  const poolId = await getPoolId(publicClient, cfg, tokenAddress, apiToken);

  const allowance = await publicClient.readContract({
    address: tokenAddress,
    abi: cfg.tokenABI,
    functionName: 'allowance',
    args: [account, cfg.swapRouterAddress],
  });

  if (allowance < amount) {
    await walletClient.writeContract({
      address: tokenAddress,
      abi: cfg.tokenABI,
      functionName: 'approve',
      args: [cfg.swapRouterAddress, 2n ** 256n - 1n],
    });
  }

  const quote = await publicClient.readContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'estimateSell',
    args: [poolId, amount, account],
  });

  const minEthOut = quote[0] * 95n / 100n;

  return walletClient.writeContract({
    address: cfg.swapRouterAddress,
    abi: cfg.swapRouterABI,
    functionName: 'sell',
    args: [poolKey(tokenAddress, cfg.hookAddress), amount, minEthOut],
  });
}
```

### Borrow, borrow more, and repay with Viem

```ts theme={null}
async function viemBorrow(tokenAddress, tokenAmount, account) {
  const cfg = await getConfig();
  const publicClient = createPublicClient({ chain: bsc, transport: http(cfg.rpcUrl) });
  const walletClient = createWalletClient({ account, chain: bsc, transport: custom(window.ethereum) });

  const amount = parseEther(tokenAmount);
  const poolId = await publicClient.readContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'tokenToPoolId',
    args: [tokenAddress],
  });

  const allowance = await publicClient.readContract({
    address: tokenAddress,
    abi: cfg.tokenABI,
    functionName: 'allowance',
    args: [account, cfg.hookAddress],
  });

  if (allowance < amount) {
    await walletClient.writeContract({
      address: tokenAddress,
      abi: cfg.tokenABI,
      functionName: 'approve',
      args: [cfg.hookAddress, 2n ** 256n - 1n],
    });
  }

  return walletClient.writeContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'borrow',
    args: [poolId, amount],
  });
}

async function viemBorrowMore(tokenAddress, account) {
  const cfg = await getConfig();
  const publicClient = createPublicClient({ chain: bsc, transport: http(cfg.rpcUrl) });
  const walletClient = createWalletClient({ account, chain: bsc, transport: custom(window.ethereum) });

  const poolId = await publicClient.readContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'tokenToPoolId',
    args: [tokenAddress],
  });

  return walletClient.writeContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'borrowMore',
    args: [poolId],
  });
}

async function viemRepay(tokenAddress, bnbAmount, account) {
  const cfg = await getConfig();
  const publicClient = createPublicClient({ chain: bsc, transport: http(cfg.rpcUrl) });
  const walletClient = createWalletClient({ account, chain: bsc, transport: custom(window.ethereum) });

  const poolId = await publicClient.readContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'tokenToPoolId',
    args: [tokenAddress],
  });

  return walletClient.writeContract({
    address: cfg.hookAddress,
    abi: cfg.hookABI,
    functionName: 'repay',
    args: [poolId],
    value: parseEther(bnbAmount),
  });
}
```

## Web3.js

```js theme={null}
import Web3 from 'web3';

const API_BASE = 'https://lfg.rich/api/bsc/tokens';
const ZERO = '0x0000000000000000000000000000000000000000';

async function web3Context(tokenAddress, web3) {
  const cfg = (await (await fetch(`${API_BASE}/config/contracts`)).json()).data;
  const tokenData = (await (await fetch(`${API_BASE}/${tokenAddress}`)).json()).data;

  const factory = new web3.eth.Contract(cfg.factoryABI, cfg.factoryAddress);
  const hook = new web3.eth.Contract(cfg.hookABI, cfg.hookAddress);
  const router = new web3.eth.Contract(cfg.swapRouterABI, cfg.swapRouterAddress);
  const token = new web3.eth.Contract(cfg.tokenABI, tokenAddress);

  const poolId = tokenData.pool_id || tokenData.poolId || await hook.methods.tokenToPoolId(tokenAddress).call();

  let key;
  try {
    key = await factory.methods.getPoolKey(tokenAddress).call();
  } catch {
    key = [ZERO, tokenAddress, 3000, 60, cfg.hookAddress];
  }

  return { cfg, tokenData, factory, hook, router, token, poolId, key };
}

async function web3Buy({ tokenAddress, bnbAmount, from, web3 }) {
  const { hook, router, poolId, key } = await web3Context(tokenAddress, web3);
  const value = web3.utils.toWei(bnbAmount, 'ether');

  const quote = await hook.methods.estimateBuy(poolId, value, from).call();
  const minTokensOut = (BigInt(quote.tokensOut || quote[0]) * 95n / 100n).toString();

  return router.methods.buy(key, minTokensOut).send({ from, value });
}

async function web3Sell({ tokenAddress, tokenAmount, from, web3 }) {
  const { cfg, hook, router, token, poolId, key } = await web3Context(tokenAddress, web3);
  const amount = web3.utils.toWei(tokenAmount, 'ether');

  const allowance = await token.methods.allowance(from, cfg.swapRouterAddress).call();
  if (BigInt(allowance) < BigInt(amount)) {
    await token.methods.approve(cfg.swapRouterAddress, web3.utils.toTwosComplement(-1)).send({ from });
  }

  const quote = await hook.methods.estimateSell(poolId, amount, from).call();
  const minEthOut = (BigInt(quote.ethOut || quote[0]) * 95n / 100n).toString();

  return router.methods.sell(key, amount, minEthOut).send({ from });
}

async function web3Borrow({ tokenAddress, tokenAmount, from, web3 }) {
  const { cfg, hook, token, poolId } = await web3Context(tokenAddress, web3);
  const amount = web3.utils.toWei(tokenAmount, 'ether');

  const allowance = await token.methods.allowance(from, cfg.hookAddress).call();
  if (BigInt(allowance) < BigInt(amount)) {
    await token.methods.approve(cfg.hookAddress, web3.utils.toTwosComplement(-1)).send({ from });
  }

  return hook.methods.borrow(poolId, amount).send({ from });
}

async function web3BorrowMore({ tokenAddress, from, web3 }) {
  const { hook, poolId } = await web3Context(tokenAddress, web3);
  return hook.methods.borrowMore(poolId).send({ from });
}

async function web3Repay({ tokenAddress, bnbAmount, from, web3 }) {
  const { hook, poolId } = await web3Context(tokenAddress, web3);
  const value = web3.utils.toWei(bnbAmount, 'ether');
  return hook.methods.repay(poolId).send({ from, value });
}
```

## Python Web3.py

```python theme={null}
from web3 import Web3
import requests

API_BASE = "https://lfg.rich/api/bsc/tokens"
ZERO = "0x0000000000000000000000000000000000000000"

def load_config():
    data = requests.get(f"{API_BASE}/config/contracts", timeout=20).json()
    if not data.get("success"):
        raise RuntimeError(data.get("error", "Failed to load config"))
    return data["data"]

def load_token(token_address):
    data = requests.get(f"{API_BASE}/{token_address}", timeout=20).json()
    if not data.get("success"):
        raise RuntimeError(data.get("error", "Failed to load token"))
    return data["data"]

def pool_context(w3: Web3, token_address: str):
    cfg = load_config()
    token_data = load_token(token_address)

    factory = w3.eth.contract(address=Web3.to_checksum_address(cfg["factoryAddress"]), abi=cfg["factoryABI"])
    hook = w3.eth.contract(address=Web3.to_checksum_address(cfg["hookAddress"]), abi=cfg["hookABI"])
    router = w3.eth.contract(address=Web3.to_checksum_address(cfg["swapRouterAddress"]), abi=cfg["swapRouterABI"])
    token = w3.eth.contract(address=Web3.to_checksum_address(token_address), abi=cfg["tokenABI"])

    pool_id = token_data.get("pool_id") or token_data.get("poolId")
    if not pool_id:
        pool_id = hook.functions.tokenToPoolId(Web3.to_checksum_address(token_address)).call()

    try:
        key = factory.functions.getPoolKey(Web3.to_checksum_address(token_address)).call()
    except Exception:
        key = (
            ZERO,
            Web3.to_checksum_address(token_address),
            3000,
            60,
            Web3.to_checksum_address(cfg["hookAddress"]),
        )

    return cfg, token_data, factory, hook, router, token, pool_id, key

def sign_and_send(w3: Web3, tx, private_key: str):
    signed = w3.eth.account.sign_transaction(tx, private_key)
    tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
    return w3.eth.wait_for_transaction_receipt(tx_hash)
```

### Buy with Python

```python theme={null}
def buy_token(w3, token_address, bnb_amount, wallet, private_key, slippage_pct=5):
    cfg, token_data, factory, hook, router, token, pool_id, key = pool_context(w3, token_address)
    wallet = Web3.to_checksum_address(wallet)
    wei_in = w3.to_wei(bnb_amount, "ether")

    tokens_out, platform_fee, inviter_fee = hook.functions.estimateBuy(pool_id, wei_in, wallet).call()
    min_tokens_out = tokens_out * (100 - slippage_pct) // 100

    tx = router.functions.buy(key, min_tokens_out).build_transaction({
        "from": wallet,
        "value": wei_in,
        "nonce": w3.eth.get_transaction_count(wallet),
        "gas": 650000,
        "gasPrice": w3.eth.gas_price,
        "chainId": 56,
    })
    return sign_and_send(w3, tx, private_key)
```

### Sell with Python

```python theme={null}
def sell_token(w3, token_address, token_amount, wallet, private_key, slippage_pct=5):
    cfg, token_data, factory, hook, router, token, pool_id, key = pool_context(w3, token_address)
    wallet = Web3.to_checksum_address(wallet)
    amount = w3.to_wei(token_amount, "ether")

    allowance = token.functions.allowance(wallet, Web3.to_checksum_address(cfg["swapRouterAddress"])).call()
    nonce = w3.eth.get_transaction_count(wallet)

    if allowance < amount:
        approve_tx = token.functions.approve(
            Web3.to_checksum_address(cfg["swapRouterAddress"]),
            2**256 - 1
        ).build_transaction({
            "from": wallet,
            "nonce": nonce,
            "gas": 120000,
            "gasPrice": w3.eth.gas_price,
            "chainId": 56,
        })
        sign_and_send(w3, approve_tx, private_key)
        nonce += 1

    eth_out, platform_fee, inviter_fee = hook.functions.estimateSell(pool_id, amount, wallet).call()
    min_eth_out = eth_out * (100 - slippage_pct) // 100

    tx = router.functions.sell(key, amount, min_eth_out).build_transaction({
        "from": wallet,
        "nonce": nonce,
        "gas": 650000,
        "gasPrice": w3.eth.gas_price,
        "chainId": 56,
    })
    return sign_and_send(w3, tx, private_key)
```

### Borrow, borrow more, and repay with Python

```python theme={null}
def borrow_token(w3, token_address, token_amount, wallet, private_key):
    cfg, token_data, factory, hook, router, token, pool_id, key = pool_context(w3, token_address)
    wallet = Web3.to_checksum_address(wallet)
    amount = w3.to_wei(token_amount, "ether")
    nonce = w3.eth.get_transaction_count(wallet)

    allowance = token.functions.allowance(wallet, Web3.to_checksum_address(cfg["hookAddress"])).call()
    if allowance < amount:
        approve_tx = token.functions.approve(
            Web3.to_checksum_address(cfg["hookAddress"]),
            2**256 - 1
        ).build_transaction({
            "from": wallet,
            "nonce": nonce,
            "gas": 120000,
            "gasPrice": w3.eth.gas_price,
            "chainId": 56,
        })
        sign_and_send(w3, approve_tx, private_key)
        nonce += 1

    tx = hook.functions.borrow(pool_id, amount).build_transaction({
        "from": wallet,
        "nonce": nonce,
        "gas": 650000,
        "gasPrice": w3.eth.gas_price,
        "chainId": 56,
    })
    return sign_and_send(w3, tx, private_key)

def borrow_more(w3, token_address, wallet, private_key):
    cfg, token_data, factory, hook, router, token, pool_id, key = pool_context(w3, token_address)
    wallet = Web3.to_checksum_address(wallet)

    tx = hook.functions.borrowMore(pool_id).build_transaction({
        "from": wallet,
        "nonce": w3.eth.get_transaction_count(wallet),
        "gas": 650000,
        "gasPrice": w3.eth.gas_price,
        "chainId": 56,
    })
    return sign_and_send(w3, tx, private_key)

def repay(w3, token_address, bnb_amount, wallet, private_key):
    cfg, token_data, factory, hook, router, token, pool_id, key = pool_context(w3, token_address)
    wallet = Web3.to_checksum_address(wallet)

    tx = hook.functions.repay(pool_id).build_transaction({
        "from": wallet,
        "value": w3.to_wei(bnb_amount, "ether"),
        "nonce": w3.eth.get_transaction_count(wallet),
        "gas": 650000,
        "gasPrice": w3.eth.gas_price,
        "chainId": 56,
    })
    return sign_and_send(w3, tx, private_key)
```

## Common mistakes

| Mistake                                                    | Fix                                                                                       |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Calling `estimateBuy(poolId, ethIn)`                       | Use `estimateBuy(poolId, ethIn, buyer)`                                                   |
| Calling `estimateSell(poolId, tokenAmount)`                | Use `estimateSell(poolId, tokenAmount, seller)`                                           |
| Building a router call without the correct token `PoolKey` | Call `factory.getPoolKey(tokenAddress)` or build the V5 PoolKey exactly                   |
| Borrowing without token approval                           | Approve the Hook address before `hook.borrow(poolId, amount)`                             |
| Selling without token approval                             | Approve the Swap Router address before `router.sell(...)`                                 |
| Using a stale or missing `poolId`                          | Use `token.pool_id`, `factory.getTokenInfo(token).poolId`, or `hook.tokenToPoolId(token)` |
| Expecting old fee output names                             | V5 returns `platformFee` and `inviterFee`, not `floorBoostFee`                            |
