cdp-docs-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +213 -0
- package/bin/cdp-docs.js +48 -0
- package/bin/cdp-setup.js +91 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +212 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/src/templates/docs/exporting.md +0 -0
- package/src/templates/docs/fund.md +122 -0
- package/src/templates/docs/importing.md +273 -0
- package/src/templates/docs/managing-accounts.md +366 -0
- package/src/templates/docs/policies.md +730 -0
- package/src/templates/docs/transfer.md +366 -0
- package/src/templates/docs/wallet-accounts.md +203 -0
- package/src/templates/docs/wallet-start.md +741 -0
- package/src/templates/prompt/INTEGRATION-SUMMARY.md +151 -0
- package/src/templates/prompt/SETUP-CDP-WALLET.md +142 -0
- package/src/templates/prompt/cdp-wallet.md +1155 -0
- package/src/templates/prompt/context.md +105 -0
- package/src/templates/prompt/directory.md +97 -0
@@ -0,0 +1,741 @@
|
|
1
|
+
# Wallet API v2: Quickstart
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
The v2 Wallet API allows you to create [accounts](/wallet-api/v2/introduction/accounts) on EVM compatible networks and the Solana network.
|
6
|
+
|
7
|
+
In this quickstart, you will learn how to:
|
8
|
+
|
9
|
+
* Create EVM and Solana accounts
|
10
|
+
* Fund your accounts with testnet tokens using CDP Faucets
|
11
|
+
* Send a transaction using `viem` for Typescript or `web3` for Python
|
12
|
+
|
13
|
+
## Prerequisites
|
14
|
+
|
15
|
+
Setup all dependencies, export your keys to environment variables, and initialize a new project before you begin.
|
16
|
+
|
17
|
+
It is assumed you have:
|
18
|
+
|
19
|
+
* [Node.js](https://nodejs.org/en) 22.x+ if using Typescript
|
20
|
+
* [Python](https://www.python.org/downloads/) 3.10+ if using Python
|
21
|
+
* [Created](https://portal.cdp.coinbase.com/create-account) and [signed in](https://portal.cdp.coinbase.com/signin) to an existing CDP account
|
22
|
+
|
23
|
+
Once you have setup the prerequisite dependencies, continue reading to create keys to authenticate your requests and initialize a new project.
|
24
|
+
|
25
|
+
### Create keys
|
26
|
+
|
27
|
+
Sign in to the [CDP Portal](https://portal.cdp.coinbase.com), [create a CDP API key](https://portal.cdp.coinbase.com/projects/api-keys) and [generate a Wallet Secret](https://portal.cdp.coinbase.com/products/wallet-api).
|
28
|
+
Keep these values handy as you will need them in the following steps.
|
29
|
+
|
30
|
+
For more information, see the [CDP API Keys](/get-started/authentication/cdp-api-keys#secret-api-keys) and [Wallet Secret](/wallet-api/v2/introduction/security#wallet-secret) documentation.
|
31
|
+
|
32
|
+
### Project setup
|
33
|
+
|
34
|
+
After creating your keys, initialize a new project and instantiate the CDP client.
|
35
|
+
|
36
|
+
<Tabs groupId="programming-language">
|
37
|
+
<Tab value="Typescript" title="Typescript" default>
|
38
|
+
Initialize a new Typescript project by running:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
mkdir cdp-sdk-example && cd cdp-sdk-example && npm init -y && npm pkg set type="module" && touch main.ts && touch .env
|
42
|
+
```
|
43
|
+
|
44
|
+
Add your CDP API key and wallet secret to the `.env` file:
|
45
|
+
|
46
|
+
```bash .env
|
47
|
+
CDP_API_KEY_ID=your-api-key-id
|
48
|
+
CDP_API_KEY_SECRET=your-api-key-secret
|
49
|
+
CDP_WALLET_SECRET=your-wallet-secret
|
50
|
+
```
|
51
|
+
|
52
|
+
Now, install the [CDP SDK](https://github.com/coinbase/cdp-sdk) and the [dotenv](https://www.npmjs.com/package/dotenv) packages:
|
53
|
+
|
54
|
+
```bash
|
55
|
+
npm install @coinbase/cdp-sdk dotenv
|
56
|
+
```
|
57
|
+
|
58
|
+
Finally, in `main.ts`, instantiate the CDP client:
|
59
|
+
|
60
|
+
```typescript main.ts lines wrap [expandable]
|
61
|
+
import { CdpClient } from "@coinbase/cdp-sdk";
|
62
|
+
import dotenv from "dotenv";
|
63
|
+
|
64
|
+
dotenv.config();
|
65
|
+
|
66
|
+
// Initialize the CDP client, which automatically loads
|
67
|
+
// the API Key and Wallet Secret from the environment
|
68
|
+
// variables.
|
69
|
+
const cdp = new CdpClient();
|
70
|
+
```
|
71
|
+
|
72
|
+
In this and in the following examples, you can run your code by running:
|
73
|
+
|
74
|
+
```bash
|
75
|
+
npx tsx main.ts
|
76
|
+
```
|
77
|
+
</Tab>
|
78
|
+
|
79
|
+
<Tab value="Python" title="Python">
|
80
|
+
Initialize a new Python project by running:
|
81
|
+
|
82
|
+
```bash
|
83
|
+
mkdir cdp-sdk-example && cd cdp-sdk-example && python -m venv .venv && source .venv/bin/activate && touch main.py && touch .env
|
84
|
+
```
|
85
|
+
|
86
|
+
Add your CDP API key and wallet secret to the `.env` file:
|
87
|
+
|
88
|
+
```bash .env
|
89
|
+
CDP_API_KEY_ID=your-api-key-id
|
90
|
+
CDP_API_KEY_SECRET=your-api-key-secret
|
91
|
+
CDP_WALLET_SECRET=your-wallet-secret
|
92
|
+
```
|
93
|
+
|
94
|
+
Now, install the [CDP SDK](https://github.com/coinbase/cdp-sdk) and the [python-dotenv](https://pypi.org/project/python-dotenv/) package:
|
95
|
+
|
96
|
+
```bash
|
97
|
+
pip install cdp-sdk python-dotenv
|
98
|
+
```
|
99
|
+
|
100
|
+
Finally, in `main.py`, instantiate the CDP client:
|
101
|
+
|
102
|
+
```python title="main.py"
|
103
|
+
from cdp import CdpClient
|
104
|
+
import asyncio
|
105
|
+
from dotenv import load_dotenv
|
106
|
+
|
107
|
+
load_dotenv()
|
108
|
+
|
109
|
+
async def main():
|
110
|
+
# Initialize the CDP client, which automatically loads
|
111
|
+
# the API Key and Wallet Secret from the environment
|
112
|
+
# variables.
|
113
|
+
cdp = CdpClient()
|
114
|
+
await cdp.close()
|
115
|
+
|
116
|
+
|
117
|
+
asyncio.run(main())
|
118
|
+
```
|
119
|
+
|
120
|
+
In this and in the following examples, you can run your code by running:
|
121
|
+
|
122
|
+
```bash
|
123
|
+
python main.py
|
124
|
+
```
|
125
|
+
</Tab>
|
126
|
+
</Tabs>
|
127
|
+
|
128
|
+
## 1. Create an account
|
129
|
+
|
130
|
+
The v2 Wallet API offers support for both [EVM compatible accounts and Solana accounts](/wallet-api/v2/introduction/accounts).
|
131
|
+
|
132
|
+
### EVM
|
133
|
+
|
134
|
+
To create an EVM account, see below:
|
135
|
+
|
136
|
+
<CodeGroup>
|
137
|
+
```typescript main.ts lines wrap
|
138
|
+
import { CdpClient } from "@coinbase/cdp-sdk";
|
139
|
+
import dotenv from "dotenv";
|
140
|
+
|
141
|
+
dotenv.config();
|
142
|
+
|
143
|
+
const cdp = new CdpClient();
|
144
|
+
const account = await cdp.evm.createAccount();
|
145
|
+
console.log(`Created EVM account: ${account.address}`);
|
146
|
+
```
|
147
|
+
|
148
|
+
```python main.py lines wrap
|
149
|
+
import asyncio
|
150
|
+
from cdp import CdpClient
|
151
|
+
from dotenv import load_dotenv
|
152
|
+
|
153
|
+
load_dotenv()
|
154
|
+
|
155
|
+
async def main():
|
156
|
+
cdp = CdpClient()
|
157
|
+
account = await cdp.evm.create_account()
|
158
|
+
print(f"Created EVM account: {account.address}")
|
159
|
+
await cdp.close()
|
160
|
+
|
161
|
+
|
162
|
+
asyncio.run(main())
|
163
|
+
```
|
164
|
+
</CodeGroup>
|
165
|
+
|
166
|
+
After running the above snippet, you should see similar output:
|
167
|
+
|
168
|
+
```console lines wrap
|
169
|
+
Created EVM account: 0x3c0D84055994c3062819Ce8730869D0aDeA4c3Bf
|
170
|
+
```
|
171
|
+
|
172
|
+
<Tip>
|
173
|
+
You can also create accounts with human-readable names and retrieve them later using the `getOrCreateAccount` method.
|
174
|
+
|
175
|
+
See the [Managing Accounts](/wallet-api/v2/using-the-wallet-api/managing-accounts#account-names) guide for more information.
|
176
|
+
</Tip>
|
177
|
+
|
178
|
+
### Solana
|
179
|
+
|
180
|
+
To create a Solana account, see below:
|
181
|
+
|
182
|
+
<CodeGroup>
|
183
|
+
```typescript main.ts lines wrap
|
184
|
+
import { CdpClient } from "@coinbase/cdp-sdk";
|
185
|
+
import dotenv from "dotenv";
|
186
|
+
|
187
|
+
dotenv.config();
|
188
|
+
|
189
|
+
const cdp = new CdpClient();
|
190
|
+
const account = await cdp.solana.createAccount();
|
191
|
+
console.log(`Created Solana account: ${account.address}`);
|
192
|
+
```
|
193
|
+
|
194
|
+
```python main.py lines wrap
|
195
|
+
import asyncio
|
196
|
+
from cdp import CdpClient
|
197
|
+
from dotenv import load_dotenv
|
198
|
+
|
199
|
+
load_dotenv()
|
200
|
+
|
201
|
+
async def main():
|
202
|
+
cdp = CdpClient()
|
203
|
+
account = await cdp.solana.create_account()
|
204
|
+
print(f"Created Solana account: {account.address}")
|
205
|
+
await cdp.close()
|
206
|
+
|
207
|
+
|
208
|
+
asyncio.run(main())
|
209
|
+
```
|
210
|
+
</CodeGroup>
|
211
|
+
|
212
|
+
After running the above snippet, you should see similar output:
|
213
|
+
|
214
|
+
```console lines wrap
|
215
|
+
Created Solana account: 2XBS6naS1v7pXEg25z43FGHnmEgEad53fmiZ9S6LPgKn
|
216
|
+
```
|
217
|
+
|
218
|
+
## 2. Fund account with test funds
|
219
|
+
|
220
|
+
Accounts do not have funds on creation. We provide a [Faucet API](/faucets/introduction/welcome) to easily fund your EVM account with testnet tokens and Solana account with devnet tokens.
|
221
|
+
|
222
|
+
<Info>
|
223
|
+
Before you request funds, ensure you read about [rate limits when using CDP Faucets](/faucets/introduction/welcome#supported-assets).
|
224
|
+
</Info>
|
225
|
+
|
226
|
+
### EVM
|
227
|
+
|
228
|
+
<CodeGroup>
|
229
|
+
```typescript main.ts lines wrap
|
230
|
+
import { CdpClient } from "@coinbase/cdp-sdk";
|
231
|
+
import dotenv from "dotenv";
|
232
|
+
|
233
|
+
dotenv.config();
|
234
|
+
|
235
|
+
const cdp = new CdpClient();
|
236
|
+
|
237
|
+
const account = await cdp.evm.createAccount();
|
238
|
+
const faucetResponse = await cdp.evm.requestFaucet({
|
239
|
+
address: account.address,
|
240
|
+
network: "base-sepolia",
|
241
|
+
token: "eth"
|
242
|
+
});
|
243
|
+
console.log(`Requested funds from ETH faucet: https://sepolia.basescan.org/tx/${faucetResponse.transactionHash}`);
|
244
|
+
```
|
245
|
+
|
246
|
+
```python main.py lines wrap
|
247
|
+
import asyncio
|
248
|
+
from cdp import CdpClient
|
249
|
+
from dotenv import load_dotenv
|
250
|
+
|
251
|
+
load_dotenv()
|
252
|
+
|
253
|
+
async def main():
|
254
|
+
cdp = CdpClient()
|
255
|
+
|
256
|
+
account = await cdp.evm.create_account()
|
257
|
+
|
258
|
+
faucet_hash = await cdp.evm.request_faucet(
|
259
|
+
address=account.address,
|
260
|
+
network="base-sepolia",
|
261
|
+
token="eth"
|
262
|
+
)
|
263
|
+
print(f"Requested funds from ETH faucet: https://sepolia.basescan.org/tx/{faucet_hash}")
|
264
|
+
|
265
|
+
await cdp.close()
|
266
|
+
|
267
|
+
|
268
|
+
asyncio.run(main())
|
269
|
+
```
|
270
|
+
</CodeGroup>
|
271
|
+
|
272
|
+
After running the above, you should see similar output:
|
273
|
+
|
274
|
+
```console lines wrap
|
275
|
+
Requested funds from ETH faucet: https://sepolia.basescan.org/tx/0x9e93a16f2ca67f35bcb1ea2933f19035ae1e71ff3100d2abc6a22ce024d085ec
|
276
|
+
```
|
277
|
+
|
278
|
+
### Solana
|
279
|
+
|
280
|
+
<CodeGroup>
|
281
|
+
```typescript main.ts lines wrap
|
282
|
+
import { CdpClient } from "@coinbase/cdp-sdk";
|
283
|
+
import dotenv from "dotenv";
|
284
|
+
|
285
|
+
dotenv.config();
|
286
|
+
|
287
|
+
const cdp = new CdpClient();
|
288
|
+
|
289
|
+
const account = await cdp.solana.createAccount();
|
290
|
+
|
291
|
+
const { signature } = await cdp.solana.requestFaucet({
|
292
|
+
address: account.address,
|
293
|
+
token: "sol"
|
294
|
+
});
|
295
|
+
console.log(`Requested funds from Solana faucet: https://explorer.solana.com/tx/${signature}?cluster=devnet`);
|
296
|
+
```
|
297
|
+
|
298
|
+
```python main.py lines wrap
|
299
|
+
import asyncio
|
300
|
+
from cdp import CdpClient
|
301
|
+
from dotenv import load_dotenv
|
302
|
+
|
303
|
+
load_dotenv()
|
304
|
+
|
305
|
+
async def main():
|
306
|
+
cdp = CdpClient()
|
307
|
+
|
308
|
+
account = await cdp.solana.create_account()
|
309
|
+
|
310
|
+
tx_signature_response = await cdp.solana.request_faucet(
|
311
|
+
address=account.address,
|
312
|
+
token="sol"
|
313
|
+
)
|
314
|
+
|
315
|
+
print(f"Requested funds from Solana faucet: https://explorer.solana.com/tx/{tx_signature_response.transaction_signature}?cluster=devnet")
|
316
|
+
|
317
|
+
await cdp.close()
|
318
|
+
|
319
|
+
|
320
|
+
asyncio.run(main())
|
321
|
+
```
|
322
|
+
</CodeGroup>
|
323
|
+
|
324
|
+
After running the above, you should see similar output:
|
325
|
+
|
326
|
+
```console lines wrap
|
327
|
+
Requested funds from Solana faucet: https://explorer.solana.com/tx/4KEPbhkRLTg2FJNqV5bbUd6zv1TNkksxF9PDHw2FodrTha3jq2Cojn4hSKtjPWdrZiRDuYp7okRuc1oYvh3JkLuE?cluster=devnet
|
328
|
+
```
|
329
|
+
|
330
|
+
## 3. Send a transaction
|
331
|
+
|
332
|
+
### EVM
|
333
|
+
|
334
|
+
<Tabs groupId="programming-language">
|
335
|
+
<Tab value="Typescript" title="Typescript" default>
|
336
|
+
You can send transactions using the v2 Wallet API.
|
337
|
+
|
338
|
+
Note that in order to wait for transaction confirmation, you will need to have `viem` installed:
|
339
|
+
|
340
|
+
```bash
|
341
|
+
npm install viem
|
342
|
+
```
|
343
|
+
|
344
|
+
In the example below, we:
|
345
|
+
|
346
|
+
1. Create a new EVM account.
|
347
|
+
2. Request ETH from the faucet.
|
348
|
+
3. Use the v2 Wallet API to send a transaction.
|
349
|
+
4. Wait for transaction confirmation.
|
350
|
+
|
351
|
+
```typescript main.ts lines wrap [expandable]
|
352
|
+
import { CdpClient } from "@coinbase/cdp-sdk";
|
353
|
+
import { http, createPublicClient, parseEther } from "viem";
|
354
|
+
import { baseSepolia } from "viem/chains";
|
355
|
+
import dotenv from "dotenv";
|
356
|
+
|
357
|
+
dotenv.config();
|
358
|
+
|
359
|
+
const cdp = new CdpClient();
|
360
|
+
|
361
|
+
const publicClient = createPublicClient({
|
362
|
+
chain: baseSepolia,
|
363
|
+
transport: http(),
|
364
|
+
});
|
365
|
+
|
366
|
+
// Step 1: Create a new EVM account.
|
367
|
+
const account = await cdp.evm.createAccount();
|
368
|
+
console.log("Successfully created EVM account:", account.address);
|
369
|
+
|
370
|
+
// Step 2: Request ETH from the faucet.
|
371
|
+
const { transactionHash: faucetTransactionHash } = await cdp.evm.requestFaucet({
|
372
|
+
address: account.address,
|
373
|
+
network: "base-sepolia",
|
374
|
+
token: "eth",
|
375
|
+
});
|
376
|
+
|
377
|
+
const faucetTxReceipt = await publicClient.waitForTransactionReceipt({
|
378
|
+
hash: faucetTransactionHash,
|
379
|
+
});
|
380
|
+
console.log("Successfully requested ETH from faucet:", faucetTxReceipt.transactionHash);
|
381
|
+
|
382
|
+
// Step 3: Use the v2 Wallet API to send a transaction.
|
383
|
+
const transactionResult = await cdp.evm.sendTransaction({
|
384
|
+
address: account.address,
|
385
|
+
transaction: {
|
386
|
+
to: "0x0000000000000000000000000000000000000000",
|
387
|
+
value: parseEther("0.000001"),
|
388
|
+
},
|
389
|
+
network: "base-sepolia",
|
390
|
+
});
|
391
|
+
|
392
|
+
// Step 4: Wait for the transaction to be confirmed
|
393
|
+
const txReceipt = await publicClient.waitForTransactionReceipt({
|
394
|
+
hash: transactionResult.transactionHash,
|
395
|
+
});
|
396
|
+
|
397
|
+
console.log(
|
398
|
+
`Transaction sent! Link: https://sepolia.basescan.org/tx/${transactionResult.transactionHash}`
|
399
|
+
);
|
400
|
+
```
|
401
|
+
</Tab>
|
402
|
+
|
403
|
+
<Tab value="Python" title="Python">
|
404
|
+
You can send transactions using the v2 Wallet API.
|
405
|
+
|
406
|
+
Note that in order to wait for transaction confirmation, you will need to have `web3` installed:
|
407
|
+
|
408
|
+
```bash
|
409
|
+
pip install web3
|
410
|
+
```
|
411
|
+
|
412
|
+
In the example below, we:
|
413
|
+
|
414
|
+
1. Create a new EVM account.
|
415
|
+
2. Request ETH from the faucet.
|
416
|
+
3. Use the v2 Wallet API to send a transaction.
|
417
|
+
4. Wait for transaction confirmation.
|
418
|
+
|
419
|
+
```python main.py lines wrap [expandable]
|
420
|
+
import asyncio
|
421
|
+
|
422
|
+
from cdp import CdpClient
|
423
|
+
from cdp.evm_transaction_types import TransactionRequestEIP1559
|
424
|
+
|
425
|
+
from dotenv import load_dotenv
|
426
|
+
from web3 import Web3
|
427
|
+
|
428
|
+
load_dotenv()
|
429
|
+
|
430
|
+
w3 = Web3(Web3.HTTPProvider("https://sepolia.base.org"))
|
431
|
+
|
432
|
+
|
433
|
+
async def main():
|
434
|
+
async with CdpClient() as cdp:
|
435
|
+
account = await cdp.evm.create_account()
|
436
|
+
print(f"Created account: {account.address}")
|
437
|
+
|
438
|
+
faucet_hash = await cdp.evm.request_faucet(
|
439
|
+
address=account.address, network="base-sepolia", token="eth"
|
440
|
+
)
|
441
|
+
|
442
|
+
w3.eth.wait_for_transaction_receipt(faucet_hash)
|
443
|
+
print(f"Received funds from faucet for address: {account.address}")
|
444
|
+
|
445
|
+
tx_hash = await cdp.evm.send_transaction(
|
446
|
+
address=account.address,
|
447
|
+
transaction=TransactionRequestEIP1559(
|
448
|
+
to="0x0000000000000000000000000000000000000000",
|
449
|
+
value=w3.to_wei(0.000001, "ether"),
|
450
|
+
),
|
451
|
+
network="base-sepolia",
|
452
|
+
)
|
453
|
+
|
454
|
+
|
455
|
+
print(f"Transaction sent! Link: https://sepolia.basescan.org/tx/{tx_hash}")
|
456
|
+
|
457
|
+
|
458
|
+
asyncio.run(main())
|
459
|
+
```
|
460
|
+
</Tab>
|
461
|
+
</Tabs>
|
462
|
+
|
463
|
+
### Solana
|
464
|
+
|
465
|
+
<Tabs groupId="programming-language">
|
466
|
+
<Tab value="Typescript" title="Typescript" default>
|
467
|
+
You can send transactions on Solana using the [`@solana/web3.js`](https://solana.com/docs/clients/javascript) v1 library.
|
468
|
+
|
469
|
+
```bash
|
470
|
+
npm install @solana/web3.js@1
|
471
|
+
```
|
472
|
+
|
473
|
+
In the example below, we:
|
474
|
+
|
475
|
+
1. Create a new Solana account.
|
476
|
+
2. Request SOL from the faucet.
|
477
|
+
3. Wait for funds to become available.
|
478
|
+
4. Send the transaction to a specified address.
|
479
|
+
|
480
|
+
```typescript main.ts lines wrap [expandable]
|
481
|
+
import {
|
482
|
+
Connection,
|
483
|
+
PublicKey,
|
484
|
+
SystemProgram,
|
485
|
+
Transaction,
|
486
|
+
} from "@solana/web3.js";
|
487
|
+
import { CdpClient } from "@coinbase/cdp-sdk";
|
488
|
+
import dotenv from "dotenv";
|
489
|
+
|
490
|
+
dotenv.config();
|
491
|
+
|
492
|
+
const cdp = new CdpClient();
|
493
|
+
|
494
|
+
const connection = new Connection("https://api.devnet.solana.com");
|
495
|
+
|
496
|
+
async function createAccount() {
|
497
|
+
const account = await cdp.solana.createAccount();
|
498
|
+
console.log(`Created account: ${account.address}`);
|
499
|
+
return account;
|
500
|
+
}
|
501
|
+
|
502
|
+
async function requestFaucet(address: string) {
|
503
|
+
await cdp.solana.requestFaucet({
|
504
|
+
address,
|
505
|
+
token: "sol",
|
506
|
+
});
|
507
|
+
}
|
508
|
+
|
509
|
+
async function waitForBalance(address: string) {
|
510
|
+
let balance = 0;
|
511
|
+
let attempts = 0;
|
512
|
+
const maxAttempts = 30;
|
513
|
+
|
514
|
+
while (balance === 0 && attempts < maxAttempts) {
|
515
|
+
balance = await connection.getBalance(new PublicKey(address));
|
516
|
+
if (balance === 0) {
|
517
|
+
console.log("Waiting for funds...");
|
518
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
519
|
+
attempts++;
|
520
|
+
} else {
|
521
|
+
console.log("Account funded with", balance / 1e9, "SOL");
|
522
|
+
}
|
523
|
+
}
|
524
|
+
|
525
|
+
if (balance === 0) {
|
526
|
+
throw new Error("Account not funded after multiple attempts");
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
async function sendTransaction(address: string) {
|
531
|
+
// Amount of lamports to send (default: 1000 = 0.000001 SOL)
|
532
|
+
const lamportsToSend = 1000;
|
533
|
+
const fromAddress = new PublicKey(address)
|
534
|
+
const toAddress = new PublicKey("EeVPcnRE1mhcY85wAh3uPJG1uFiTNya9dCJjNUPABXzo");
|
535
|
+
|
536
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
537
|
+
|
538
|
+
const transaction = new Transaction();
|
539
|
+
transaction.add(
|
540
|
+
SystemProgram.transfer({
|
541
|
+
fromPubkey: fromAddress,
|
542
|
+
toPubkey: toAddress,
|
543
|
+
lamports: lamportsToSend,
|
544
|
+
})
|
545
|
+
);
|
546
|
+
|
547
|
+
transaction.recentBlockhash = blockhash;
|
548
|
+
transaction.feePayer = fromAddress;
|
549
|
+
|
550
|
+
const serializedTx = Buffer.from(
|
551
|
+
transaction.serialize({ requireAllSignatures: false })
|
552
|
+
).toString("base64");
|
553
|
+
|
554
|
+
const { signature: txSignature } = await cdp.solana.signTransaction({
|
555
|
+
address,
|
556
|
+
transaction: serializedTx,
|
557
|
+
});
|
558
|
+
const decodedSignedTx = Buffer.from(txSignature, "base64");
|
559
|
+
|
560
|
+
console.log("Sending transaction...");
|
561
|
+
const txSendSignature = await connection.sendRawTransaction(decodedSignedTx);
|
562
|
+
|
563
|
+
const latestBlockhash = await connection.getLatestBlockhash();
|
564
|
+
|
565
|
+
console.log("Waiting for transaction to be confirmed...");
|
566
|
+
const confirmation = await connection.confirmTransaction({
|
567
|
+
signature: txSendSignature,
|
568
|
+
blockhash: latestBlockhash.blockhash,
|
569
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
570
|
+
});
|
571
|
+
|
572
|
+
if (confirmation.value.err) {
|
573
|
+
throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`);
|
574
|
+
}
|
575
|
+
|
576
|
+
console.log(`Sent SOL: https://explorer.solana.com/tx/${txSendSignature}?cluster=devnet`);
|
577
|
+
}
|
578
|
+
|
579
|
+
async function main() {
|
580
|
+
const account = await createAccount();
|
581
|
+
await requestFaucet(account.address);
|
582
|
+
await waitForBalance(account.address);
|
583
|
+
await sendTransaction(account.address);
|
584
|
+
}
|
585
|
+
|
586
|
+
main().catch(console.error)
|
587
|
+
```
|
588
|
+
</Tab>
|
589
|
+
|
590
|
+
<Tab value="Python" title="Python">
|
591
|
+
You can send transactions on Solana using the [`solana`](https://solana.com/docs/clients/python) library.
|
592
|
+
|
593
|
+
```bash
|
594
|
+
pip install solana solders
|
595
|
+
```
|
596
|
+
|
597
|
+
In the example below, we:
|
598
|
+
|
599
|
+
1. Create a new Solana account.
|
600
|
+
2. Request SOL from the faucet.
|
601
|
+
3. Wait for funds to become available.
|
602
|
+
4. Send the transaction to a specified address.
|
603
|
+
|
604
|
+
```python main.py lines wrap [expandable]
|
605
|
+
import time
|
606
|
+
import base64
|
607
|
+
import asyncio
|
608
|
+
from cdp import CdpClient
|
609
|
+
from dotenv import load_dotenv
|
610
|
+
from solana.rpc.api import Client as SolanaClient
|
611
|
+
from solana.rpc.types import TxOpts
|
612
|
+
from solders.pubkey import Pubkey as PublicKey
|
613
|
+
from solders.system_program import TransferParams, transfer
|
614
|
+
from solders.message import Message
|
615
|
+
|
616
|
+
load_dotenv()
|
617
|
+
|
618
|
+
cdp = CdpClient()
|
619
|
+
|
620
|
+
connection = SolanaClient("https://api.devnet.solana.com")
|
621
|
+
|
622
|
+
async def create_sol_account():
|
623
|
+
account = await cdp.solana.create_account()
|
624
|
+
print(f"Created account: {account.address}")
|
625
|
+
return account
|
626
|
+
|
627
|
+
|
628
|
+
async def request_faucet(address: str):
|
629
|
+
await cdp.solana.request_faucet(
|
630
|
+
address,
|
631
|
+
token="sol"
|
632
|
+
)
|
633
|
+
|
634
|
+
|
635
|
+
async def wait_for_balance(address: str):
|
636
|
+
balance = 0
|
637
|
+
max_attempts = 30
|
638
|
+
attempts = 0
|
639
|
+
|
640
|
+
while balance == 0 and attempts < max_attempts:
|
641
|
+
balance_resp = connection.get_balance(PublicKey.from_string(address))
|
642
|
+
balance = balance_resp.value
|
643
|
+
if balance == 0:
|
644
|
+
print("Waiting for funds...")
|
645
|
+
time.sleep(1)
|
646
|
+
attempts += 1
|
647
|
+
else:
|
648
|
+
print(f"Account funded with {balance / 1e9} SOL ({balance} lamports)")
|
649
|
+
|
650
|
+
if balance == 0:
|
651
|
+
raise ValueError("Account not funded after multiple attempts")
|
652
|
+
|
653
|
+
|
654
|
+
async def send_transaction(address: str):
|
655
|
+
# Amount of lamports to send (default: 1000 = 0.000001 SOL)
|
656
|
+
lamports_to_send = 1000;
|
657
|
+
from_address = PublicKey.from_string(address)
|
658
|
+
to_address = PublicKey.from_string("EeVPcnRE1mhcY85wAh3uPJG1uFiTNya9dCJjNUPABXzo")
|
659
|
+
|
660
|
+
blockhash_resp = connection.get_latest_blockhash()
|
661
|
+
blockhash = blockhash_resp.value.blockhash
|
662
|
+
|
663
|
+
transfer_params = TransferParams(
|
664
|
+
from_pubkey=from_address,
|
665
|
+
to_pubkey=to_address,
|
666
|
+
lamports=lamports_to_send,
|
667
|
+
)
|
668
|
+
transfer_instr = transfer(transfer_params)
|
669
|
+
|
670
|
+
message = Message.new_with_blockhash(
|
671
|
+
[transfer_instr],
|
672
|
+
from_address,
|
673
|
+
blockhash,
|
674
|
+
)
|
675
|
+
|
676
|
+
# Create a transaction envelope with signature space
|
677
|
+
sig_count = bytes([1]) # 1 byte for signature count (1)
|
678
|
+
empty_sig = bytes([0] * 64) # 64 bytes of zeros for the empty signature
|
679
|
+
message_bytes = bytes(message) # Get the serialized message bytes
|
680
|
+
|
681
|
+
# Concatenate to form the transaction bytes
|
682
|
+
tx_bytes = sig_count + empty_sig + message_bytes
|
683
|
+
|
684
|
+
# Encode to base64 used by CDP API
|
685
|
+
serialized_tx = base64.b64encode(tx_bytes).decode("utf-8")
|
686
|
+
|
687
|
+
signed_tx_response = await cdp.solana.sign_transaction(
|
688
|
+
address,
|
689
|
+
transaction=serialized_tx,
|
690
|
+
)
|
691
|
+
|
692
|
+
# Decode the signed transaction from base64
|
693
|
+
decoded_signed_tx = base64.b64decode(signed_tx_response.signed_transaction)
|
694
|
+
|
695
|
+
print("Sending transaction...")
|
696
|
+
tx_resp = connection.send_raw_transaction(
|
697
|
+
decoded_signed_tx,
|
698
|
+
opts=TxOpts(skip_preflight=False, preflight_commitment="processed"),
|
699
|
+
)
|
700
|
+
signature = tx_resp.value
|
701
|
+
|
702
|
+
print("Waiting for transaction to be confirmed...")
|
703
|
+
confirmation = connection.confirm_transaction(signature, commitment="processed")
|
704
|
+
|
705
|
+
if hasattr(confirmation, "err") and confirmation.err:
|
706
|
+
raise ValueError(f"Transaction failed: {confirmation.err}")
|
707
|
+
|
708
|
+
print(f"Sent SOL: https://explorer.solana.com/tx/{signature}?cluster=devnet")
|
709
|
+
|
710
|
+
|
711
|
+
async def main():
|
712
|
+
account = await create_sol_account()
|
713
|
+
await request_faucet(account.address)
|
714
|
+
await wait_for_balance(account.address)
|
715
|
+
await send_transaction(account.address)
|
716
|
+
|
717
|
+
await cdp.close()
|
718
|
+
|
719
|
+
asyncio.run(main())
|
720
|
+
```
|
721
|
+
</Tab>
|
722
|
+
</Tabs>
|
723
|
+
|
724
|
+
## Video: Watch and learn
|
725
|
+
|
726
|
+
Watch the video to learn about CDP Wallets and see a comprehensive demo, which covers:
|
727
|
+
|
728
|
+
* Overview of CDP Wallet API v2 features and capabilities
|
729
|
+
* Live demonstration of creating accounts and managing wallets
|
730
|
+
* Best practices for building with CDP Wallets
|
731
|
+
|
732
|
+
<Frame>
|
733
|
+
<iframe width="560" height="315" src="https://www.youtube.com/embed/_XMRgDU9a2Y" title="CDP Wallets Demo" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen />
|
734
|
+
</Frame>
|
735
|
+
|
736
|
+
## What to read next
|
737
|
+
|
738
|
+
* [v2 Wallet Accounts](/wallet-api/v2/introduction/accounts): An overview of the types of accounts supported by the v2 Wallet API.
|
739
|
+
* [Using Smart Accounts](/wallet-api/v2/evm-features/smart-accounts): A step-by-step guide on how to create and use smart accounts.
|
740
|
+
* [v2 Wallet Security](/wallet-api/v2/introduction/security): Learn about the security features of the v2 Wallet API.
|
741
|
+
* [Faucets](/faucets/introduction/welcome): Learn more on supported testnet assets and their associated rate limits.
|