Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:01:14 +08:00
commit e17e955d35
19 changed files with 6218 additions and 0 deletions

View File

@@ -0,0 +1,305 @@
# Anvil Advanced Usage
Advanced Anvil features for local development and testing.
## Account Impersonation
### Auto-Impersonate All Accounts
```bash
# Start with auto-impersonation
anvil --auto-impersonate
```
Now any account can send transactions without private key:
```bash
cast send $CONTRACT "transfer(address,uint256)" $TO 1000 \
--from 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 \
--unlocked
```
### Impersonate Specific Account
```bash
# Via RPC
cast rpc anvil_impersonateAccount 0x1234...
# Stop impersonating
cast rpc anvil_stopImpersonatingAccount 0x1234...
```
### In Foundry Tests
```solidity
address whale = 0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503;
vm.startPrank(whale);
usdc.transfer(address(this), 1_000_000e6);
vm.stopPrank();
```
## State Manipulation
### Set Balance
```bash
# Set ETH balance
cast rpc anvil_setBalance 0x1234... 0xDE0B6B3A7640000 # 1 ETH in hex
# In tests
vm.deal(address, 100 ether);
```
### Set Code
```bash
# Deploy code at address
cast rpc anvil_setCode 0x1234... 0x608060405234801...
# In tests
vm.etch(address, code);
```
### Set Storage
```bash
# Set storage slot
cast rpc anvil_setStorageAt 0x1234... 0x0 0x...
# In tests
vm.store(address, slot, value);
```
### Set Nonce
```bash
cast rpc anvil_setNonce 0x1234... 0x10 # 16 in hex
```
## Mining Modes
### Auto-Mining (Default)
```bash
anvil # Mines block on each transaction
```
### Interval Mining
```bash
# Mine every 12 seconds
anvil --block-time 12
```
### Manual Mining
```bash
# Disable auto-mining
anvil --no-mining
# Mine manually
cast rpc evm_mine
# Mine multiple blocks
cast rpc anvil_mine 10 # Mine 10 blocks
```
### Mining Control
```bash
# Enable auto-mine
cast rpc evm_setAutomine true
# Set interval
cast rpc evm_setIntervalMining 5000 # 5 seconds in ms
```
## State Snapshots
### Dump State
```bash
# Start anvil, make changes, then dump
anvil --dump-state state.json
# Load from previous state
anvil --load-state state.json
```
### Runtime Snapshots
```bash
# Create snapshot
SNAPSHOT_ID=$(cast rpc evm_snapshot)
# Make changes...
# Revert to snapshot
cast rpc evm_revert $SNAPSHOT_ID
```
### In Tests
```solidity
uint256 snapshot = vm.snapshot();
// Make changes...
vm.revertTo(snapshot);
```
## Fork Configuration
### Basic Fork
```bash
anvil --fork-url https://eth-mainnet.g.alchemy.com/v2/KEY
```
### Pin Block
```bash
anvil --fork-url $RPC_URL --fork-block-number 18000000
```
### Fork with Caching
```bash
# Cache fork data locally
anvil --fork-url $RPC_URL --fork-retry-backoff 1000
# Disable caching
anvil --fork-url $RPC_URL --no-storage-caching
```
### Multiple Forks
```solidity
// In tests
uint256 mainnetFork = vm.createFork("mainnet");
uint256 arbitrumFork = vm.createFork("arbitrum");
vm.selectFork(mainnetFork);
// Test on mainnet...
vm.selectFork(arbitrumFork);
// Test on arbitrum...
```
## Time Manipulation
```bash
# Set timestamp
cast rpc evm_setNextBlockTimestamp 1700000000
# Increase time
cast rpc evm_increaseTime 86400 # 1 day
# In tests
vm.warp(block.timestamp + 1 days);
vm.roll(block.number + 100);
```
## RPC Methods
### Common Anvil RPC
| Method | Description |
|--------|-------------|
| `anvil_setBalance` | Set ETH balance |
| `anvil_setCode` | Set contract code |
| `anvil_setStorageAt` | Set storage slot |
| `anvil_setNonce` | Set account nonce |
| `anvil_impersonateAccount` | Impersonate address |
| `anvil_mine` | Mine blocks |
| `anvil_reset` | Reset fork |
| `anvil_dumpState` | Export state |
| `anvil_loadState` | Import state |
### EVM Methods
| Method | Description |
|--------|-------------|
| `evm_snapshot` | Create snapshot |
| `evm_revert` | Revert to snapshot |
| `evm_mine` | Mine single block |
| `evm_setAutomine` | Toggle auto-mining |
| `evm_increaseTime` | Advance time |
| `evm_setNextBlockTimestamp` | Set next timestamp |
## Configuration
### Startup Options
```bash
anvil \
--port 8545 \
--accounts 10 \
--balance 10000 \
--mnemonic "test test test..." \
--derivation-path "m/44'/60'/0'/0/" \
--block-time 12 \
--gas-limit 30000000 \
--gas-price 0 \
--chain-id 31337 \
--hardfork prague
```
### Hardfork Selection
```bash
anvil --hardfork shanghai
anvil --hardfork cancun
anvil --hardfork prague # Latest
```
## Testing Patterns
### Fork Test Setup
```solidity
function setUp() public {
vm.createSelectFork(vm.envString("MAINNET_RPC_URL"), 18000000);
// Impersonate whale
address whale = 0x47ac0Fb4F2D84898e4D9E7b4DaB3C24507a6D503;
vm.startPrank(whale);
usdc.transfer(address(this), 1_000_000e6);
vm.stopPrank();
}
```
### State Reset Between Tests
```solidity
uint256 snapshot;
function setUp() public {
if (snapshot == 0) {
// First run: setup and snapshot
_deployContracts();
snapshot = vm.snapshot();
} else {
// Subsequent runs: revert to clean state
vm.revertTo(snapshot);
}
}
```
### Testing Mainnet Interactions
```solidity
function test_SwapOnUniswap() public {
vm.createSelectFork("mainnet");
address router = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
deal(address(this), 10 ether);
IRouter(router).swapExactETHForTokens{value: 1 ether}(
0, path, address(this), block.timestamp
);
}
```