diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 0000000..5663b47 --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -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 \ No newline at end of file diff --git a/README.md b/README.md index 007a0f9..5ce72c3 100644 --- a/README.md +++ b/README.md @@ -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({ @@ -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 }); ``` diff --git a/docs/node/configuration.mdx b/docs/node/configuration.mdx index 3edf190..269055c 100644 --- a/docs/node/configuration.mdx +++ b/docs/node/configuration.mdx @@ -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: @@ -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 diff --git a/docs/node/overview.mdx b/docs/node/overview.mdx index 0789d05..22719eb 100644 --- a/docs/node/overview.mdx +++ b/docs/node/overview.mdx @@ -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({ @@ -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. }); ``` @@ -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({ @@ -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 }); ```