Skip to content

Commit 2530336

Browse files
authored
Merge pull request game-by-virtuals#55 from BitMind-AI/cdp-plugin
CDP Plugin For Virtuals
2 parents 4f8fef6 + b65886f commit 2530336

6 files changed

Lines changed: 830 additions & 0 deletions

File tree

plugins/cdp/README.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Coinbase Developer Platform (CDP) Plugin for GAME SDK
2+
3+
A plugin for interacting with Coinbase's CDP through the GAME SDK. This plugin provides a simple interface for wallet management, transfers, trading, and webhooks on Base network.
4+
5+
## Features
6+
7+
- Wallet Management (create, import, export)
8+
- Gasless USDC Transfers
9+
- ETH/USDC Trading
10+
- Webhook Integration
11+
- Transfer/Trade History
12+
- Testnet Faucet Support
13+
- Base Network Support (Sepolia testnet & mainnet)
14+
15+
## Installation
16+
17+
```bash
18+
# Install from local directory
19+
pip install -e plugins/coinbase
20+
21+
# Dependencies will be installed automatically:
22+
# - game-sdk>=0.1.1
23+
# - cdp-sdk>=0.16.0
24+
# - python-dotenv>=1.0.0
25+
```
26+
27+
## Configuration
28+
29+
Set up your environment variables in a `.env` file:
30+
31+
```env
32+
# Required
33+
GAME_API_KEY=your_game_api_key
34+
CDP_API_KEY_NAME=your_cdp_api_key_name
35+
CDP_API_KEY_PRIVATE_KEY=your_cdp_api_key_private_key
36+
```
37+
38+
## Basic Usage
39+
40+
```python
41+
from cdp_game_sdk.cdp_plugin import CDPPlugin
42+
43+
# Initialize plugin
44+
plugin = CDPPlugin()
45+
plugin.initialize()
46+
47+
# Create and fund a wallet
48+
wallet = plugin.create_wallet()
49+
print(f"New wallet created: {wallet['address']}")
50+
51+
# Request testnet funds
52+
plugin.request_testnet_funds("eth")
53+
plugin.request_testnet_funds("usdc")
54+
55+
# Check balances
56+
balances = plugin.get_wallet_balance()
57+
print(f"ETH: {balances['eth']}")
58+
print(f"USDC: {balances['usdc']}")
59+
60+
# Transfer USDC (gasless)
61+
plugin.transfer(
62+
amount=0.1,
63+
currency="usdc",
64+
to_address="0x123...",
65+
gasless=True
66+
)
67+
68+
# Trade ETH for USDC
69+
plugin.trade(
70+
amount=0.1,
71+
from_currency="eth",
72+
to_currency="usdc"
73+
)
74+
```
75+
76+
## Examples
77+
78+
The plugin comes with two example implementations:
79+
80+
### CDP Worker
81+
82+
```python
83+
from cdp_game_sdk.cdp_plugin import CDPPlugin
84+
from examples.cdp_worker import CDPWorker
85+
86+
worker = CDPWorker()
87+
88+
# Create and fund a wallet
89+
worker.run("create_and_fund_wallet")
90+
91+
# Transfer USDC
92+
worker.run("transfer_usdc",
93+
to_address="0x123...",
94+
amount=10.0
95+
)
96+
97+
# Trade ETH for USDC
98+
worker.run("trade_eth_for_usdc",
99+
amount=0.1
100+
)
101+
```
102+
103+
### CDP Agent
104+
105+
```python
106+
from examples.cdp_agent import main as run_agent
107+
108+
# Starts a monitoring agent that:
109+
# - Maintains minimum ETH/USDC balances
110+
# - Monitors transfers
111+
# - Creates webhooks for notifications
112+
run_agent()
113+
```
114+
115+
## API Reference
116+
117+
### CDPPlugin
118+
119+
Main plugin class for interacting with CDP.
120+
121+
#### Initialization
122+
```python
123+
plugin = CDPPlugin()
124+
plugin.initialize(use_server_signer=False)
125+
```
126+
127+
#### Methods
128+
129+
**Wallet Management**
130+
- `create_wallet()`: Create new wallet
131+
- `import_wallet(wallet_id: str, seed_file: str)`: Import existing wallet
132+
- `export_wallet(file_path: str, encrypt: bool)`: Export wallet data
133+
- `get_wallet_balance()`: Get ETH and USDC balances
134+
135+
**Transactions**
136+
- `transfer(amount: float, currency: str, to_address: str, gasless: bool)`: Transfer funds
137+
- `trade(amount: float, from_currency: str, to_currency: str)`: Trade between currencies
138+
- `request_testnet_funds(currency: str)`: Request testnet funds from faucet
139+
140+
**Monitoring**
141+
- `get_transfer_history()`: Get list of transfers
142+
- `get_trade_history()`: Get list of trades
143+
- `create_webhook(notification_url: str)`: Create notification webhook
144+
145+
## Development
146+
147+
Run tests:
148+
```bash
149+
pytest plugins/coinbase/test_cdp.py -v
150+
```
151+
152+
## Contributing
153+
154+
1. Fork the repository
155+
2. Create your feature branch
156+
3. Run tests and add new ones
157+
4. Submit a pull request
158+
159+
## Support
160+
161+
- Documentation: [CDP Documentation](https://docs.cloud.coinbase.com/cdp/docs)
162+
- Issues: [GitHub Issues](https://github.com/game-by-virtuals/game-python/issues)
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
from typing import Dict, Any, Optional, List
2+
import os
3+
from cdp import *
4+
from cdp.client.models.webhook import WebhookEventType, WebhookEventFilter
5+
6+
7+
class CDPPlugin:
8+
"""
9+
Coinbase Developer Platform Plugin for interacting with CDP
10+
"""
11+
12+
def __init__(self) -> None:
13+
"""Initialize the CDP plugin"""
14+
self.id: str = "cdp_plugin"
15+
self.name: str = "CDP Plugin"
16+
self.api_key_name = os.environ.get("CDP_API_KEY_NAME")
17+
self.api_key_private_key = os.environ.get("CDP_API_KEY_PRIVATE_KEY")
18+
self.network = "base-sepolia" # Default to testnet
19+
self.wallet = None
20+
21+
def initialize(self, use_server_signer: bool = False):
22+
"""Initialize the plugin"""
23+
if not self.api_key_name:
24+
raise ValueError("CDP_API_KEY_NAME environment variable is required")
25+
if not self.api_key_private_key:
26+
raise ValueError("CDP_API_KEY_PRIVATE_KEY environment variable is required")
27+
28+
# Configure CDP
29+
Cdp.configure(self.api_key_name, self.api_key_private_key)
30+
if use_server_signer:
31+
Cdp.use_server_signer = True
32+
33+
def create_wallet(self) -> Dict[str, Any]:
34+
"""Create a new wallet"""
35+
self.wallet = Wallet.create(self.network)
36+
return {
37+
"wallet_id": self.wallet.id,
38+
"address": self.wallet.default_address.address_id
39+
}
40+
41+
def import_wallet(self, wallet_id: str, seed_file: str = None) -> None:
42+
"""Import an existing wallet"""
43+
self.wallet = Wallet.fetch(wallet_id)
44+
if seed_file:
45+
self.wallet.load_seed(seed_file)
46+
47+
def get_wallet_balance(self) -> Dict[str, float]:
48+
"""Get wallet balances"""
49+
if not self.wallet:
50+
raise ValueError("No wallet initialized")
51+
return {
52+
"eth": float(self.wallet.default_address.balance("eth")),
53+
"usdc": float(self.wallet.default_address.balance("usdc"))
54+
}
55+
56+
def request_testnet_funds(self, currency: str = "eth") -> Dict[str, Any]:
57+
"""Request testnet funds from faucet"""
58+
if not self.wallet:
59+
raise ValueError("No wallet initialized")
60+
tx = self.wallet.faucet(currency)
61+
tx.wait()
62+
return {
63+
"transaction_id": tx.id,
64+
"status": tx.status
65+
}
66+
67+
def transfer(
68+
self,
69+
amount: float,
70+
currency: str,
71+
to_address: str,
72+
gasless: bool = False,
73+
skip_batching: bool = False
74+
) -> Dict[str, Any]:
75+
"""
76+
Transfer funds to another address
77+
"""
78+
if not self.wallet:
79+
raise ValueError("No wallet initialized")
80+
81+
tx = self.wallet.transfer(
82+
amount,
83+
currency.lower(),
84+
to_address,
85+
gasless=gasless,
86+
skip_batching=skip_batching
87+
).wait()
88+
89+
return {
90+
"transaction_id": tx.id,
91+
"status": tx.status
92+
}
93+
94+
def trade(
95+
self,
96+
amount: float,
97+
from_currency: str,
98+
to_currency: str
99+
) -> Dict[str, Any]:
100+
"""
101+
Trade between currencies
102+
"""
103+
if not self.wallet:
104+
raise ValueError("No wallet initialized")
105+
106+
trade = self.wallet.trade(
107+
amount,
108+
from_currency.lower(),
109+
to_currency.lower()
110+
).wait()
111+
112+
return {
113+
"trade_id": trade.id,
114+
"status": trade.status
115+
}
116+
117+
def get_transfer_history(self) -> List[Dict[str, Any]]:
118+
"""Get transfer history"""
119+
if not self.wallet:
120+
raise ValueError("No wallet initialized")
121+
return list(self.wallet.default_address.transfers())
122+
123+
def get_trade_history(self) -> List[Dict[str, Any]]:
124+
"""Get trade history"""
125+
if not self.wallet:
126+
raise ValueError("No wallet initialized")
127+
return list(self.wallet.default_address.trades())
128+
129+
def create_webhook(
130+
self,
131+
notification_url: str,
132+
event_type: str = WebhookEventType.ERC20_TRANSFER,
133+
network: str = None
134+
) -> Dict[str, Any]:
135+
"""Create a webhook for notifications"""
136+
if not self.wallet:
137+
raise ValueError("No wallet initialized")
138+
139+
webhook = self.wallet.create_webhook(
140+
notification_url,
141+
event_type=event_type,
142+
network_id=network or self.network
143+
)
144+
145+
return {
146+
"webhook_id": webhook.id,
147+
"status": webhook.status
148+
}
149+
150+
def export_wallet(self, file_path: str, encrypt: bool = True) -> None:
151+
"""Export wallet data to file"""
152+
if not self.wallet:
153+
raise ValueError("No wallet initialized")
154+
self.wallet.save_seed(file_path, encrypt=encrypt)

0 commit comments

Comments
 (0)