Skip to main content

Bot Integration

This guide shows how to process trade signals through Evix with slippage protection — a common pattern for automated trading bots.

Full Example

import { createPublicClient, createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { EvixClient } from "@inductiv/evix-sdk";

const account = privateKeyToAccount("0x...");

const publicClient = createPublicClient({
chain: base,
transport: http(),
});

const walletClient = createWalletClient({
account,
chain: base,
transport: http(),
});

const evix = new EvixClient({
chainId: base.id,
contractAddress: "0x...",
publicClient,
walletClient,
});

// Define a trade signal type
type TradeSignal = {
tokenIn: `0x${string}`;
tokenOut: `0x${string}`;
amountIn: bigint;
maxSlippageBps: bigint;
};

async function executeSignal(signal: TradeSignal) {
const deadline = BigInt(Math.floor(Date.now() / 1000) + 30);

// Simulate to get expected output
const expectedOut = await evix.simulateSwap({
tokenIn: signal.tokenIn,
tokenOut: signal.tokenOut,
amountIn: signal.amountIn,
deadline,
minAmountOut: 0n,
recipient: account.address,
});

const minOut =
expectedOut - (expectedOut * signal.maxSlippageBps) / 10_000n;

console.log(
`Signal: ${signal.amountIn} in -> expected ${expectedOut} out (min: ${minOut})`
);

const result = await evix.swap({
tokenIn: signal.tokenIn,
tokenOut: signal.tokenOut,
amountIn: signal.amountIn,
deadline,
minAmountOut: minOut,
recipient: account.address,
});

console.log(`Executed: ${result.transactionHash}`);
return result;
}

// Process signals from a queue
async function main() {
const signals: TradeSignal[] = [
{
tokenIn: "0x..." as `0x${string}`,
tokenOut: "0x..." as `0x${string}`,
amountIn: 500_000n,
maxSlippageBps: 30n, // 0.3%
},
];

for (const signal of signals) {
try {
await executeSignal(signal);
} catch (err) {
console.error("Signal execution failed:", err);
}
}
}

main().catch(console.error);

Key Patterns

Tight Deadlines

For bot integrations, use short deadlines (15–60 seconds). Stale transactions that land late can result in unfavorable execution.

// 30-second deadline for latency-sensitive bots
const deadline = BigInt(Math.floor(Date.now() / 1000) + 30);

Per-Signal Slippage

Each signal carries its own maxSlippageBps, allowing you to differentiate between:

  • Aggressive signals (low slippage, tight tolerance)
  • Opportunistic signals (higher slippage, more flexibility)

Error Isolation

Wrap each signal execution in a try/catch to prevent a single failure from halting the queue:

for (const signal of signals) {
try {
await executeSignal(signal);
} catch (err) {
// Log and continue — don't let one bad signal halt the pipeline
console.error("Signal execution failed:", err);
}
}

Simulation as Gating

Use the simulation result to gate execution. If the simulated output is below a profitability threshold, skip the signal:

const expectedOut = await evix.simulateSwap(params);

if (expectedOut < signal.minProfitableOutput) {
console.log("Skipping: output below profitability threshold");
return;
}

Considerations

ConcernRecommendation
Deadline15–60s for bots, shorter is better
Slippage10–50 bps for stable pairs, higher for volatile
Error handlingIsolate per-signal, log failures, continue processing
SimulationAlways simulate first — it catches stale pairs, bad amounts, and reverts
ConcurrencyProcess signals sequentially per account to avoid nonce conflicts