Skip to content

Commit

Permalink
Merge pull request elizaOS#608 from monilpat/realitySpiral/coinbaseTr…
Browse files Browse the repository at this point in the history
…ading

feat: implement coinbase trading
  • Loading branch information
jkbrooks authored Nov 28, 2024
2 parents d0093cc + cd98ff9 commit 13b212d
Show file tree
Hide file tree
Showing 20 changed files with 4,515 additions and 218 deletions.
8 changes: 6 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,15 @@ ZEROG_PRIVATE_KEY=
ZEROG_FLOW_ADDRESS=


# Coinbase Commerce
# Coinbase
COINBASE_COMMERCE_KEY=
COINBASE_API_KEY=
COINBASE_PRIVATE_KEY=

COINBASE_GENERATED_WALLET_ID=
COINBASE_GENERATED_WALLET_HEX_SEED=


# TEE Configuration
DSTACK_SIMULATOR_ENDPOINT=
WALLET_SECRET_SALT=secret_salt

51 changes: 33 additions & 18 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { bootstrapPlugin } from "@ai16z/plugin-bootstrap";
import {
coinbaseCommercePlugin,
coinbaseMassPaymentsPlugin,
tradePlugin,
} from "@ai16z/plugin-coinbase";
import { confluxPlugin } from "@ai16z/plugin-conflux";
import { evmPlugin } from "@ai16z/plugin-evm";
Expand Down Expand Up @@ -85,21 +86,31 @@ function tryLoadFile(filePath: string): string | null {
export async function loadCharacters(
charactersArg: string
): Promise<Character[]> {
let characterPaths = charactersArg?.split(",").map((filePath) => filePath.trim());
let characterPaths = charactersArg
?.split(",")
.map((filePath) => filePath.trim());
const loadedCharacters = [];

if (characterPaths?.length > 0) {
for (const characterPath of characterPaths) {
let content = null;
let resolvedPath = "";

// Try different path resolutions in order
const pathsToTry = [
characterPath, // exact path as specified
path.resolve(process.cwd(), characterPath), // relative to cwd
path.resolve(__dirname, characterPath), // relative to current script
path.resolve(__dirname, "../characters", path.basename(characterPath)), // relative to characters dir from agent
path.resolve(__dirname, "../../characters", path.basename(characterPath)), // relative to project root characters dir
path.resolve(
__dirname,
"../characters",
path.basename(characterPath)
), // relative to characters dir from agent
path.resolve(
__dirname,
"../../characters",
path.basename(characterPath)
), // relative to project root characters dir
];

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

if (content === null) {
elizaLogger.error(`Error loading character from ${characterPath}: File not found in any of the expected locations`);
elizaLogger.error(
`Error loading character from ${characterPath}: File not found in any of the expected locations`
);
elizaLogger.error("Tried the following paths:");
pathsToTry.forEach(p => elizaLogger.error(` - ${p}`));
pathsToTry.forEach((p) => elizaLogger.error(` - ${p}`));
process.exit(1);
}

Expand All @@ -134,9 +147,13 @@ export async function loadCharacters(
}

loadedCharacters.push(character);
elizaLogger.info(`Successfully loaded character from: ${resolvedPath}`);
elizaLogger.info(
`Successfully loaded character from: ${resolvedPath}`
);
} catch (e) {
elizaLogger.error(`Error parsing character from ${resolvedPath}: ${e}`);
elizaLogger.error(
`Error parsing character from ${resolvedPath}: ${e}`
);
process.exit(1);
}
}
Expand Down Expand Up @@ -285,7 +302,7 @@ export function createAgent(
character.name
);

nodePlugin ??= createNodePlugin()
nodePlugin ??= createNodePlugin();

return new AgentRuntime({
databaseAdapter: db,
Expand All @@ -300,25 +317,23 @@ export function createAgent(
: null,
nodePlugin,
getSecret(character, "SOLANA_PUBLIC_KEY") ||
getSecret(character, "WALLET_PUBLIC_KEY") &&
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")
(getSecret(character, "WALLET_PUBLIC_KEY") &&
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x"))
? solanaPlugin
: null,
getSecret(character, "EVM_PUBLIC_KEY") ||
getSecret(character, "WALLET_PUBLIC_KEY") &&
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x")
(getSecret(character, "WALLET_PUBLIC_KEY") &&
!getSecret(character, "WALLET_PUBLIC_KEY")?.startsWith("0x"))
? evmPlugin
: null,
getSecret(character, "ZEROG_PRIVATE_KEY") ? zgPlugin : null,
getSecret(character, "COINBASE_COMMERCE_KEY")
? coinbaseCommercePlugin
: null,
getSecret(character, "COINBASE_API_KEY") &&
...(getSecret(character, "COINBASE_API_KEY") &&
getSecret(character, "COINBASE_PRIVATE_KEY")
? coinbaseMassPaymentsPlugin
: null,
getSecret(character, "BUTTPLUG_API_KEY") ? buttplugPlugin : null,
getSecret(character, "WALLET_SECRET_SALT") ? teePlugin : null,
? [coinbaseMassPaymentsPlugin, tradePlugin]
: []),
].filter(Boolean),
providers: [],
actions: [],
Expand Down
170 changes: 144 additions & 26 deletions docs/docs/packages/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,44 @@ This plugin enables Eliza to interact with the Coinbase Commerce API to create a

---

### Coinbase Wallet Management

The plugin automatically handles wallet creation or uses an existing wallet if the required details are provided during the first run.

1. **Wallet Generation on First Run**
If no wallet information is provided (`COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID`), the plugin will:

- **Generate a new wallet** using the Coinbase SDK.
- Automatically **export the wallet details** (`seed` and `walletId`) and securely store them in `runtime.character.settings.secrets` or other configured storage.
- Log the wallet’s default address for reference.
- 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.

2. **Using an Existing Wallet**
If wallet information is available during the first run:
- Provide `COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID` via `runtime.character.settings.secrets` or environment variables.
- The plugin will **import the wallet** and use it for processing mass payouts.

---

### Coinbase Wallet Management

The plugin automatically handles wallet creation or uses an existing wallet if the required details are provided during the first run.

1. **Wallet Generation on First Run**
If no wallet information is provided (`COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID`), the plugin will:

- **Generate a new wallet** using the Coinbase SDK.
- Automatically **export the wallet details** (`seed` and `walletId`) and securely store them in `runtime.character.settings.secrets` or other configured storage.
- Log the wallet’s default address for reference.
- 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.

2. **Using an Existing Wallet**
If wallet information is available during the first run:
- Provide `COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID` via `runtime.character.settings.secrets` or environment variables.
- The plugin will **import the wallet** and use it for processing mass payouts.

---

#### 6. Coinbase MassPayments Plugin (`@eliza/plugin-coinbase`)

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.
Expand Down Expand Up @@ -311,7 +349,6 @@ The plugin automatically handles wallet creation or uses an existing wallet if t
- Provide `COINBASE_GENERATED_WALLET_HEX_SEED` and `COINBASE_GENERATED_WALLET_ID` via `runtime.character.settings.secrets` or environment variables.
- The plugin will **import the wallet** and use it for processing mass payouts.


**Required Configurations:**

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

---

**Wallet Creation Process:**
### Wallet Creation Process

1. **Automatic Wallet Creation**
When no wallet details are available:
Expand Down Expand Up @@ -449,37 +487,117 @@ const provider = new DeriveKeyProvider();
// Derive a raw key
try {
const rawKey = await provider.rawDeriveKey(
"/path/to/derive",
"subject-identifier"
);
// rawKey is a DeriveKeyResponse that can be used for further processing
// to get the uint8Array do the following
const rawKeyArray = rawKey.asUint8Array()
const rawKey = await provider.rawDeriveKey(
"/path/to/derive",
"subject-identifier",
);
// rawKey is a DeriveKeyResponse that can be used for further processing
// to get the uint8Array do the following
const rawKeyArray = rawKey.asUint8Array();
} catch (error) {
console.error("Raw key derivation failed:", error);
}
// Derive a Solana keypair (Ed25519)
try {
const solanaKeypair = await provider.deriveEd25519Keypair(
"/path/to/derive",
"subject-identifier",
);
// solanaKeypair can now be used for Solana operations
} catch (error) {
console.error("Solana key derivation failed:", error);
}
// Derive an Ethereum keypair (ECDSA)
try {
const evmKeypair = await provider.deriveEcdsaKeypair(
"/path/to/derive",
"subject-identifier",
);
// evmKeypair can now be used for Ethereum operations
} catch (error) {
console.error("EVM key derivation failed:", error);
}
```

**RemoteAttestationProvider Usage**

```typescript
import { RemoteAttestationProvider } from "@ai16z/plugin-tee";
// Initialize the provider
const provider = new RemoteAttestationProvider();
// Generate Remote Attestation
try {
const attestation = await provider.generateAttestation("your-report-data");
console.log("Attestation:", attestation);
} catch (error) {
console.error("Failed to generate attestation:", error);
}
```

**Configuration**

When using the provider through the runtime environment, ensure the following settings are configured:

```env
# Optional, for simulator purposes if testing on mac or windows. Leave empty for Linux x86 machines.
DSTACK_SIMULATOR_ENDPOINT="http://host.docker.internal:8090"
WALLET_SECRET_SALT=your-secret-salt // Required to single agent deployments
```

---

#### 7. TEE Plugin (`@ai16z/plugin-tee`)

Integrates [Dstack SDK](https://github.com/Dstack-TEE/dstack) to enable TEE (Trusted Execution Environment) functionality and deploy secure & privacy-enhanced Eliza Agents:

**Providers:**

- `deriveKeyProvider` - Allows for secure key derivation within a TEE environment. It supports deriving keys for both Solana (Ed25519) and Ethereum (ECDSA) chains.
- `remoteAttestationProvider` - Generate a Remote Attestation Quote based on `report_data`.

**DeriveKeyProvider Usage**

```typescript
import { DeriveKeyProvider } from "@ai16z/plugin-tee";
// Initialize the provider
const provider = new DeriveKeyProvider();
// Derive a raw key
try {
const rawKey = await provider.rawDeriveKey(
"/path/to/derive",
"subject-identifier",
);
// rawKey is a DeriveKeyResponse that can be used for further processing
// to get the uint8Array do the following
const rawKeyArray = rawKey.asUint8Array();
} catch (error) {
console.error("Raw key derivation failed:", error);
console.error("Raw key derivation failed:", error);
}
// Derive a Solana keypair (Ed25519)
try {
const solanaKeypair = await provider.deriveEd25519Keypair(
"/path/to/derive",
"subject-identifier"
);
// solanaKeypair can now be used for Solana operations
const solanaKeypair = await provider.deriveEd25519Keypair(
"/path/to/derive",
"subject-identifier",
);
// solanaKeypair can now be used for Solana operations
} catch (error) {
console.error("Solana key derivation failed:", error);
console.error("Solana key derivation failed:", error);
}
// Derive an Ethereum keypair (ECDSA)
try {
const evmKeypair = await provider.deriveEcdsaKeypair(
"/path/to/derive",
"subject-identifier"
);
// evmKeypair can now be used for Ethereum operations
const evmKeypair = await provider.deriveEcdsaKeypair(
"/path/to/derive",
"subject-identifier",
);
// evmKeypair can now be used for Ethereum operations
} catch (error) {
console.error("EVM key derivation failed:", error);
console.error("EVM key derivation failed:", error);
}
```

Expand All @@ -491,10 +609,10 @@ import { RemoteAttestationProvider } from "@ai16z/plugin-tee";
const provider = new RemoteAttestationProvider();
// Generate Remote Attestation
try {
const attestation = await provider.generateAttestation("your-report-data");
console.log("Attestation:", attestation);
const attestation = await provider.generateAttestation("your-report-data");
console.log("Attestation:", attestation);
} catch (error) {
console.error("Failed to generate attestation:", error);
console.error("Failed to generate attestation:", error);
}
```

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

___
---

### Writing Custom Plugins

Expand Down
14 changes: 9 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
"devDependencies": {
"@commitlint/cli": "^18.4.4",
"@commitlint/config-conventional": "^18.4.4",
"lerna": "8.1.5",
"only-allow": "1.2.1",
"concurrently": "9.1.0",
"husky": "9.1.7",
"lerna": "8.1.5",
"only-allow": "1.2.1",
"prettier": "3.3.3",
"typedoc": "0.26.11",
"typescript": "5.6.3",
Expand All @@ -44,14 +44,18 @@
"node": "23.3.0"
},
"dependencies": {
"@coinbase/coinbase-sdk": "^0.10.0",
"csv-parse": "^5.6.0",
"@0glabs/0g-ts-sdk": "^0.2.1",
"amqplib": "0.10.5",
"@ai16z/eliza": "0.1.4-alpha.3",
"@coinbase/coinbase-sdk": "^0.10.0",
"csv-parse": "^5.6.0",
"ollama-ai-provider": "^0.16.1",
"optional": "^0.1.4",
"sharp": "^0.33.5",
"tslog": "^4.9.3"
},
"packageManager": "[email protected]+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee"
"packageManager": "[email protected]+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
"workspaces": [
"packages/*"
]
}
Loading

0 comments on commit 13b212d

Please sign in to comment.