Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 38 additions & 0 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: "Copilot Setup Steps"

# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml

jobs:
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
copilot-setup-steps:
runs-on: ubuntu-latest

# Set the permissions to the lowest permissions possible needed for your steps.
# Copilot will be given its own token for its operations.
permissions:
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
contents: read

# You can define any steps you want, and they will run before the agent starts.
# If you do not check out your code, Copilot will do this for you.
steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"

- name: Install JavaScript dependencies
run: npm ci
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,15 @@ Fork mode creates a local copy of a blockchain network at a specific point in ti
```typescript
import { configure, createOnchainTest } from '@coinbase/onchaintestkit';

// Fork Ethereum mainnet for testing
// Fork Ethereum mainnet for testing with real contracts and data
const test = createOnchainTest(
configure()
.withLocalNode({
fork: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key',
forkBlockNumber: 18500000, // Optional: fork from specific block
forkBlockNumber: 18500000, // Optional: fork from specific block for reproducible tests
chainId: 1,
// Fund test accounts with sufficient ETH for transactions
balance: '100000000000000000000', // 100 ETH per account
})
.withMetaMask()
.withNetwork({
Expand All @@ -134,8 +136,9 @@ const test = createOnchainTest(
);

test('swap on forked Uniswap', async ({ page, metamask }) => {
// Test with real Uniswap contracts and liquidity
// Test with real Uniswap contracts and liquidity pools
await page.goto('https://app.uniswap.org');
// Your test interacts with actual mainnet contract state
// ... your test logic
});
```
Expand Down
41 changes: 38 additions & 3 deletions docs/node/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@ const test = createOnchainTest(
);
```

### Getting Started Tips

If you're new to fork mode, here are some practical tips to get started:

1. **Start Simple**: Begin with a basic fork without specifying a block number - this uses the latest state
2. **Use Demo Keys First**: Many RPC providers offer demo endpoints for testing
3. **Check Your Balance**: Make sure your test accounts have enough ETH for the transactions you plan to test
4. **Verify Chain ID**: Always match the chain ID in your node config with your network config

```typescript
// Beginner-friendly fork setup
const simpleConfig = configure()
.withLocalNode({
// Using a demo endpoint - replace with your own API key for production use
fork: 'https://eth-mainnet.g.alchemy.com/v2/demo',
chainId: 1, // Ethereum mainnet
// Good starting balance for most tests
balance: '100000000000000000000', // 100 ETH
})
.withMetaMask()
.withNetwork({
name: 'Local Fork',
rpcUrl: 'http://localhost:8545',
chainId: 1, // Must match node chainId
symbol: 'ETH',
})
.build();
```

## Configuration Options

The `withLocalNode()` method accepts a `NodeConfig` object with the following options:
Expand Down Expand Up @@ -377,9 +406,15 @@ const config = configure()

#### 2. RPC Provider Selection

- **Paid providers** (Alchemy, Infura): Faster, more reliable
- **Public endpoints**: Free but may be rate-limited
- **Local archive node**: Fastest but requires setup
Different providers offer varying performance and reliability:

- **Alchemy** (`https://eth-mainnet.g.alchemy.com/v2/API_KEY`): Fast, reliable, generous free tier
- **Infura** (`https://mainnet.infura.io/v3/PROJECT_ID`): Well-established, good performance
- **QuickNode** (`https://your-endpoint.quiknode.pro/API_KEY/`): High performance, premium features
- **Public endpoints**: Free but may be slower and rate-limited
- **Local archive node**: Fastest but requires significant setup and storage

Choose paid providers for production testing and public endpoints for initial experimentation.

#### 3. Account Configuration

Expand Down
37 changes: 28 additions & 9 deletions docs/node/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ Here's how to set up fork mode in your tests:
```typescript
import { configure, createOnchainTest } from '@coinbase/onchaintestkit';

// Fork from Ethereum mainnet
// Fork from Ethereum mainnet to test with real contracts and data
const test = createOnchainTest(
configure()
.withLocalNode({
fork: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key',
chainId: 1,
// Configure sufficient balance for testing
balance: '100000000000000000000', // 100 ETH per test account
})
.withMetaMask()
.withNetwork({
Expand All @@ -42,6 +44,7 @@ const test = createOnchainTest(

test('swap tokens on forked mainnet', async ({ page, metamask, node }) => {
// Your test now has access to all mainnet contracts and balances
// This includes real Uniswap pools, token contracts, and liquidity data
// Test interactions with Uniswap, Aave, etc.
});
```
Expand All @@ -68,15 +71,18 @@ const test = createOnchainTest(
### Testing DeFi Interactions

```typescript
import { configure, createOnchainTest } from '@coinbase/onchaintestkit';
import { BaseActionType } from '@coinbase/onchaintestkit';

// Test lending protocol interactions with real liquidity
const test = createOnchainTest(
configure()
.withLocalNode({
fork: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key',
forkBlockNumber: 18500000,
forkBlockNumber: 18500000, // Fork from a specific block for reproducible tests
chainId: 1,
// Pre-fund test accounts with ETH
balance: '100000000000000000000', // 100 ETH
// Pre-fund test accounts with ETH for gas and transactions
balance: '100000000000000000000', // 100 ETH per account
})
.withMetaMask()
.withNetwork({
Expand All @@ -89,37 +95,50 @@ const test = createOnchainTest(
);

test('deposit ETH to Aave', async ({ page, metamask }) => {
// Navigate to Aave interface
// Navigate to Aave interface - this will use real Aave contracts
await page.goto('https://app.aave.com');

// Connect wallet
// Connect MetaMask wallet to the DApp
await page.getByRole('button', { name: 'Connect Wallet' }).click();
await page.getByText('MetaMask').click();
await metamask.handleAction(BaseActionType.CONNECT_TO_DAPP);

// Perform deposit with real Aave contracts
// Perform deposit with real Aave contracts and liquidity data
await page.getByRole('button', { name: 'Supply' }).click();
// ... rest of test logic
// ... rest of test logic for completing the deposit
});
```

### Testing NFT Marketplace

```typescript
// Fork to test NFT interactions with real collections
import { configure, createOnchainTest } from '@coinbase/onchaintestkit';

// Fork to test NFT interactions with real collections and marketplace data
const test = createOnchainTest(
configure()
.withLocalNode({
fork: 'https://eth-mainnet.g.alchemy.com/v2/your-api-key',
chainId: 1,
// Ensure sufficient ETH for NFT transactions and gas
balance: '50000000000000000000', // 50 ETH per account
})
.withMetaMask()
.withNetwork({
name: 'Forked Mainnet',
rpcUrl: 'http://localhost:8545',
chainId: 1,
symbol: 'ETH',
})
.build()
);

test('bid on NFT auction', async ({ page, metamask }) => {
// Test with real NFT collections and marketplace contracts
await page.goto('https://opensea.io/collection/your-collection');

// Connect wallet and place bid using real marketplace contracts
// This interacts with actual OpenSea contracts and NFT data
// ... test NFT bidding logic
});
```
Expand Down