323 lines
6.8 KiB
Markdown
323 lines
6.8 KiB
Markdown
|
|
# Etherscan-Compatible API Specification
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
This document specifies the Etherscan-compatible API layer that provides an API surface matching Blockscout/Etherscan APIs for tool compatibility and easier migration.
|
||
|
|
|
||
|
|
**Base URL**: `https://api.explorer.d-bis.org/api`
|
||
|
|
|
||
|
|
**Note**: This is a compatibility layer that translates Etherscan API calls to our internal API.
|
||
|
|
|
||
|
|
## API Surface Mapping
|
||
|
|
|
||
|
|
### Account Endpoints
|
||
|
|
|
||
|
|
#### Get Account Balance
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=account&action=balance&address={address}&tag=latest`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/addresses/{chain_id}/{address}` (extract balance)
|
||
|
|
|
||
|
|
**Response Format** (matches Etherscan):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "1",
|
||
|
|
"message": "OK",
|
||
|
|
"result": "1000000000000000000"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Get Token Balance
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=account&action=tokenbalance&contractaddress={token}&address={address}&tag=latest`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/addresses/{chain_id}/{address}/tokens` (filter by token address)
|
||
|
|
|
||
|
|
**Response Format**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "1",
|
||
|
|
"message": "OK",
|
||
|
|
"result": "1000000000000000000"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Get Transaction List
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=account&action=txlist&address={address}&startblock=0&endblock=99999999&page=1&offset=10&sort=desc`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/addresses/{chain_id}/{address}/transactions` (with pagination)
|
||
|
|
|
||
|
|
**Response Format**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "1",
|
||
|
|
"message": "OK",
|
||
|
|
"result": [
|
||
|
|
{
|
||
|
|
"blockNumber": "12345",
|
||
|
|
"timeStamp": "1640995200",
|
||
|
|
"hash": "0x...",
|
||
|
|
"from": "0x...",
|
||
|
|
"to": "0x...",
|
||
|
|
"value": "1000000000000000000",
|
||
|
|
"gas": "21000",
|
||
|
|
"gasPrice": "20000000000",
|
||
|
|
"gasUsed": "21000",
|
||
|
|
"isError": "0",
|
||
|
|
"txreceipt_status": "1"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Transaction Endpoints
|
||
|
|
|
||
|
|
#### Get Transaction Status
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=transaction&action=getstatus&txhash={hash}`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/transactions/{chain_id}/{hash}` (extract status)
|
||
|
|
|
||
|
|
**Response Format**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "1",
|
||
|
|
"message": "OK",
|
||
|
|
"result": {
|
||
|
|
"isError": "0",
|
||
|
|
"errDescription": ""
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Get Transaction Receipt Status
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=transaction&action=gettxreceiptstatus&txhash={hash}`
|
||
|
|
|
||
|
|
**Response Format**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "1",
|
||
|
|
"message": "OK",
|
||
|
|
"result": {
|
||
|
|
"status": "1"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Block Endpoints
|
||
|
|
|
||
|
|
#### Get Block by Number
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=proxy&action=eth_getBlockByNumber&tag={number}&boolean=true`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/blocks/{chain_id}/{number}` (transform format)
|
||
|
|
|
||
|
|
**Response Format** (Ethereum JSON-RPC format):
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"jsonrpc": "2.0",
|
||
|
|
"result": {
|
||
|
|
"number": "0x3039",
|
||
|
|
"hash": "0x...",
|
||
|
|
"transactions": [...]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Contract Endpoints
|
||
|
|
|
||
|
|
#### Get Contract ABI
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=contract&action=getabi&address={address}`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/contracts/{chain_id}/{address}/abi`
|
||
|
|
|
||
|
|
**Response Format**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "1",
|
||
|
|
"message": "OK",
|
||
|
|
"result": "[{...}]"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Verify Contract
|
||
|
|
|
||
|
|
**Etherscan**: `POST /api?module=contract&action=verifysourcecode`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `POST /v1/contracts/{chain_id}/{address}/verify`
|
||
|
|
|
||
|
|
**Parameter Mapping**:
|
||
|
|
- `sourceCode` → `source_code`
|
||
|
|
- `codeformat` → `verification_method`
|
||
|
|
- `contractaddress` → `address`
|
||
|
|
- `compilerversion` → `compiler_version`
|
||
|
|
|
||
|
|
### Token Endpoints
|
||
|
|
|
||
|
|
#### Get Token Total Supply
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=stats&action=tokensupply&contractaddress={address}`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/tokens/{chain_id}/{address}` (extract total_supply)
|
||
|
|
|
||
|
|
### Event Logs
|
||
|
|
|
||
|
|
#### Get Event Logs
|
||
|
|
|
||
|
|
**Etherscan**: `GET /api?module=logs&action=getLogs&address={address}&topic0={topic0}&fromBlock={fromBlock}&toBlock={toBlock}`
|
||
|
|
|
||
|
|
**Our Implementation**:
|
||
|
|
- Maps to: `GET /v1/logs` (with filters)
|
||
|
|
|
||
|
|
**Response Format**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "1",
|
||
|
|
"message": "OK",
|
||
|
|
"result": [
|
||
|
|
{
|
||
|
|
"address": "0x...",
|
||
|
|
"topics": ["0x..."],
|
||
|
|
"data": "0x...",
|
||
|
|
"blockNumber": "0x3039",
|
||
|
|
"transactionHash": "0x...",
|
||
|
|
"logIndex": "0x0"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Parameter Translation
|
||
|
|
|
||
|
|
### Common Parameters
|
||
|
|
|
||
|
|
| Etherscan | Our API | Notes |
|
||
|
|
|-----------|---------|-------|
|
||
|
|
| `module` | N/A | Determines endpoint category |
|
||
|
|
| `action` | N/A | Determines specific action |
|
||
|
|
| `address` | `address` | Same |
|
||
|
|
| `tag` | `block_number` | Convert "latest" to current block |
|
||
|
|
| `startblock` | `from_block` | Same |
|
||
|
|
| `endblock` | `to_block` | Same |
|
||
|
|
| `page` | `page` | Same |
|
||
|
|
| `offset` | `page_size` | Same |
|
||
|
|
| `sort` | `order` | Same (asc/desc) |
|
||
|
|
|
||
|
|
### Chain ID Handling
|
||
|
|
|
||
|
|
**Etherscan**: No chain_id parameter (single chain)
|
||
|
|
|
||
|
|
**Our API**: Require `chain_id` parameter or use default from context
|
||
|
|
|
||
|
|
**Mapping**: Add `chain_id` parameter to all requests
|
||
|
|
|
||
|
|
## Response Format Compatibility
|
||
|
|
|
||
|
|
### Status Codes
|
||
|
|
|
||
|
|
**Etherscan Format**:
|
||
|
|
- `status: "1"` = Success
|
||
|
|
- `status: "0"` = Error
|
||
|
|
|
||
|
|
**Our Format**:
|
||
|
|
- HTTP 200 = Success (map to status "1")
|
||
|
|
- HTTP 4xx/5xx = Error (map to status "0")
|
||
|
|
|
||
|
|
### Error Messages
|
||
|
|
|
||
|
|
**Etherscan Format**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"status": "0",
|
||
|
|
"message": "NOTOK",
|
||
|
|
"result": "Error message here"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Our Mapping**:
|
||
|
|
- Map our error codes to Etherscan error messages
|
||
|
|
- Preserve error details in result field
|
||
|
|
|
||
|
|
## Migration Guide
|
||
|
|
|
||
|
|
### For Tools Using Etherscan API
|
||
|
|
|
||
|
|
**Step 1**: Update base URL
|
||
|
|
- Old: `https://api.etherscan.io/api`
|
||
|
|
- New: `https://api.explorer.d-bis.org/api`
|
||
|
|
|
||
|
|
**Step 2**: Add chain_id parameter (if needed)
|
||
|
|
- Add `&chainid=138` to requests
|
||
|
|
- Or use default chain from connection
|
||
|
|
|
||
|
|
**Step 3**: Test compatibility
|
||
|
|
- Verify response formats match
|
||
|
|
- Check error handling
|
||
|
|
- Validate data accuracy
|
||
|
|
|
||
|
|
### For New Integrations
|
||
|
|
|
||
|
|
**Recommendation**: Use native REST API instead of Etherscan-compatible API
|
||
|
|
- More features
|
||
|
|
- Better performance
|
||
|
|
- Clearer API design
|
||
|
|
|
||
|
|
## Limitations
|
||
|
|
|
||
|
|
### Not All Endpoints Supported
|
||
|
|
|
||
|
|
**Supported**:
|
||
|
|
- Account operations
|
||
|
|
- Transaction queries
|
||
|
|
- Block queries
|
||
|
|
- Contract verification
|
||
|
|
- Token operations
|
||
|
|
- Event logs
|
||
|
|
|
||
|
|
**Not Supported** (Etherscan-specific):
|
||
|
|
- Gas tracker (use our analytics API)
|
||
|
|
- Historical stats (use our analytics API)
|
||
|
|
- Token list (use our token API)
|
||
|
|
|
||
|
|
### Response Format Differences
|
||
|
|
|
||
|
|
**Some differences may exist**:
|
||
|
|
- Field naming (camelCase vs snake_case)
|
||
|
|
- Data precision
|
||
|
|
- Additional fields in our responses
|
||
|
|
|
||
|
|
## Implementation
|
||
|
|
|
||
|
|
### Translation Layer
|
||
|
|
|
||
|
|
**Architecture**:
|
||
|
|
- Request interceptor: Parse Etherscan-style requests
|
||
|
|
- Parameter mapper: Convert to our API format
|
||
|
|
- Response transformer: Convert our responses to Etherscan format
|
||
|
|
|
||
|
|
**Code Structure**:
|
||
|
|
```
|
||
|
|
compatibility/
|
||
|
|
├── etherscan/
|
||
|
|
│ ├── request_parser.py # Parse Etherscan requests
|
||
|
|
│ ├── parameter_mapper.py # Map parameters
|
||
|
|
│ └── response_transformer.py # Transform responses
|
||
|
|
```
|
||
|
|
|
||
|
|
## References
|
||
|
|
|
||
|
|
- REST API: See `rest-api.md`
|
||
|
|
- API Gateway: See `api-gateway.md`
|
||
|
|
|