A Go script that scans a blockchain using the Blockscout API to find transactions where the Upgraded(address)
event was emitted multiple times (2 or more) within the same transaction.
- Go 1.21 or higher installed
- Internet connection to access the Blockscout API
The scanner is pre-configured to scan the Story network by default using https://www.storyscan.io/.
To scan a different network, you can:
-
Change the default network: Modify the
DefaultConfig()
function inconfig.go
to return a different network configuration (e.g.,BaseNetworkConfig()
,EthereumNetworkConfig()
) -
Use available network configurations in
network_configs.go
:StoryNetworkConfig()
- Story Protocol (default, scans all addresses)StoryTargetedScanConfig()
- Story Protocol with specific addresses (much faster)StoryAddressListConfig("addresses.txt")
- Story Protocol with addresses from fileBaseNetworkConfig()
- Base networkEthereumNetworkConfig()
- Ethereum mainnetRecentBlocksConfig()
- Scan only recent blocksFastScanConfig()
- Faster scanning with larger block ranges
-
Supported networks in the Networks map:
- story: Story Protocol (https://www.storyscan.io/)
- base: Base network (https://base.blockscout.com)
- ethereum: Ethereum mainnet (https://eth.blockscout.com)
- polygon: Polygon (https://polygon.blockscout.com)
- optimism: Optimism (https://optimism.blockscout.com)
-
Configuration options:
- EventTopic: The keccak256 hash of the
Upgraded(address)
event - BlockRange: Number of blocks to scan in each API call (default: 10,000)
- RateLimit: Delay between API calls to respect rate limits (default: 500ms)
- TargetAddresses: List of specific contract addresses to monitor (empty = all addresses)
- EventTopic: The keccak256 hash of the
-
Initialize the Go module (if not already done):
go mod init cpimp-scanner
-
Run the scanner:
go run main.go
- Fetches the latest block number from the blockchain
- Scans the blockchain in chunks (default: 10,000 blocks per chunk)
- Queries Blockscout API for logs matching the
Upgraded(address)
event topic- If
TargetAddresses
is specified, only scans those specific contract addresses (much faster) - If
TargetAddresses
is empty, scans all addresses on the network
- If
- Groups logs by transaction hash and counts occurrences
- Identifies transactions with 2 or more
Upgraded(address)
events - Retrieves transaction details to get the 'from' address
- Outputs results to CSV with the following columns:
- Transaction Hash
- Explorer Link
- From Address
- Block Number
For faster scanning, you can target specific contract addresses:
// In config.go, change DefaultConfig() to:
func DefaultConfig() ScannerConfig {
return StoryTargetedScanConfig()
}
// In config.go, change DefaultConfig() to:
func DefaultConfig() ScannerConfig {
return StoryAddressListConfig("my_addresses.txt")
}
Create a text file (e.g., my_addresses.txt
) with one address per line:
# Comments start with # or //
0x1234567890123456789012345678901234567890
0x2345678901234567890123456789012345678901
# Add as many addresses as needed
Benefits of address targeting:
- 10-100x faster scanning (depending on how many addresses you target vs. total contracts)
- Lower API usage and reduced rate limiting
- Focus on specific contracts you care about
The script creates a file called upgraded_transactions.csv
containing all transactions where the Upgraded(address)
event was emitted multiple times.
- Full chain scan: This script scans the entire blockchain from genesis block to latest
- Rate limiting: Built-in delays to respect API rate limits
- Chunking: Processes blocks in manageable chunks to avoid timeouts
- Resume capability: Automatic resume from interruption with unique progress tracking
- Multiple scans: Run different scans independently (different addresses, networks, etc.)
Each scan gets a unique ID based on its configuration (network, addresses, event topic). This allows multiple independent scans:
- Unique IDs: Each scan configuration gets a unique hash-based ID
- Independent progress: Different scans don't interfere with each other
- Automatic cleanup: Progress files are removed when scans complete
a1b2c3d4e5f6g7h8
- Story network, all addressesf9e8d7c6b5a49382
- Story network, 3 specific addresses9876543210abcdef
- Base network, all addresses
You can run different scans at the same time:
# Terminal 1: Scan all addresses
go run *.go
# Terminal 2: Scan specific addresses (different config)
# Modify config.go to use StoryTargetedScanConfig(), then:
go run *.go
# Each will have its own progress file and can resume independently
The CSV will contain entries like:
Transaction Hash,Explorer Link,From Address,Block Number
0x1234...5678,https://base.blockscout.com/tx/0x1234...5678,0xabcd...ef01,12345678
- API timeouts: Reduce the
BLOCK_RANGE
constant - Rate limit errors: Increase the
RATE_LIMIT_DELAY
constant - Network issues: Check your internet connection and Blockscout URL
- No results: Verify the event topic hash is correct for your use case
To scan for different events:
- Calculate the keccak256 hash of your event signature
- Update the
UPGRADED_EVENT_TOPIC
constant - Modify the struct definitions if your event has different parameters