Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(new-plugin): add arbitrage plugin with example character #2784

Merged
merged 6 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -931,3 +931,15 @@ BTC_FUNDRAISING_CAP=100 # Maximum amount for fundraising
# Trikon Plugin Configuration
TRIKON_WALLET_ADDRESS= # Your Trikon wallet address (must be a valid 64-character hex string starting with '0x')
TRIKON_INITIAL_BALANCE= # (Optional) The initial balance for the wallet. Defaults to "0" if not provided.

####################################
#### Arbitrage Plugin Configuration ####
####################################

ARBITRAGE_ETHEREUM_WS_URL= # WebSocket URL for Ethereum node connection
ARBITRAGE_EVM_PROVIDER_URL= # RPC URL for Ethereum node connection (if WS not available)
ARBITRAGE_EVM_PRIVATE_KEY= # Private key for the wallet executing arbitrage transactions
FLASHBOTS_RELAY_SIGNING_KEY= # Signing key for Flashbots relay interactions
BUNDLE_EXECUTOR_ADDRESS= # Address of the bundle executor contract


1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
"@elizaos/client-xmtp": "workspace:*",
"@elizaos/plugin-trikon": "workspace:*",
"@elizaos/plugin-zilliqa": "workspace:*",
"@elizaos/plugin-arbitrage": "workspace:*",
"readline": "1.3.0",
"ws": "8.18.0",
"yargs": "17.7.2"
Expand Down
12 changes: 9 additions & 3 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ import { MongoClient } from "mongodb";
import { quickIntelPlugin } from "@elizaos/plugin-quick-intel"

import { trikonPlugin } from "@elizaos/plugin-trikon"
import arbitragePlugin from "@elizaos/plugin-arbitrage"
const __filename = fileURLToPath(import.meta.url) // get the resolved path to the file
const __dirname = path.dirname(__filename) // get the name of the directory

Expand Down Expand Up @@ -632,9 +633,9 @@ export async function initializeClients(character: Character, runtime: IAgentRun
}

if (clientTypes.includes(Clients.XMTP)) {
const xmtpClient = await XmtpClientInterface.start(runtime);
if (xmtpClient) clients.xmtp = xmtpClient;
}
const xmtpClient = await XmtpClientInterface.start(runtime);
if (xmtpClient) clients.xmtp = xmtpClient;
}

if (clientTypes.includes(Clients.DISCORD)) {
const discordClient = await DiscordClientInterface.start(runtime)
Expand Down Expand Up @@ -929,6 +930,11 @@ export async function createAgent(character: Character, db: IDatabaseAdapter, ca
getSecret(character, "QUICKINTEL_API_KEY") ? quickIntelPlugin : null,
getSecret(character, "GELATO_RELAY_API_KEY") ? gelatoPlugin : null,
getSecret(character, "TRIKON_WALLET_ADDRESS") ? trikonPlugin : null,
getSecret(character, "ARBITRAGE_EVM_PRIVATE_KEY") &&
(getSecret(character, "ARBITRAGE_EVM_PROVIDER_URL")
|| getSecret(character, "ARBITRAGE_ETHEREUM_WS_URL"))
&& getSecret(character, "ARBITRAGE_FLASHBOTS_RELAY_SIGNING_KEY")
&& getSecret(character, "ARBITRAGE_BUNDLE_EXECUTOR_ADDRESS") ? arbitragePlugin : null,
].flat().filter(Boolean),
providers: [],
managers: [],
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"@ai-sdk/provider": "1.0.6",
"@ai-sdk/provider-utils": "2.1.2",
"cookie": "0.7.0",
"bs58": "5.0.0"
"bs58": "5.0.0",
"@coral-xyz/anchor": "0.28.0"
}
},
"engines": {
Expand Down
115 changes: 115 additions & 0 deletions packages/plugin-arbitrage/examples/trader.character.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
{
"name": "Trader",
"description": "A trading bot that specializes in crypto arbitrage",
"clients": ["direct"],
"modelProvider": "anthropic",
"settings": {
"secrets": {
"EVM_PRIVATE_KEY": "YOUR_PRIVATE_KEY_HERE",
"FLASHBOTS_RELAY_SIGNING_KEY": "YOUR_FLASHBOTS_KEY_HERE",
"BUNDLE_EXECUTOR_ADDRESS": "YOUR_EXECUTOR_ADDRESS_HERE"
},
"arbitrage": {
"ethereumWsUrl": "YOUR_ETH_WSS_URL",
"rpcUrl": "YOUR_ETH_RPC_URL"
}
},
"plugins": [
"@elizaos/plugin-arbitrage",
"@elizaos/plugin-evm"
],
"modelSettings": {
"provider": "anthropic",
"model": "claude-3-sonnet-20240229"
},
"bio": [
"Expert in cryptocurrency trading and arbitrage.",
"Specializes in identifying profitable trading opportunities.",
"Monitors multiple exchanges for price differences.",
"Provides real-time market analysis and insights."
],
"lore": [
"Created to help traders identify and execute profitable arbitrage opportunities.",
"Trained on extensive market data and trading patterns."
],
"knowledge": [
"Understands cryptocurrency market dynamics",
"Knows how to identify arbitrage opportunities",
"Can analyze trading pairs across different exchanges",
"Monitors market conditions in real-time"
],
"messageExamples": [
[
{
"user": "{{user1}}",
"content": { "text": "analyze BTC/ETH pair for arbitrage opportunities" }
},
{
"user": "Trader",
"content": {
"text": "I'll analyze the BTC/ETH trading pair for potential arbitrage opportunities across different exchanges."
}
}
],
[
{
"user": "{{user1}}",
"content": { "text": "check current market conditions" }
},
{
"user": "Trader",
"content": {
"text": "I'll check the current market conditions and look for profitable trading opportunities."
}
}
]
],
"postExamples": [
"Market Analysis: Current arbitrage opportunities in the BTC/ETH market",
"Trading Update: Identified profitable arbitrage paths between exchanges",
"Market Alert: Significant price divergence detected between exchanges",
"Strategy Overview: Best practices for arbitrage trading"
],
"topics": [
"cryptocurrency trading",
"arbitrage opportunities",
"market analysis",
"trading strategies",
"price analysis",
"exchange monitoring",
"risk management",
"trading automation"
],
"adjectives": [
"analytical",
"precise",
"professional",
"strategic",
"vigilant",
"data-driven",
"methodical",
"efficient"
],
"style": {
"all": [
"Keep responses clear and data-driven",
"Focus on market opportunities",
"Provide actionable insights",
"Be professional and precise",
"Use clear market terminology",
"Always consider risk management"
],
"chat": [
"Provide detailed market analysis",
"Be direct and informative",
"Focus on actionable opportunities",
"Maintain professional tone"
],
"post": [
"Share clear market insights",
"Highlight significant opportunities",
"Include relevant market data",
"Maintain analytical perspective"
]
}
}
49 changes: 49 additions & 0 deletions packages/plugin-arbitrage/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@elizaos/plugin-arbitrage",
"version": "0.1.0",
"description": "Arbitrage trading plugin for Eliza",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"default": "./dist/index.js"
}
},
"scripts": {
"clean": "rm -rf dist",
"build": "tsup --format esm --dts",
"dev": "tsup --format esm --dts --watch"
},
"dependencies": {
"@elizaos/adapter-sqlite": "^0.1.8",
"@elizaos/core": "workspace:*",
"@ethersproject/abi": "^5.7.0",
"@ethersproject/abstract-provider": "^5.7.0",
"@ethersproject/address": "^5.7.0",
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@ethersproject/units": "^5.7.0",
"@ethersproject/wallet": "^5.7.0",
"@flashbots/ethers-provider-bundle": "0.6.2",
"dotenv": "^16.4.7",
"ethers": "5.7.2",
"lodash": "^4.17.21",
"ws": "^8.18.0"
},
"devDependencies": {
"@types/lodash": "^4.17.14",
"@types/node": "^22.10.9",
"@types/ws": "^8.5.13",
"rimraf": "^5.0.5",
"typescript": "^5.7.3",
"@types/dotenv": "^8.2.0",
"tsup": "^8.0.2"
},
"peerDependencies": {
"@elizaos/core": "workspace:*"
}
}
40 changes: 40 additions & 0 deletions packages/plugin-arbitrage/src/actions/arbitrageAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Action, IAgentRuntime, Memory, ServiceType } from "@elizaos/core";
import { ArbitrageService } from "../services/ArbitrageService";

export const executeArbitrageAction: Action = {
name: "EXECUTE_ARBITRAGE",
similes: ["TRADE_ARBITRAGE", "RUN_ARBITRAGE"],
description: "Execute arbitrage trades across markets",

validate: async (runtime: IAgentRuntime, message: Memory) => {
// Validate settings are present
return runtime.getSetting("arbitrage.walletPrivateKey") !== undefined;
},

handler: async (runtime: IAgentRuntime, message: Memory) => {
const service = runtime.getService(ServiceType.ARBITRAGE) as ArbitrageService;
const markets = await service.evaluateMarkets();

if (markets.length > 0) {
await service.executeArbitrage(markets);
}

return true;
},

examples: [
[
{
user: "{{user1}}",
content: { text: "Find arbitrage opportunities" }
},
{
user: "{{user2}}",
content: {
text: "Scanning for arbitrage trades",
action: "EXECUTE_ARBITRAGE"
}
}
]
]
};
18 changes: 18 additions & 0 deletions packages/plugin-arbitrage/src/config/addresses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const UNISWAP_LOOKUP_CONTRACT_ADDRESS = '0x5EF1009b9FCD4fec3094a5564047e190D72Bd511'
//mainnet ^^ goerli vv
//export const UNISWAP_LOOKUP_CONTRACT_ADDRESS = '0xF52FE911458C6a3279832b764cDF0189e49f073A'
export const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
export const SUSHISWAP_FACTORY_ADDRESS = '0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac';
export const UNISWAP_FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f';

//export const CRO_FACTORY_ADDRESS = "0x9DEB29c9a4c7A88a3C0257393b7f3335338D9A9D";
//export const ZEUS_FACTORY_ADDRESS = "0xbdda21dd8da31d5bee0c9bb886c044ebb9b8906a";
//export const LUA_FACTORY_ADDRESS = "0x0388c1e0f210abae597b7de712b9510c6c36c857";

export const FACTORY_ADDRESSES = [
//CRO_FACTORY_ADDRESS,
//ZEUS_FACTORY_ADDRESS,
//LUA_FACTORY_ADDRESS,
SUSHISWAP_FACTORY_ADDRESS,
UNISWAP_FACTORY_ADDRESS,
]
15 changes: 15 additions & 0 deletions packages/plugin-arbitrage/src/config/thresholds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BigNumber } from "ethers";

export interface MarketThresholds {
minProfitThreshold: BigNumber;
maxTradeSize: BigNumber;
gasLimit: number;
minerRewardPercentage: number;
}

export const DEFAULT_THRESHOLDS: MarketThresholds = {
minProfitThreshold: BigNumber.from("100000000000000"), // 0.0001 ETH
maxTradeSize: BigNumber.from("1000000000000000000"), // 1 ETH
gasLimit: 500000,
minerRewardPercentage: 90
};
Loading
Loading