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: implement coinbase trading #608

Merged
merged 26 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6c87685
feat: implement coinbase trading
monilpat Nov 26, 2024
7ee219e
Make massPayments gasless if usdc
monilpat Nov 26, 2024
c9e7ead
write to csv + clean up
monilpat Nov 26, 2024
27cf67a
clean up 2
monilpat Nov 28, 2024
4c991d3
Tested and working ETH <-> USDC
monilpat Nov 28, 2024
d91094f
Update readme
monilpat Nov 28, 2024
3feda9c
Add disclaimer
monilpat Nov 28, 2024
a6fee50
Merge branch 'realitySpiral/coinbaseTrading' of https://github.com/mo…
monilpat Nov 28, 2024
18d1013
merge conflicts
monilpat Nov 28, 2024
389ea25
add missing eslint fix
monilpat Nov 28, 2024
ee64a1d
Address linter
monilpat Nov 28, 2024
11f0b9f
Update .env.example
monilpat Nov 28, 2024
0b2332e
feat: implement coinbase trading
monilpat Nov 26, 2024
d657e85
Make massPayments gasless if usdc
monilpat Nov 26, 2024
1c4b13b
write to csv + clean up
monilpat Nov 26, 2024
069344d
clean up 2
monilpat Nov 28, 2024
d9df31e
Tested and working ETH <-> USDC
monilpat Nov 28, 2024
133614e
Update readme
monilpat Nov 28, 2024
0b66cfa
Add disclaimer
monilpat Nov 28, 2024
f94c2d5
merge conflicts
monilpat Nov 28, 2024
a2aad01
add missing eslint fix
monilpat Nov 28, 2024
4104d0b
Address linter
monilpat Nov 28, 2024
fe58d49
Update .env.example
monilpat Nov 28, 2024
1f864a1
Merge branch 'realitySpiral/coinbaseTrading' of https://github.com/mo…
monilpat Nov 28, 2024
90bf758
Reset commit history
monilpat Nov 28, 2024
cd98ff9
Merge branch 'realitySpiral/coinbaseTrading' of https://github.com/mo…
monilpat Nov 28, 2024
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
8 changes: 6 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,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": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee"
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
"workspaces": [
"packages/*"
]
}
Loading