UNPKG

cdp-docs-cli

Version:

CLI tool to set up CDP (Coinbase Developer Platform) documentation and integration in your project

742 lines (536 loc) 22.1 kB
# Wallet API v2: Quickstart ## Overview The v2 Wallet API allows you to create [accounts](/wallet-api/v2/introduction/accounts) on EVM compatible networks and the Solana network. In this quickstart, you will learn how to: * Create EVM and Solana accounts * Fund your accounts with testnet tokens using CDP Faucets * Send a transaction using `viem` for Typescript or `web3` for Python ## Prerequisites Setup all dependencies, export your keys to environment variables, and initialize a new project before you begin. It is assumed you have: * [Node.js](https://nodejs.org/en) 22.x+ if using Typescript * [Python](https://www.python.org/downloads/) 3.10+ if using Python * [Created](https://portal.cdp.coinbase.com/create-account) and [signed in](https://portal.cdp.coinbase.com/signin) to an existing CDP account Once you have setup the prerequisite dependencies, continue reading to create keys to authenticate your requests and initialize a new project. ### Create keys 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). Keep these values handy as you will need them in the following steps. 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. ### Project setup After creating your keys, initialize a new project and instantiate the CDP client. <Tabs groupId="programming-language"> <Tab value="Typescript" title="Typescript" default> Initialize a new Typescript project by running: ```bash mkdir cdp-sdk-example && cd cdp-sdk-example && npm init -y && npm pkg set type="module" && touch main.ts && touch .env ``` Add your CDP API key and wallet secret to the `.env` file: ```bash .env CDP_API_KEY_ID=your-api-key-id CDP_API_KEY_SECRET=your-api-key-secret CDP_WALLET_SECRET=your-wallet-secret ``` Now, install the [CDP SDK](https://github.com/coinbase/cdp-sdk) and the [dotenv](https://www.npmjs.com/package/dotenv) packages: ```bash npm install @coinbase/cdp-sdk dotenv ``` Finally, in `main.ts`, instantiate the CDP client: ```typescript main.ts lines wrap [expandable] import { CdpClient } from "@coinbase/cdp-sdk"; import dotenv from "dotenv"; dotenv.config(); // Initialize the CDP client, which automatically loads // the API Key and Wallet Secret from the environment // variables. const cdp = new CdpClient(); ``` In this and in the following examples, you can run your code by running: ```bash npx tsx main.ts ``` </Tab> <Tab value="Python" title="Python"> Initialize a new Python project by running: ```bash mkdir cdp-sdk-example && cd cdp-sdk-example && python -m venv .venv && source .venv/bin/activate && touch main.py && touch .env ``` Add your CDP API key and wallet secret to the `.env` file: ```bash .env CDP_API_KEY_ID=your-api-key-id CDP_API_KEY_SECRET=your-api-key-secret CDP_WALLET_SECRET=your-wallet-secret ``` Now, install the [CDP SDK](https://github.com/coinbase/cdp-sdk) and the [python-dotenv](https://pypi.org/project/python-dotenv/) package: ```bash pip install cdp-sdk python-dotenv ``` Finally, in `main.py`, instantiate the CDP client: ```python title="main.py" from cdp import CdpClient import asyncio from dotenv import load_dotenv load_dotenv() async def main(): # Initialize the CDP client, which automatically loads # the API Key and Wallet Secret from the environment # variables. cdp = CdpClient() await cdp.close() asyncio.run(main()) ``` In this and in the following examples, you can run your code by running: ```bash python main.py ``` </Tab> </Tabs> ## 1. Create an account The v2 Wallet API offers support for both [EVM compatible accounts and Solana accounts](/wallet-api/v2/introduction/accounts). ### EVM To create an EVM account, see below: <CodeGroup> ```typescript main.ts lines wrap import { CdpClient } from "@coinbase/cdp-sdk"; import dotenv from "dotenv"; dotenv.config(); const cdp = new CdpClient(); const account = await cdp.evm.createAccount(); console.log(`Created EVM account: ${account.address}`); ``` ```python main.py lines wrap import asyncio from cdp import CdpClient from dotenv import load_dotenv load_dotenv() async def main(): cdp = CdpClient() account = await cdp.evm.create_account() print(f"Created EVM account: {account.address}") await cdp.close() asyncio.run(main()) ``` </CodeGroup> After running the above snippet, you should see similar output: ```console lines wrap Created EVM account: 0x3c0D84055994c3062819Ce8730869D0aDeA4c3Bf ``` <Tip> You can also create accounts with human-readable names and retrieve them later using the `getOrCreateAccount` method. See the [Managing Accounts](/wallet-api/v2/using-the-wallet-api/managing-accounts#account-names) guide for more information. </Tip> ### Solana To create a Solana account, see below: <CodeGroup> ```typescript main.ts lines wrap import { CdpClient } from "@coinbase/cdp-sdk"; import dotenv from "dotenv"; dotenv.config(); const cdp = new CdpClient(); const account = await cdp.solana.createAccount(); console.log(`Created Solana account: ${account.address}`); ``` ```python main.py lines wrap import asyncio from cdp import CdpClient from dotenv import load_dotenv load_dotenv() async def main(): cdp = CdpClient() account = await cdp.solana.create_account() print(f"Created Solana account: {account.address}") await cdp.close() asyncio.run(main()) ``` </CodeGroup> After running the above snippet, you should see similar output: ```console lines wrap Created Solana account: 2XBS6naS1v7pXEg25z43FGHnmEgEad53fmiZ9S6LPgKn ``` ## 2. Fund account with test funds 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. <Info> Before you request funds, ensure you read about [rate limits when using CDP Faucets](/faucets/introduction/welcome#supported-assets). </Info> ### EVM <CodeGroup> ```typescript main.ts lines wrap import { CdpClient } from "@coinbase/cdp-sdk"; import dotenv from "dotenv"; dotenv.config(); const cdp = new CdpClient(); const account = await cdp.evm.createAccount(); const faucetResponse = await cdp.evm.requestFaucet({ address: account.address, network: "base-sepolia", token: "eth" }); console.log(`Requested funds from ETH faucet: https://sepolia.basescan.org/tx/${faucetResponse.transactionHash}`); ``` ```python main.py lines wrap import asyncio from cdp import CdpClient from dotenv import load_dotenv load_dotenv() async def main(): cdp = CdpClient() account = await cdp.evm.create_account() faucet_hash = await cdp.evm.request_faucet( address=account.address, network="base-sepolia", token="eth" ) print(f"Requested funds from ETH faucet: https://sepolia.basescan.org/tx/{faucet_hash}") await cdp.close() asyncio.run(main()) ``` </CodeGroup> After running the above, you should see similar output: ```console lines wrap Requested funds from ETH faucet: https://sepolia.basescan.org/tx/0x9e93a16f2ca67f35bcb1ea2933f19035ae1e71ff3100d2abc6a22ce024d085ec ``` ### Solana <CodeGroup> ```typescript main.ts lines wrap import { CdpClient } from "@coinbase/cdp-sdk"; import dotenv from "dotenv"; dotenv.config(); const cdp = new CdpClient(); const account = await cdp.solana.createAccount(); const { signature } = await cdp.solana.requestFaucet({ address: account.address, token: "sol" }); console.log(`Requested funds from Solana faucet: https://explorer.solana.com/tx/${signature}?cluster=devnet`); ``` ```python main.py lines wrap import asyncio from cdp import CdpClient from dotenv import load_dotenv load_dotenv() async def main(): cdp = CdpClient() account = await cdp.solana.create_account() tx_signature_response = await cdp.solana.request_faucet( address=account.address, token="sol" ) print(f"Requested funds from Solana faucet: https://explorer.solana.com/tx/{tx_signature_response.transaction_signature}?cluster=devnet") await cdp.close() asyncio.run(main()) ``` </CodeGroup> After running the above, you should see similar output: ```console lines wrap Requested funds from Solana faucet: https://explorer.solana.com/tx/4KEPbhkRLTg2FJNqV5bbUd6zv1TNkksxF9PDHw2FodrTha3jq2Cojn4hSKtjPWdrZiRDuYp7okRuc1oYvh3JkLuE?cluster=devnet ``` ## 3. Send a transaction ### EVM <Tabs groupId="programming-language"> <Tab value="Typescript" title="Typescript" default> You can send transactions using the v2 Wallet API. Note that in order to wait for transaction confirmation, you will need to have `viem` installed: ```bash npm install viem ``` In the example below, we: 1. Create a new EVM account. 2. Request ETH from the faucet. 3. Use the v2 Wallet API to send a transaction. 4. Wait for transaction confirmation. ```typescript main.ts lines wrap [expandable] import { CdpClient } from "@coinbase/cdp-sdk"; import { http, createPublicClient, parseEther } from "viem"; import { baseSepolia } from "viem/chains"; import dotenv from "dotenv"; dotenv.config(); const cdp = new CdpClient(); const publicClient = createPublicClient({ chain: baseSepolia, transport: http(), }); // Step 1: Create a new EVM account. const account = await cdp.evm.createAccount(); console.log("Successfully created EVM account:", account.address); // Step 2: Request ETH from the faucet. const { transactionHash: faucetTransactionHash } = await cdp.evm.requestFaucet({ address: account.address, network: "base-sepolia", token: "eth", }); const faucetTxReceipt = await publicClient.waitForTransactionReceipt({ hash: faucetTransactionHash, }); console.log("Successfully requested ETH from faucet:", faucetTxReceipt.transactionHash); // Step 3: Use the v2 Wallet API to send a transaction. const transactionResult = await cdp.evm.sendTransaction({ address: account.address, transaction: { to: "0x0000000000000000000000000000000000000000", value: parseEther("0.000001"), }, network: "base-sepolia", }); // Step 4: Wait for the transaction to be confirmed const txReceipt = await publicClient.waitForTransactionReceipt({ hash: transactionResult.transactionHash, }); console.log( `Transaction sent! Link: https://sepolia.basescan.org/tx/${transactionResult.transactionHash}` ); ``` </Tab> <Tab value="Python" title="Python"> You can send transactions using the v2 Wallet API. Note that in order to wait for transaction confirmation, you will need to have `web3` installed: ```bash pip install web3 ``` In the example below, we: 1. Create a new EVM account. 2. Request ETH from the faucet. 3. Use the v2 Wallet API to send a transaction. 4. Wait for transaction confirmation. ```python main.py lines wrap [expandable] import asyncio from cdp import CdpClient from cdp.evm_transaction_types import TransactionRequestEIP1559 from dotenv import load_dotenv from web3 import Web3 load_dotenv() w3 = Web3(Web3.HTTPProvider("https://sepolia.base.org")) async def main(): async with CdpClient() as cdp: account = await cdp.evm.create_account() print(f"Created account: {account.address}") faucet_hash = await cdp.evm.request_faucet( address=account.address, network="base-sepolia", token="eth" ) w3.eth.wait_for_transaction_receipt(faucet_hash) print(f"Received funds from faucet for address: {account.address}") tx_hash = await cdp.evm.send_transaction( address=account.address, transaction=TransactionRequestEIP1559( to="0x0000000000000000000000000000000000000000", value=w3.to_wei(0.000001, "ether"), ), network="base-sepolia", ) print(f"Transaction sent! Link: https://sepolia.basescan.org/tx/{tx_hash}") asyncio.run(main()) ``` </Tab> </Tabs> ### Solana <Tabs groupId="programming-language"> <Tab value="Typescript" title="Typescript" default> You can send transactions on Solana using the [`@solana/web3.js`](https://solana.com/docs/clients/javascript) v1 library. ```bash npm install @solana/web3.js@1 ``` In the example below, we: 1. Create a new Solana account. 2. Request SOL from the faucet. 3. Wait for funds to become available. 4. Send the transaction to a specified address. ```typescript main.ts lines wrap [expandable] import { Connection, PublicKey, SystemProgram, Transaction, } from "@solana/web3.js"; import { CdpClient } from "@coinbase/cdp-sdk"; import dotenv from "dotenv"; dotenv.config(); const cdp = new CdpClient(); const connection = new Connection("https://api.devnet.solana.com"); async function createAccount() { const account = await cdp.solana.createAccount(); console.log(`Created account: ${account.address}`); return account; } async function requestFaucet(address: string) { await cdp.solana.requestFaucet({ address, token: "sol", }); } async function waitForBalance(address: string) { let balance = 0; let attempts = 0; const maxAttempts = 30; while (balance === 0 && attempts < maxAttempts) { balance = await connection.getBalance(new PublicKey(address)); if (balance === 0) { console.log("Waiting for funds..."); await new Promise(resolve => setTimeout(resolve, 1000)); attempts++; } else { console.log("Account funded with", balance / 1e9, "SOL"); } } if (balance === 0) { throw new Error("Account not funded after multiple attempts"); } } async function sendTransaction(address: string) { // Amount of lamports to send (default: 1000 = 0.000001 SOL) const lamportsToSend = 1000; const fromAddress = new PublicKey(address) const toAddress = new PublicKey("EeVPcnRE1mhcY85wAh3uPJG1uFiTNya9dCJjNUPABXzo"); const { blockhash } = await connection.getLatestBlockhash(); const transaction = new Transaction(); transaction.add( SystemProgram.transfer({ fromPubkey: fromAddress, toPubkey: toAddress, lamports: lamportsToSend, }) ); transaction.recentBlockhash = blockhash; transaction.feePayer = fromAddress; const serializedTx = Buffer.from( transaction.serialize({ requireAllSignatures: false }) ).toString("base64"); const { signature: txSignature } = await cdp.solana.signTransaction({ address, transaction: serializedTx, }); const decodedSignedTx = Buffer.from(txSignature, "base64"); console.log("Sending transaction..."); const txSendSignature = await connection.sendRawTransaction(decodedSignedTx); const latestBlockhash = await connection.getLatestBlockhash(); console.log("Waiting for transaction to be confirmed..."); const confirmation = await connection.confirmTransaction({ signature: txSendSignature, blockhash: latestBlockhash.blockhash, lastValidBlockHeight: latestBlockhash.lastValidBlockHeight, }); if (confirmation.value.err) { throw new Error(`Transaction failed: ${confirmation.value.err.toString()}`); } console.log(`Sent SOL: https://explorer.solana.com/tx/${txSendSignature}?cluster=devnet`); } async function main() { const account = await createAccount(); await requestFaucet(account.address); await waitForBalance(account.address); await sendTransaction(account.address); } main().catch(console.error) ``` </Tab> <Tab value="Python" title="Python"> You can send transactions on Solana using the [`solana`](https://solana.com/docs/clients/python) library. ```bash pip install solana solders ``` In the example below, we: 1. Create a new Solana account. 2. Request SOL from the faucet. 3. Wait for funds to become available. 4. Send the transaction to a specified address. ```python main.py lines wrap [expandable] import time import base64 import asyncio from cdp import CdpClient from dotenv import load_dotenv from solana.rpc.api import Client as SolanaClient from solana.rpc.types import TxOpts from solders.pubkey import Pubkey as PublicKey from solders.system_program import TransferParams, transfer from solders.message import Message load_dotenv() cdp = CdpClient() connection = SolanaClient("https://api.devnet.solana.com") async def create_sol_account(): account = await cdp.solana.create_account() print(f"Created account: {account.address}") return account async def request_faucet(address: str): await cdp.solana.request_faucet( address, token="sol" ) async def wait_for_balance(address: str): balance = 0 max_attempts = 30 attempts = 0 while balance == 0 and attempts < max_attempts: balance_resp = connection.get_balance(PublicKey.from_string(address)) balance = balance_resp.value if balance == 0: print("Waiting for funds...") time.sleep(1) attempts += 1 else: print(f"Account funded with {balance / 1e9} SOL ({balance} lamports)") if balance == 0: raise ValueError("Account not funded after multiple attempts") async def send_transaction(address: str): # Amount of lamports to send (default: 1000 = 0.000001 SOL) lamports_to_send = 1000; from_address = PublicKey.from_string(address) to_address = PublicKey.from_string("EeVPcnRE1mhcY85wAh3uPJG1uFiTNya9dCJjNUPABXzo") blockhash_resp = connection.get_latest_blockhash() blockhash = blockhash_resp.value.blockhash transfer_params = TransferParams( from_pubkey=from_address, to_pubkey=to_address, lamports=lamports_to_send, ) transfer_instr = transfer(transfer_params) message = Message.new_with_blockhash( [transfer_instr], from_address, blockhash, ) # Create a transaction envelope with signature space sig_count = bytes([1]) # 1 byte for signature count (1) empty_sig = bytes([0] * 64) # 64 bytes of zeros for the empty signature message_bytes = bytes(message) # Get the serialized message bytes # Concatenate to form the transaction bytes tx_bytes = sig_count + empty_sig + message_bytes # Encode to base64 used by CDP API serialized_tx = base64.b64encode(tx_bytes).decode("utf-8") signed_tx_response = await cdp.solana.sign_transaction( address, transaction=serialized_tx, ) # Decode the signed transaction from base64 decoded_signed_tx = base64.b64decode(signed_tx_response.signed_transaction) print("Sending transaction...") tx_resp = connection.send_raw_transaction( decoded_signed_tx, opts=TxOpts(skip_preflight=False, preflight_commitment="processed"), ) signature = tx_resp.value print("Waiting for transaction to be confirmed...") confirmation = connection.confirm_transaction(signature, commitment="processed") if hasattr(confirmation, "err") and confirmation.err: raise ValueError(f"Transaction failed: {confirmation.err}") print(f"Sent SOL: https://explorer.solana.com/tx/{signature}?cluster=devnet") async def main(): account = await create_sol_account() await request_faucet(account.address) await wait_for_balance(account.address) await send_transaction(account.address) await cdp.close() asyncio.run(main()) ``` </Tab> </Tabs> ## Video: Watch and learn Watch the video to learn about CDP Wallets and see a comprehensive demo, which covers: * Overview of CDP Wallet API v2 features and capabilities * Live demonstration of creating accounts and managing wallets * Best practices for building with CDP Wallets <Frame> <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 /> </Frame> ## What to read next * [v2 Wallet Accounts](/wallet-api/v2/introduction/accounts): An overview of the types of accounts supported by the v2 Wallet API. * [Using Smart Accounts](/wallet-api/v2/evm-features/smart-accounts): A step-by-step guide on how to create and use smart accounts. * [v2 Wallet Security](/wallet-api/v2/introduction/security): Learn about the security features of the v2 Wallet API. * [Faucets](/faucets/introduction/welcome): Learn more on supported testnet assets and their associated rate limits.