A comprehensive TypeScript module for blockchain interactions using Coinbase Developer Platform (CDP) SDK. This module provides easy-to-use functions for ENS registration, token transfers, approvals, and transaction management on EVM-compatible chains.
- ✅ ENS Name Registration - Register and manage Ethereum Name Service domains
- ✅ Native Token Transfers - Send ETH/native tokens across networks
- ✅ ERC-20 Operations - Transfer, approve, and check allowances for any ERC-20 token
- ✅ Generic Transactions - Send any custom transaction to the blockchain
- ✅ Contract Reading - Read data from smart contracts (view/pure functions)
- ✅ TypeScript Support - Full type safety with comprehensive type definitions
- ✅ Multi-Network - Support for Ethereum, Base, and their testnets
- 🔄 Automatic gas estimation
- 🔐 Secure transaction signing via CDP API
- 📊 Token balance and allowance checking
- 🎯 Idempotency support for reliable operations
- 🛠️ Utility functions for formatting and parsing amounts
Before you begin, ensure you have:
- Node.js v18+ installed
- CDP API credentials (API Key ID and Secret)
- TypeScript v5.0+ (optional but recommended)
- Basic understanding of Ethereum/EVM blockchains
# Create project directory
mkdir blockchain-operations
cd blockchain-operations
# Copy the module files
# - abis.ts
# - blockchain.ts
# - utils.ts (optional)npm install @coinbase/cdp-sdk viemnpm install --save-dev typescript @types/node tsxnpx tsc --initUpdate tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022"],
"esModuleInterop": true,
"skipLibCheck": true,
"strict": true,
"resolveJsonModule": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}Visit Coinbase Developer Platform and:
- Create a new project
- Generate API credentials
- Save your API Key ID and API Key Secret
Create a .env file:
CDP_API_KEY_ID=your_api_key_id_here
CDP_API_KEY_SECRET=your_api_key_secret_here
CDP_WALLET_SECRET=optional_wallet_encryption_secretimport dotenv from 'dotenv';
dotenv.config();import { CdpClient } from "@coinbase/cdp-sdk";
import { BlockchainOperations } from "./blockchain.js";
import { parseUnits } from "viem";
// Initialize CDP Client
const cdp = new CdpClient({
apiKeyId: process.env.CDP_API_KEY_ID!,
apiKeySecret: process.env.CDP_API_KEY_SECRET!,
});
// Create blockchain operations instance
const blockchain = new BlockchainOperations(cdp.openApiClient);
// Get or create an account
const account = await cdp.evm.createAccount({ name: "MyWallet" });
console.log(`Account address: ${account.address}`);// Transfer 0.001 ETH
const result = await blockchain.transferNative({
from: account.address,
to: "0x1234567890123456789012345678901234567890",
amountInEth: "0.001",
network: "base-sepolia",
});
console.log(`Transaction hash: ${result.transactionHash}`);new BlockchainOperations(client: CdpOpenApiClientType)Creates a new instance of blockchain operations.
Parameters:
client- CDP OpenAPI client instance
Register a new ENS domain name.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
owner |
Address |
✅ | Owner's wallet address |
name |
string |
✅ | ENS name (without .eth) |
durationInYears |
number |
✅ | Registration duration |
network |
"ethereum" | "ethereum-sepolia" |
✅ | Network to use |
idempotencyKey |
string |
❌ | Optional idempotency key |
Returns: Promise<TransactionResult>
Example:
const result = await blockchain.registerENSName({
owner: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
name: "myname",
durationInYears: 1,
network: "ethereum-sepolia"
});Check if an ENS name is available for registration.
Example:
const available = await blockchain.checkENSAvailability(
"myname",
"ethereum-sepolia"
);
console.log(`Available: ${available}`);Transfer native tokens (ETH) to another address.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
from |
Address |
✅ | Sender's address |
to |
Address |
✅ | Recipient's address |
amountInEth |
string |
✅ | Amount in ETH (e.g., "0.1") |
network |
Network |
✅ | Network to use |
idempotencyKey |
string |
❌ | Optional idempotency key |
Returns: Promise<TransactionResult>
Example:
const result = await blockchain.transferNative({
from: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
to: "0x1234567890123456789012345678901234567890",
amountInEth: "0.1",
network: "base-sepolia"
});Transfer ERC-20 tokens to another address.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
from |
Address |
✅ | Sender's address |
to |
Address |
✅ | Recipient's address |
tokenAddress |
Address |
✅ | Token contract address |
amount |
bigint |
✅ | Amount in smallest unit |
network |
Network |
✅ | Network to use |
idempotencyKey |
string |
❌ | Optional idempotency key |
Returns: Promise<TransactionResult>
Example:
import { parseUnits } from "viem";
// Transfer 100 USDC (6 decimals)
const result = await blockchain.transferERC20({
from: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
to: "0x1234567890123456789012345678901234567890",
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
amount: parseUnits("100", 6),
network: "base"
});Approve a spender to use your ERC-20 tokens.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
from |
Address |
✅ | Owner's address |
spender |
Address |
✅ | Spender's address |
tokenAddress |
Address |
✅ | Token contract address |
amount |
bigint |
✅ | Amount to approve |
network |
Network |
✅ | Network to use |
idempotencyKey |
string |
❌ | Optional idempotency key |
Returns: Promise<TransactionResult>
Example:
// Approve Uniswap to spend 1000 USDC
const result = await blockchain.approveERC20({
from: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
spender: "0xUniswapRouterAddress",
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
amount: parseUnits("1000", 6),
network: "base"
});Approve unlimited amount (max uint256).
Example:
const result = await blockchain.approveERC20Unlimited({
from: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
spender: "0xUniswapRouterAddress",
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
network: "base"
});Check how much a spender is allowed to spend.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
owner |
Address |
✅ | Token owner's address |
spender |
Address |
✅ | Spender's address |
tokenAddress |
Address |
✅ | Token contract address |
network |
Network |
✅ | Network to use |
Returns: Promise<bigint> - Current allowance amount
Example:
const allowance = await blockchain.checkAllowance({
owner: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
spender: "0xUniswapRouterAddress",
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
network: "base"
});
console.log(`Allowance: ${formatUnits(allowance, 6)} USDC`);Check if allowance is sufficient for a transfer.
Example:
const hasEnough = await blockchain.hasEnoughAllowance({
owner: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
spender: "0xUniswapRouterAddress",
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
requiredAmount: parseUnits("500", 6),
network: "base"
});
console.log(`Has enough allowance: ${hasEnough}`);Send a generic EVM transaction.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
from |
Address |
✅ | Sender's address |
transaction |
TransactionRequestEIP1559 |
✅ | Transaction request |
network |
Network |
✅ | Network to use |
idempotencyKey |
string |
❌ | Optional idempotency key |
Returns: Promise<TransactionResult>
Example:
import { parseEther } from "viem";
const result = await blockchain.sendTransaction({
from: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
transaction: {
to: "0x1234567890123456789012345678901234567890",
value: parseEther("0.1"),
data: "0x"
},
network: "base-sepolia"
});Read data from a smart contract (view/pure functions).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
contractAddress |
Address |
✅ | Contract address |
abi |
readonly unknown[] |
✅ | Contract ABI |
functionName |
string |
✅ | Function to call |
args |
unknown[] |
❌ | Function arguments |
network |
Network |
✅ | Network to use |
Example (with external RPC):
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";
// Use viem for read operations
const publicClient = createPublicClient({
chain: base,
transport: http()
});
const balance = await publicClient.readContract({
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
abi: ERC20_ABI,
functionName: "balanceOf",
args: ["0x742d35Cc6634C0532925a3b844Bc454e4438f44e"]
});Get comprehensive token information.
Example:
const info = await blockchain.getTokenInfo(
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"base"
);
console.log(`Token: ${info.name} (${info.symbol})`);
console.log(`Decimals: ${info.decimals}`);
console.log(`Total Supply: ${info.totalSupply}`);Get token balance for an account.
Example:
const balance = await blockchain.getERC20Balance(
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"base"
);Format token amount with proper decimals.
const formatted = blockchain.formatTokenAmount(
BigInt(1000000),
6
);
console.log(formatted); // "1.0"Parse amount from human-readable string.
const parsed = blockchain.parseTokenAmount("1.5", 6);
console.log(parsed); // 1500000nimport { CdpClient } from "@coinbase/cdp-sdk";
import { BlockchainOperations } from "./blockchain.js";
import { parseUnits, formatUnits } from "viem";
async function completeWorkflow() {
// 1. Initialize
const cdp = new CdpClient({
apiKeyId: process.env.CDP_API_KEY_ID!,
apiKeySecret: process.env.CDP_API_KEY_SECRET!,
});
const blockchain = new BlockchainOperations(cdp.openApiClient);
const account = await cdp.evm.createAccount({ name: "Demo" });
console.log(`Account: ${account.address}`);
// 2. Get testnet funds
await account.requestFaucet({
network: "base-sepolia",
token: "eth"
});
// 3. Transfer ETH
const ethTransfer = await blockchain.transferNative({
from: account.address,
to: "0x1234567890123456789012345678901234567890",
amountInEth: "0.001",
network: "base-sepolia"
});
console.log(`ETH Transfer: ${ethTransfer.transactionHash}`);
// 4. Transfer ERC-20
const usdcAddress = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
const erc20Transfer = await blockchain.transferERC20({
from: account.address,
to: "0x1234567890123456789012345678901234567890",
tokenAddress: usdcAddress,
amount: parseUnits("10", 6),
network: "base-sepolia"
});
console.log(`USDC Transfer: ${erc20Transfer.transactionHash}`);
// 5. Approve token spending
const approval = await blockchain.approveERC20({
from: account.address,
spender: "0x9876543210987654321098765432109876543210",
tokenAddress: usdcAddress,
amount: parseUnits("100", 6),
network: "base-sepolia"
});
console.log(`Approval: ${approval.transactionHash}`);
// 6. Check allowance
const allowance = await blockchain.checkAllowance({
owner: account.address,
spender: "0x9876543210987654321098765432109876543210",
tokenAddress: usdcAddress,
network: "base-sepolia"
});
console.log(`Allowance: ${formatUnits(allowance, 6)} USDC`);
}
completeWorkflow().catch(console.error);async function swapWithUniswap() {
const UNISWAP_ROUTER = "0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24";
const USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
// 1. Check current allowance
const currentAllowance = await blockchain.checkAllowance({
owner: account.address,
spender: UNISWAP_ROUTER,
tokenAddress: USDC,
network: "base"
});
const requiredAmount = parseUnits("1000", 6);
// 2. Approve if needed
if (currentAllowance < requiredAmount) {
console.log("Approving USDC for Uniswap...");
await blockchain.approveERC20({
from: account.address,
spender: UNISWAP_ROUTER,
tokenAddress: USDC,
amount: requiredAmount,
network: "base"
});
}
// 3. Execute swap
// (You would encode the swap call data here)
console.log("Ready to swap!");
}async function multiNetworkOperations() {
const networks = ["base", "base-sepolia", "ethereum-sepolia"] as const;
for (const network of networks) {
console.log(`\n=== Operating on ${network} ===`);
// Transfer on each network
const result = await blockchain.transferNative({
from: account.address,
to: "0x1234567890123456789012345678901234567890",
amountInEth: "0.001",
network
});
console.log(`✅ Transaction: ${result.transactionHash}`);
}
}my-blockchain-project/
├── src/
│ ├── abis.ts # Contract ABIs
│ ├── blockchain.ts # Main operations
│ ├── utils.ts # Helper functions
│ ├── config.ts # Configuration
│ └── examples/
│ ├── basic-transfer.ts
│ ├── token-approval.ts
│ └── ens-registration.ts
├── tests/
│ └── blockchain.test.ts
├── .env
├── .gitignore
├── package.json
├── tsconfig.json
└── README.md