Skip to content

Commit 2eb5298

Browse files
author
vasox276
committedJan 12, 2025
Add GoldRush plugin
1 parent 52e9c74 commit 2eb5298

File tree

10 files changed

+730
-0
lines changed

10 files changed

+730
-0
lines changed
 
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# @elizaos/plugin-goldrush
2+
3+
A plugin for ElizaOS that integrates Covalent's GoldRush SDK for cross-chain wallet monitoring.
4+
5+
## Features
6+
7+
- Cross-chain wallet balance tracking (in chain's native currency)
8+
- Basic transaction history (last 10 transactions)
9+
- Support for multiple chains:
10+
- Ethereum
11+
- Solana
12+
- Algorand
13+
- Aptos
14+
- Cosmos
15+
- Tron
16+
- Comprehensive error handling and logging
17+
18+
## Installation
19+
20+
```bash
21+
pnpm add @elizaos/plugin-goldrush
22+
```
23+
24+
## Configuration
25+
26+
1. Get a Covalent API key from [Covalent](https://www.covalenthq.com/platform/auth/register/)
27+
28+
2. Add your API key to your ElizaOS environment:
29+
30+
```bash
31+
# .env file
32+
COVALENT_API_KEY=your_api_key_here
33+
```
34+
35+
3. Add the plugin to your ElizaOS configuration:
36+
37+
```typescript
38+
import { goldrushPlugin } from "@elizaos/plugin-goldrush";
39+
40+
// The plugin will be automatically loaded if COVALENT_API_KEY is present
41+
const config = {
42+
plugins: [goldrushPlugin],
43+
};
44+
```
45+
46+
## Usage
47+
48+
The plugin provides a provider that can be used to fetch wallet data:
49+
50+
```typescript
51+
try {
52+
// Get wallet data - note that runtime parameter is required
53+
const result = await runtime.providers.goldrush.get(runtime, {
54+
address: "0x123...",
55+
chain: "eth-mainnet" // Optional, defaults to eth-mainnet
56+
});
57+
58+
// The result includes:
59+
{
60+
address: string; // The wallet address
61+
balance: string; // Balance in chain's native currency (e.g., ETH for Ethereum)
62+
transactions: string[]; // Array of transaction hashes (up to 10 most recent)
63+
lastUpdated: number; // Timestamp of when the data was fetched
64+
}
65+
} catch (error) {
66+
// Handle specific error cases
67+
if (error.message.includes("Invalid Ethereum address")) {
68+
console.error("The provided address is not a valid Ethereum address");
69+
} else if (error.message.includes("Unsupported chain")) {
70+
console.error("The specified blockchain is not supported");
71+
} else if (error.message.includes("Invalid API key")) {
72+
console.error("Please check your Covalent API key configuration");
73+
} else {
74+
console.error("An error occurred while fetching wallet data:", error);
75+
}
76+
}
77+
```
78+
79+
## Supported Chains
80+
81+
- eth-mainnet (Ethereum Mainnet)
82+
- solana-mainnet
83+
- algorand-mainnet
84+
- aptos-mainnet
85+
- cosmos-mainnet
86+
- tron-mainnet
87+
88+
## Error Messages
89+
90+
The provider may throw the following errors:
91+
92+
- `"Covalent API key is required"` - When initializing without an API key
93+
- `"Invalid API key"` - When the provided API key is invalid
94+
- `"Wallet address is required"` - When calling get() without an address
95+
- `"Invalid Ethereum address format"` - When the address doesn't match the expected format
96+
- `"Unsupported chain: {chain}"` - When the specified chain is not supported
97+
- `"Failed to fetch wallet balances"` - When the Covalent API request fails
98+
- `"An unknown error occurred while fetching wallet data"` - For unexpected errors
99+
100+
## Error Handling
101+
102+
The provider includes error handling for common scenarios:
103+
104+
- Invalid API key validation on initialization
105+
- Invalid wallet address format checking
106+
- Unsupported chain validation
107+
- Network error handling with appropriate error messages
108+
- Graceful handling of failed transaction fetches (continues with empty array)
109+
110+
## License
111+
112+
MIT
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@elizaos/plugin-goldrush",
3+
"version": "0.1.0",
4+
"description": "Covalent GoldRush SDK integration for wallet monitoring and analytics",
5+
"type": "module",
6+
"main": "dist/index.js",
7+
"module": "dist/index.js",
8+
"types": "dist/index.d.ts",
9+
"exports": {
10+
".": {
11+
"@elizaos/source": "./src/index.ts",
12+
"types": "./dist/index.d.ts",
13+
"default": "./dist/index.js"
14+
}
15+
},
16+
"files": [
17+
"dist"
18+
],
19+
"scripts": {
20+
"build": "tsup",
21+
"dev": "tsup --watch",
22+
"lint": "eslint src/**/*.ts",
23+
"test": "vitest run",
24+
"test:watch": "vitest",
25+
"test:coverage": "vitest run --coverage"
26+
},
27+
"dependencies": {
28+
"@elizaos/core": "workspace:*",
29+
"@covalenthq/client-sdk": "^0.7.3"
30+
},
31+
"devDependencies": {
32+
"tsup": "^8.0.1",
33+
"vitest": "^1.2.1"
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { describe, it, expect, beforeAll } from "vitest";
2+
import { GoldRushProvider } from "../index";
3+
import type { IAgentRuntime } from "@elizaos/core";
4+
5+
// Using a test address with minimal transactions
6+
const TEST_ADDRESS = "0x1234567890123456789012345678901234567890";
7+
8+
// Mock runtime
9+
const mockRuntime: IAgentRuntime = {
10+
logger: console,
11+
config: {
12+
COVALENT_API_KEY: process.env.COVALENT_API_KEY || "",
13+
},
14+
};
15+
16+
describe("GoldRush Plugin Tests", () => {
17+
let provider: GoldRushProvider;
18+
19+
beforeAll(async () => {
20+
const apiKey = process.env.COVALENT_API_KEY;
21+
if (!apiKey) {
22+
throw new Error(
23+
"COVALENT_API_KEY environment variable is required"
24+
);
25+
}
26+
provider = new GoldRushProvider(apiKey);
27+
try {
28+
await provider.init();
29+
} catch (error) {
30+
console.error("Failed to initialize provider:", error);
31+
throw error;
32+
}
33+
}, 30000);
34+
35+
describe("Initialization", () => {
36+
it("should throw error when initialized without API key", () => {
37+
expect(() => new GoldRushProvider("")).toThrow(
38+
"Covalent API key is required"
39+
);
40+
});
41+
42+
it("should throw error with invalid API key", async () => {
43+
const invalidProvider = new GoldRushProvider("invalid_key");
44+
try {
45+
await invalidProvider.init();
46+
fail("Should have thrown an error");
47+
} catch (error) {
48+
expect(error).toBeDefined();
49+
expect(error instanceof Error).toBe(true);
50+
}
51+
});
52+
});
53+
54+
describe("Wallet Data Fetching", () => {
55+
it("should fetch wallet data from eth-mainnet", async () => {
56+
try {
57+
const result = await provider.get(mockRuntime, {
58+
address: TEST_ADDRESS,
59+
chain: "eth-mainnet",
60+
} as any);
61+
62+
expect(result).toBeDefined();
63+
expect(result.address).toBe(TEST_ADDRESS);
64+
expect(result.balance).toBeDefined();
65+
expect(Array.isArray(result.transactions)).toBe(true);
66+
expect(result.lastUpdated).toBeDefined();
67+
} catch (error) {
68+
console.error("Failed to fetch wallet data:", error);
69+
throw error;
70+
}
71+
}, 30000);
72+
73+
it("should handle missing address", async () => {
74+
await expect(provider.get(mockRuntime, {} as any)).rejects.toThrow(
75+
"Wallet address is required"
76+
);
77+
});
78+
79+
it("should handle invalid addresses", async () => {
80+
await expect(
81+
provider.get(mockRuntime, {
82+
address: "0xinvalid",
83+
chain: "eth-mainnet",
84+
} as any)
85+
).rejects.toThrow("Invalid Ethereum address");
86+
});
87+
88+
it("should handle unsupported chains", async () => {
89+
await expect(
90+
provider.get(mockRuntime, {
91+
address: TEST_ADDRESS,
92+
chain: "invalid-chain",
93+
} as any)
94+
).rejects.toThrow("Unsupported chain: invalid-chain");
95+
});
96+
97+
it("should handle network errors gracefully", async () => {
98+
// Mock a network error by using an invalid API key temporarily
99+
const originalApiKey = provider["client"].apiKey;
100+
provider["client"].apiKey = "invalid_key";
101+
102+
try {
103+
await provider.get(mockRuntime, {
104+
address: TEST_ADDRESS,
105+
chain: "eth-mainnet",
106+
} as any);
107+
fail("Should have thrown an error");
108+
} catch (error) {
109+
expect(error).toBeDefined();
110+
} finally {
111+
// Restore the valid API key
112+
provider["client"].apiKey = originalApiKey;
113+
}
114+
});
115+
});
116+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { config } from "dotenv";
2+
import { resolve } from "path";
3+
4+
// Load environment variables from .env file
5+
config({ path: resolve(__dirname, "../../../.env") });
6+
7+
// Add global test setup here if needed
8+
beforeAll(() => {
9+
// Verify required environment variables
10+
const requiredEnvVars = ["COVALENT_API_KEY"];
11+
const missing = requiredEnvVars.filter((key) => !process.env[key]);
12+
13+
if (missing.length > 0) {
14+
throw new Error(
15+
`Missing required environment variables: ${missing.join(", ")}`
16+
);
17+
}
18+
});

0 commit comments

Comments
 (0)