Skip to content

Commit

Permalink
feat: 0x plugin (#2329)
Browse files Browse the repository at this point in the history
* draft commit

* remove useless file

* update readme

* Update packages/plugin-0x/src/EVMtokenRegistry.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update packages/plugin-0x/src/EVMtokenRegistry.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update packages/plugin-0x/src/actions/swap.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update packages/plugin-0x/src/actions/getIndicativePrice.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update packages/plugin-0x/src/actions/getQuote.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update packages/plugin-0x/src/hooks.ts/useGetWalletClient.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* refactor according to codeRabbit

* fix syntax error, remove mode=json from Anthropic

* remove unnecessary logging

* remove changes to mode=json for generation

* remove ai from packagejson, its in core/package.json already

* resolve pnpm-lock

* Update pnpm-lock.yaml

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Sayo <[email protected]>
  • Loading branch information
3 people authored Jan 21, 2025
1 parent cac3912 commit d51ab66
Show file tree
Hide file tree
Showing 18 changed files with 2,024 additions and 45 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,10 @@ AKASH_MANIFEST_VALIDATION_LEVEL=strict
QUAI_PRIVATE_KEY=
QUAI_RPC_URL=https://rpc.quai.network

# 0x
ZERO_EX_API_KEY=
ALCHEMY_HTTP_TRANSPORT_URL=

# Instagram Configuration
INSTAGRAM_DRY_RUN=false
INSTAGRAM_USERNAME= # Account username
Expand Down
2 changes: 2 additions & 0 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ import { zksyncEraPlugin } from "@elizaos/plugin-zksync-era";

import { nvidiaNimPlugin } from "@elizaos/plugin-nvidia-nim";

import { zxPlugin } from "@elizaos/plugin-0x";
import Database from "better-sqlite3";
import fs from "fs";
import net from "net";
Expand Down Expand Up @@ -1081,6 +1082,7 @@ export async function createAgent(
getSecret(character, "RESERVOIR_API_KEY")
? createNFTCollectionsPlugin()
: null,
getSecret(character, "ZERO_EX_API_KEY") ? zxPlugin : null,
getSecret(character, "PYTH_TESTNET_PROGRAM_KEY") ||
getSecret(character, "PYTH_MAINNET_PROGRAM_KEY")
? pythDataPlugin
Expand Down
63 changes: 41 additions & 22 deletions packages/core/src/generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,14 @@ export async function generateText({
const openai = createOpenAI({
apiKey,
baseURL: endpoint,
fetch: async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
const url = typeof input === 'string' ? input : input.toString();
fetch: async (
input: RequestInfo | URL,
init?: RequestInit
): Promise<Response> => {
const url =
typeof input === "string"
? input
: input.toString();
const chain_id =
runtime.getSetting("ETERNALAI_CHAIN_ID") || "45762";

Expand All @@ -588,9 +594,11 @@ export async function generateText({

const fetching = await runtime.fetch(url, options);

if (parseBooleanFromText(
runtime.getSetting("ETERNALAI_LOG")
)) {
if (
parseBooleanFromText(
runtime.getSetting("ETERNALAI_LOG")
)
) {
elizaLogger.info(
"Request data: ",
JSON.stringify(options, null, 2)
Expand Down Expand Up @@ -1226,30 +1234,35 @@ export async function generateText({
messages: [
{
role: "system",
content: runtime.character.system ?? settings.SYSTEM_PROMPT ?? "You are a helpful assistant"
content:
runtime.character.system ??
settings.SYSTEM_PROMPT ??
"You are a helpful assistant",
},
{
role: "user",
content: context
}
content: context,
},
],
max_tokens: max_response_length,
stream: false
stream: false,
};

const fetchResponse = await runtime.fetch(endpoint+'/llm', {
const fetchResponse = await runtime.fetch(endpoint + "/llm", {
method: "POST",
headers: {
"accept": "text/event-stream",
accept: "text/event-stream",
"Content-Type": "application/json",
"Authorization": "Bearer eliza-app-llm"
Authorization: "Bearer eliza-app-llm",
},
body: JSON.stringify(requestBody)
body: JSON.stringify(requestBody),
});

if (!fetchResponse.ok) {
const errorText = await fetchResponse.text();
throw new Error(`Livepeer request failed (${fetchResponse.status}): ${errorText}`);
throw new Error(
`Livepeer request failed (${fetchResponse.status}): ${errorText}`
);
}

const json = await fetchResponse.json();
Expand All @@ -1258,8 +1271,13 @@ export async function generateText({
throw new Error("Invalid response format from Livepeer");
}

response = json.choices[0].message.content.replace(/<\|start_header_id\|>assistant<\|end_header_id\|>\n\n/, '');
elizaLogger.debug("Successfully received response from Livepeer model");
response = json.choices[0].message.content.replace(
/<\|start_header_id\|>assistant<\|end_header_id\|>\n\n/,
""
);
elizaLogger.debug(
"Successfully received response from Livepeer model"
);
break;
}

Expand Down Expand Up @@ -1641,8 +1659,8 @@ export const generateImage = async (
return runtime.getSetting("FAL_API_KEY");
case ModelProviderName.OPENAI:
return runtime.getSetting("OPENAI_API_KEY");
case ModelProviderName.VENICE:
return runtime.getSetting("VENICE_API_KEY");
case ModelProviderName.VENICE:
return runtime.getSetting("VENICE_API_KEY");
case ModelProviderName.LIVEPEER:
return runtime.getSetting("LIVEPEER_GATEWAY_URL");
default:
Expand Down Expand Up @@ -2485,12 +2503,14 @@ async function handleLivepeer({
}: ProviderOptions): Promise<GenerateObjectResult<unknown>> {
console.log("Livepeer provider api key:", apiKey);
if (!apiKey) {
throw new Error("Livepeer provider requires LIVEPEER_GATEWAY_URL to be configured");
throw new Error(
"Livepeer provider requires LIVEPEER_GATEWAY_URL to be configured"
);
}

const livepeerClient = createOpenAI({
apiKey,
baseURL: apiKey // Use the apiKey as the baseURL since it contains the gateway URL
baseURL: apiKey, // Use the apiKey as the baseURL since it contains the gateway URL
});

return await aiGenerateObject({
Expand All @@ -2503,7 +2523,6 @@ async function handleLivepeer({
});
}


// Add type definition for Together AI response
interface TogetherAIImageResponse {
data: Array<{
Expand Down Expand Up @@ -2556,4 +2575,4 @@ export async function generateTweetActions({
await new Promise((resolve) => setTimeout(resolve, retryDelay));
retryDelay *= 2;
}
}
}
86 changes: 86 additions & 0 deletions packages/plugin-0x/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# @elizaos/plugin-0x

This plugin enables Eliza to interact with the 0x Protocol, providing decentralized exchange capabilities across multiple evm blockchain networks with optimized token swaps and liquidity aggregation.

Supported networks include:
- Ethereum Mainnet
- Polygon
- Binance Smart Chain
- Arbitrum
- Optimism
- Base
- Linea
- Scroll
- Avalanche
- Blast

## Configuration

Set the following environment variables:

```env
WALLET_PRIVATE_KEY=your_private_key
ZERO_EX_API_KEY=your_0x_api_key
{chain}_RPC_URL=your_rpc_endpoint
```

## Installation

```bash
pnpm install @elizaos/plugin-0x
```

## Usage

### Basic Integration

```typescript
import { zeroExPlugin } from "@elizaos/plugin-0x";
```

### Example Usage

The plugin supports natural language commands for ETH transfers:

```typescript
"I want to convert 1 ETH to USDC on ethereum chain";
"Give me the quote";
"Execute it";
```

## Available Actions

The plugin provides the following actions:

1. **GET_INDICATIVE_PRICE_0X**: Get indicative prices for token swaps
- Example: "Get quote for swapping 1 ETH to USDC on Ethereum chain"
- Example: "Price check for trading 100 USDT to MATIC on Polygon chain"

2. **GET_QUOTE_0X**: Get the quote for the swap. Quote expires in 5mins. (This action is triggered only after user has requested for an indicative price. No need to repeat the buy/sell tokens because the last indicative price will be stored in the memory)
- Example: "Get quote"

3. **EXECUTE_SWAP_0X**: Execute token swaps. (Action is triggered only after user has gotten a quote)
- Example: "Execute the swap"

## Security Best Practices

1. **Environment Variables**
- Never commit private keys to version control
- Use secure environment variable management
- Rotate private keys periodically

## Contributing

Contributions are welcome! Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for more information.

## Credits

This plugin integrates with:
- [0x Protocol](https://0x.org/)

For more information about 0x capabilities:
- [0x API Documentation](https://0x.org/docs/api)

## License

This plugin is part of the Eliza project. See the main project repository for license information.
36 changes: 36 additions & 0 deletions packages/plugin-0x/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@elizaos/plugin-0x",
"version": "0.1.8",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"@elizaos/source": "./src/index.ts",
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsup --format esm --dts",
"dev": "tsup --format esm --dts --watch",
"test": "vitest"
},
"dependencies": {
"@0x/swap-ts-sdk": "2.1.1"
},
"devDependencies": {
"tsup": "^8.0.1"
},
"peerDependencies": {
"@elizaos/core": "workspace:*",
"zod": "^3.22.4"
}
}
Loading

0 comments on commit d51ab66

Please sign in to comment.