Skip to content

Commit 13b212d

Browse files
authored
Merge pull request #608 from monilpat/realitySpiral/coinbaseTrading
feat: implement coinbase trading
2 parents d0093cc + cd98ff9 commit 13b212d

20 files changed

+4515
-218
lines changed

.env.example

+6-2
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,15 @@ ZEROG_PRIVATE_KEY=
141141
ZEROG_FLOW_ADDRESS=
142142

143143

144-
# Coinbase Commerce
144+
# Coinbase
145145
COINBASE_COMMERCE_KEY=
146+
COINBASE_API_KEY=
147+
COINBASE_PRIVATE_KEY=
148+
149+
COINBASE_GENERATED_WALLET_ID=
150+
COINBASE_GENERATED_WALLET_HEX_SEED=
146151

147152

148153
# TEE Configuration
149154
DSTACK_SIMULATOR_ENDPOINT=
150155
WALLET_SECRET_SALT=secret_salt
151-

agent/src/index.ts

+33-18
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { bootstrapPlugin } from "@ai16z/plugin-bootstrap";
2828
import {
2929
coinbaseCommercePlugin,
3030
coinbaseMassPaymentsPlugin,
31+
tradePlugin,
3132
} from "@ai16z/plugin-coinbase";
3233
import { confluxPlugin } from "@ai16z/plugin-conflux";
3334
import { evmPlugin } from "@ai16z/plugin-evm";
@@ -85,21 +86,31 @@ function tryLoadFile(filePath: string): string | null {
8586
export async function loadCharacters(
8687
charactersArg: string
8788
): Promise<Character[]> {
88-
let characterPaths = charactersArg?.split(",").map((filePath) => filePath.trim());
89+
let characterPaths = charactersArg
90+
?.split(",")
91+
.map((filePath) => filePath.trim());
8992
const loadedCharacters = [];
9093

9194
if (characterPaths?.length > 0) {
9295
for (const characterPath of characterPaths) {
9396
let content = null;
9497
let resolvedPath = "";
95-
98+
9699
// Try different path resolutions in order
97100
const pathsToTry = [
98101
characterPath, // exact path as specified
99102
path.resolve(process.cwd(), characterPath), // relative to cwd
100103
path.resolve(__dirname, characterPath), // relative to current script
101-
path.resolve(__dirname, "../characters", path.basename(characterPath)), // relative to characters dir from agent
102-
path.resolve(__dirname, "../../characters", path.basename(characterPath)), // relative to project root characters dir
104+
path.resolve(
105+
__dirname,
106+
"../characters",
107+
path.basename(characterPath)
108+
), // relative to characters dir from agent
109+
path.resolve(
110+
__dirname,
111+
"../../characters",
112+
path.basename(characterPath)
113+
), // relative to project root characters dir
103114
];
104115

105116
for (const tryPath of pathsToTry) {
@@ -111,9 +122,11 @@ export async function loadCharacters(
111122
}
112123

113124
if (content === null) {
114-
elizaLogger.error(`Error loading character from ${characterPath}: File not found in any of the expected locations`);
125+
elizaLogger.error(
126+
`Error loading character from ${characterPath}: File not found in any of the expected locations`
127+
);
115128
elizaLogger.error("Tried the following paths:");
116-
pathsToTry.forEach(p => elizaLogger.error(` - ${p}`));
129+
pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));
117130
process.exit(1);
118131
}
119132

@@ -134,9 +147,13 @@ export async function loadCharacters(
134147
}
135148

136149
loadedCharacters.push(character);
137-
elizaLogger.info(`Successfully loaded character from: ${resolvedPath}`);
150+
elizaLogger.info(
151+
`Successfully loaded character from: ${resolvedPath}`
152+
);
138153
} catch (e) {
139-
elizaLogger.error(`Error parsing character from ${resolvedPath}: ${e}`);
154+
elizaLogger.error(
155+
`Error parsing character from ${resolvedPath}: ${e}`
156+
);
140157
process.exit(1);
141158
}
142159
}
@@ -285,7 +302,7 @@ export function createAgent(
285302
character.name
286303
);
287304

288-
nodePlugin ??= createNodePlugin()
305+
nodePlugin ??= createNodePlugin();
289306

290307
return new AgentRuntime({
291308
databaseAdapter: db,
@@ -300,25 +317,23 @@ export function createAgent(
300317
: null,
301318
nodePlugin,
302319
getSecret(character, "SOLANA_PUBLIC_KEY") ||
303-
getSecret(character, "WALLET_PUBLIC_KEY") &&
304-
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")
320+
(getSecret(character, "WALLET_PUBLIC_KEY") &&
321+
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x"))
305322
? solanaPlugin
306323
: null,
307324
getSecret(character, "EVM_PUBLIC_KEY") ||
308-
getSecret(character, "WALLET_PUBLIC_KEY") &&
309-
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")
325+
(getSecret(character, "WALLET_PUBLIC_KEY") &&
326+
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x"))
310327
? evmPlugin
311328
: null,
312329
getSecret(character, "ZEROG_PRIVATE_KEY") ? zgPlugin : null,
313330
getSecret(character, "COINBASE_COMMERCE_KEY")
314331
? coinbaseCommercePlugin
315332
: null,
316-
getSecret(character, "COINBASE_API_KEY") &&
333+
...(getSecret(character, "COINBASE_API_KEY") &&
317334
getSecret(character, "COINBASE_PRIVATE_KEY")
318-
? coinbaseMassPaymentsPlugin
319-
: null,
320-
getSecret(character, "BUTTPLUG_API_KEY") ? buttplugPlugin : null,
321-
getSecret(character, "WALLET_SECRET_SALT") ? teePlugin : null,
335+
? [coinbaseMassPaymentsPlugin, tradePlugin]
336+
: []),
322337
].filter(Boolean),
323338
providers: [],
324339
actions: [],

docs/docs/packages/plugins.md

+144-26
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,44 @@ This plugin enables Eliza to interact with the Coinbase Commerce API to create a
225225

226226
---
227227

228+
### Coinbase Wallet Management
229+
230+
The plugin automatically handles wallet creation or uses an existing wallet if the required details are provided during the first run.
231+
232+
1. **Wallet Generation on First Run**
233+
If no wallet information is provided (`COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID`), the plugin will:
234+
235+
- **Generate a new wallet** using the Coinbase SDK.
236+
- Automatically **export the wallet details** (`seed` and `walletId`) and securely store them in `runtime.character.settings.secrets` or other configured storage.
237+
- Log the wallet’s default address for reference.
238+
- If the character file does not exist, the wallet details are saved to a characters/charactername-seed.txt file in the characters directory with a note indicating that the user must manually add these details to settings.secrets or the .env file.
239+
240+
2. **Using an Existing Wallet**
241+
If wallet information is available during the first run:
242+
- Provide `COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID` via `runtime.character.settings.secrets` or environment variables.
243+
- The plugin will **import the wallet** and use it for processing mass payouts.
244+
245+
---
246+
247+
### Coinbase Wallet Management
248+
249+
The plugin automatically handles wallet creation or uses an existing wallet if the required details are provided during the first run.
250+
251+
1. **Wallet Generation on First Run**
252+
If no wallet information is provided (`COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID`), the plugin will:
253+
254+
- **Generate a new wallet** using the Coinbase SDK.
255+
- Automatically **export the wallet details** (`seed` and `walletId`) and securely store them in `runtime.character.settings.secrets` or other configured storage.
256+
- Log the wallet’s default address for reference.
257+
- If the character file does not exist, the wallet details are saved to a characters/charactername-seed.txt file in the characters directory with a note indicating that the user must manually add these details to settings.secrets or the .env file.
258+
259+
2. **Using an Existing Wallet**
260+
If wallet information is available during the first run:
261+
- Provide `COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID` via `runtime.character.settings.secrets` or environment variables.
262+
- The plugin will **import the wallet** and use it for processing mass payouts.
263+
264+
---
265+
228266
#### 6. Coinbase MassPayments Plugin (`@eliza/plugin-coinbase`)
229267

230268
This plugin facilitates the processing of cryptocurrency mass payouts using the Coinbase SDK. It enables the creation and management of mass payouts to multiple wallet addresses, logging all transaction details to a CSV file for further analysis.
@@ -311,7 +349,6 @@ The plugin automatically handles wallet creation or uses an existing wallet if t
311349
- Provide `COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID` via `runtime.character.settings.secrets` or environment variables.
312350
- The plugin will **import the wallet** and use it for processing mass payouts.
313351

314-
315352
**Required Configurations:**
316353

317354
The following configurations must be provided for wallet management:
@@ -321,8 +358,9 @@ The following configurations must be provided for wallet management:
321358
- `COINBASE_GENERATED_WALLET_ID`: Unique wallet ID.
322359
- These variables must be securely stored in `runtime.character.settings.secrets` or as environment variables.
323360

361+
---
324362

325-
**Wallet Creation Process:**
363+
### Wallet Creation Process
326364

327365
1. **Automatic Wallet Creation**
328366
When no wallet details are available:
@@ -449,37 +487,117 @@ const provider = new DeriveKeyProvider();
449487
450488
// Derive a raw key
451489
try {
452-
const rawKey = await provider.rawDeriveKey(
453-
"/path/to/derive",
454-
"subject-identifier"
455-
);
456-
// rawKey is a DeriveKeyResponse that can be used for further processing
457-
// to get the uint8Array do the following
458-
const rawKeyArray = rawKey.asUint8Array()
490+
const rawKey = await provider.rawDeriveKey(
491+
"/path/to/derive",
492+
"subject-identifier",
493+
);
494+
// rawKey is a DeriveKeyResponse that can be used for further processing
495+
// to get the uint8Array do the following
496+
const rawKeyArray = rawKey.asUint8Array();
497+
} catch (error) {
498+
console.error("Raw key derivation failed:", error);
499+
}
500+
501+
// Derive a Solana keypair (Ed25519)
502+
try {
503+
const solanaKeypair = await provider.deriveEd25519Keypair(
504+
"/path/to/derive",
505+
"subject-identifier",
506+
);
507+
// solanaKeypair can now be used for Solana operations
508+
} catch (error) {
509+
console.error("Solana key derivation failed:", error);
510+
}
511+
512+
// Derive an Ethereum keypair (ECDSA)
513+
try {
514+
const evmKeypair = await provider.deriveEcdsaKeypair(
515+
"/path/to/derive",
516+
"subject-identifier",
517+
);
518+
// evmKeypair can now be used for Ethereum operations
519+
} catch (error) {
520+
console.error("EVM key derivation failed:", error);
521+
}
522+
```
523+
524+
**RemoteAttestationProvider Usage**
525+
526+
```typescript
527+
import { RemoteAttestationProvider } from "@ai16z/plugin-tee";
528+
// Initialize the provider
529+
const provider = new RemoteAttestationProvider();
530+
// Generate Remote Attestation
531+
try {
532+
const attestation = await provider.generateAttestation("your-report-data");
533+
console.log("Attestation:", attestation);
534+
} catch (error) {
535+
console.error("Failed to generate attestation:", error);
536+
}
537+
```
538+
539+
**Configuration**
540+
541+
When using the provider through the runtime environment, ensure the following settings are configured:
542+
543+
```env
544+
# Optional, for simulator purposes if testing on mac or windows. Leave empty for Linux x86 machines.
545+
DSTACK_SIMULATOR_ENDPOINT="http://host.docker.internal:8090"
546+
WALLET_SECRET_SALT=your-secret-salt // Required to single agent deployments
547+
```
548+
549+
---
550+
551+
#### 7. TEE Plugin (`@ai16z/plugin-tee`)
552+
553+
Integrates [Dstack SDK](https://github.com/Dstack-TEE/dstack) to enable TEE (Trusted Execution Environment) functionality and deploy secure & privacy-enhanced Eliza Agents:
554+
555+
**Providers:**
556+
557+
- `deriveKeyProvider` - Allows for secure key derivation within a TEE environment. It supports deriving keys for both Solana (Ed25519) and Ethereum (ECDSA) chains.
558+
- `remoteAttestationProvider` - Generate a Remote Attestation Quote based on `report_data`.
559+
560+
**DeriveKeyProvider Usage**
561+
562+
```typescript
563+
import { DeriveKeyProvider } from "@ai16z/plugin-tee";
564+
565+
// Initialize the provider
566+
const provider = new DeriveKeyProvider();
567+
568+
// Derive a raw key
569+
try {
570+
const rawKey = await provider.rawDeriveKey(
571+
"/path/to/derive",
572+
"subject-identifier",
573+
);
574+
// rawKey is a DeriveKeyResponse that can be used for further processing
575+
// to get the uint8Array do the following
576+
const rawKeyArray = rawKey.asUint8Array();
459577
} catch (error) {
460-
console.error("Raw key derivation failed:", error);
578+
console.error("Raw key derivation failed:", error);
461579
}
462580
463581
// Derive a Solana keypair (Ed25519)
464582
try {
465-
const solanaKeypair = await provider.deriveEd25519Keypair(
466-
"/path/to/derive",
467-
"subject-identifier"
468-
);
469-
// solanaKeypair can now be used for Solana operations
583+
const solanaKeypair = await provider.deriveEd25519Keypair(
584+
"/path/to/derive",
585+
"subject-identifier",
586+
);
587+
// solanaKeypair can now be used for Solana operations
470588
} catch (error) {
471-
console.error("Solana key derivation failed:", error);
589+
console.error("Solana key derivation failed:", error);
472590
}
473591
474592
// Derive an Ethereum keypair (ECDSA)
475593
try {
476-
const evmKeypair = await provider.deriveEcdsaKeypair(
477-
"/path/to/derive",
478-
"subject-identifier"
479-
);
480-
// evmKeypair can now be used for Ethereum operations
594+
const evmKeypair = await provider.deriveEcdsaKeypair(
595+
"/path/to/derive",
596+
"subject-identifier",
597+
);
598+
// evmKeypair can now be used for Ethereum operations
481599
} catch (error) {
482-
console.error("EVM key derivation failed:", error);
600+
console.error("EVM key derivation failed:", error);
483601
}
484602
```
485603

@@ -491,10 +609,10 @@ import { RemoteAttestationProvider } from "@ai16z/plugin-tee";
491609
const provider = new RemoteAttestationProvider();
492610
// Generate Remote Attestation
493611
try {
494-
const attestation = await provider.generateAttestation("your-report-data");
495-
console.log("Attestation:", attestation);
612+
const attestation = await provider.generateAttestation("your-report-data");
613+
console.log("Attestation:", attestation);
496614
} catch (error) {
497-
console.error("Failed to generate attestation:", error);
615+
console.error("Failed to generate attestation:", error);
498616
}
499617
```
500618

@@ -508,7 +626,7 @@ DSTACK_SIMULATOR_ENDPOINT="http://host.docker.internal:8090"
508626
WALLET_SECRET_SALT=your-secret-salt // Required to single agent deployments
509627
```
510628

511-
___
629+
---
512630

513631
### Writing Custom Plugins
514632

package.json

+9-5
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
"devDependencies": {
2626
"@commitlint/cli": "^18.4.4",
2727
"@commitlint/config-conventional": "^18.4.4",
28-
"lerna": "8.1.5",
29-
"only-allow": "1.2.1",
3028
"concurrently": "9.1.0",
3129
"husky": "9.1.7",
30+
"lerna": "8.1.5",
31+
"only-allow": "1.2.1",
3232
"prettier": "3.3.3",
3333
"typedoc": "0.26.11",
3434
"typescript": "5.6.3",
@@ -44,14 +44,18 @@
4444
"node": "23.3.0"
4545
},
4646
"dependencies": {
47-
"@coinbase/coinbase-sdk": "^0.10.0",
48-
"csv-parse": "^5.6.0",
4947
"@0glabs/0g-ts-sdk": "^0.2.1",
5048
"amqplib": "0.10.5",
49+
"@ai16z/eliza": "0.1.4-alpha.3",
50+
"@coinbase/coinbase-sdk": "^0.10.0",
51+
"csv-parse": "^5.6.0",
5152
"ollama-ai-provider": "^0.16.1",
5253
"optional": "^0.1.4",
5354
"sharp": "^0.33.5",
5455
"tslog": "^4.9.3"
5556
},
56-
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee"
57+
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
58+
"workspaces": [
59+
"packages/*"
60+
]
5761
}

0 commit comments

Comments
 (0)