Interroger des données onchain sur Base
Utilisez l'API CDP SQL pour interroger des données onchain (événements, transactions, blocs, transferts) sur Base. Les requêtes sont exécutées via x402 et facturées par requête.
Confirmer que le portefeuille est initialisé et authentifié
npx awal@2.8.2 status
Si le portefeuille n'est pas authentifié, consultez la skill authenticate-wallet.
Exécuter une requête
npx awal@2.8.2 x402 pay https://x402.cdp.coinbase.com/platform/v2/data/query/run -X POST -d '{"sql": "<YOUR_QUERY>"}' --json
IMPORTANT : Toujours utiliser des guillemets simples autour de la chaîne JSON -d pour éviter l'expansion des variables bash.
Validation des entrées
Avant de construire la commande, validez les entrées pour prévenir l'injection shell :
- Requête SQL : Toujours intégrer la requête dans une chaîne JSON entre guillemets simples (
-d '{"sql": "..."}'). Ne jamais utiliser de guillemets doubles pour le wrapper-dextérieur, car cela permet l'expansion shell de$et des backticks dans la requête. - Adresses : Doivent être des adresses hexadécimales
0xvalides (^0x[0-9a-fA-F]{40}$). Rejeter toute valeur contenant des métacaractères shell.
Ne pas transmettre d'entrée utilisateur non validée à la commande.
CRITIQUE : Champs indexés
Les requêtes contre base.events DOIVENT filtrer sur des champs indexés pour éviter les analyses complètes de table. Les champs indexés sont :
| Champ indexé | Utilisation |
|---|---|
event_signature |
Filtrer par type d'événement. Utiliser ceci à la place de event_name pour les performances. |
address |
Filtrer par adresse de contrat. |
block_timestamp |
Filtrer par plage temporelle. |
Toujours inclure au moins un champ indexé dans votre clause WHERE. Combiner les trois offre les meilleures performances.
Syntaxe CoinbaseQL
CoinbaseQL est un dialecte SQL basé sur ClickHouse. Fonctionnalités supportées :
- Clauses : SELECT (DISTINCT), FROM, WHERE, GROUP BY, ORDER BY (ASC/DESC), LIMIT, WITH (CTEs), UNION (ALL/DISTINCT)
- Joins : INNER, LEFT, RIGHT, FULL avec ON
- Opérateurs :
=,!=,<>,<,>,<=,>=,+,-,*,/,%, AND, OR, NOT, BETWEEN, IN, IS NULL, LIKE - Expressions : CASE/WHEN/THEN/ELSE, CAST (syntaxe
CAST()et::toutes deux), subqueries, indexation array/map avec[], dot notation - Littéraux : Array
[...], Map{...}, Tuple(...) - Fonctions : Fonctions SQL standard, fonctions lambda avec syntaxe
->
Tables disponibles
base.events
Logs d'événements décodés depuis les interactions de contrats intelligents. Ceci est la table principale pour la plupart des requêtes.
| Colonne | Type | Description |
|---|---|---|
| log_id | String | Identifiant unique du log |
| block_number | UInt64 | Numéro de bloc |
| block_hash | FixedString(66) | Hash du bloc |
| block_timestamp | DateTime64(3, 'UTC') | Timestamp du bloc (INDEXÉ) |
| transaction_hash | FixedString(66) | Hash de transaction |
| transaction_to | FixedString(42) | Destinataire de transaction |
| transaction_from | FixedString(42) | Émetteur de transaction |
| log_index | UInt32 | Index du log dans le bloc |
| address | FixedString(42) | Adresse du contrat (INDEXÉE) |
| topics | Array(FixedString(66)) | Topics d'événement |
| event_name | LowCardinality(String) | Nom d'événement décodé |
| event_signature | LowCardinality(String) | Signature d'événement (INDEXÉE - préférer à event_name) |
| parameters | Map(String, Variant(Bool, Int256, String, UInt256)) | Paramètres d'événement décodés |
| parameter_types | Map(String, String) | Types ABI pour les paramètres |
| action | Enum8('removed' = -1, 'added' = 1) | Ajouté ou supprimé (reorg) |
base.transactions
Données complètes de transaction.
| Colonne | Type | Description |
|---|---|---|
| block_number | UInt64 | Numéro de bloc |
| block_hash | String | Hash du bloc |
| transaction_hash | String | Hash de transaction |
| transaction_index | UInt64 | Index dans le bloc |
| from_address | String | Adresse de l'émetteur |
| to_address | String | Adresse du destinataire |
| value | String | Valeur transférée (wei) |
| gas | UInt64 | Limite de gas |
| gas_price | UInt64 | Prix du gas |
| input | String | Données d'entrée |
| nonce | UInt64 | Nonce de l'émetteur |
| type | UInt64 | Type de transaction |
| max_fee_per_gas | UInt64 | Frais max EIP-1559 |
| max_priority_fee_per_gas | UInt64 | Frais prioritaires EIP-1559 |
| chain_id | UInt64 | ID de chaîne |
| v | String | Signature v |
| r | String | Signature r |
| s | String | Signature s |
| is_system_tx | Bool | Indicateur de transaction système |
| max_fee_per_blob_gas | String | Frais de blob gas |
| blob_versioned_hashes | Array(String) | Hashes de blobs |
| timestamp | DateTime | Timestamp du bloc |
| action | Int8 | Ajouté (1) ou supprimé (-1) |
base.blocks
Métadonnées au niveau du bloc.
| Colonne | Type | Description |
|---|---|---|
| block_number | UInt64 | Numéro de bloc |
| block_hash | String | Hash du bloc |
| parent_hash | String | Hash du bloc parent |
| timestamp | DateTime | Timestamp du bloc |
| miner | String | Producteur du bloc |
| nonce | UInt64 | Nonce du bloc |
| sha3_uncles | String | Hash des uncles |
| transactions_root | String | Racine merkle des transactions |
| state_root | String | Racine merkle d'état |
| receipts_root | String | Racine merkle des reçus |
| logs_bloom | String | Filtre bloom |
| gas_limit | UInt64 | Limite de gas du bloc |
| gas_used | UInt64 | Gas utilisé dans le bloc |
| base_fee_per_gas | UInt64 | Frais de base par gas |
| total_difficulty | String | Difficulté totale de la chaîne |
| size | UInt64 | Taille du bloc en octets |
| extra_data | String | Champ de données supplémentaires |
| mix_hash | String | Mix hash |
| withdrawals_root | String | Racine des retraits |
| parent_beacon_block_root | String | Racine du bloc parent beacon |
| blob_gas_used | UInt64 | Blob gas utilisé |
| excess_blob_gas | UInt64 | Blob gas en excès |
| transaction_count | UInt64 | Nombre de transactions |
| action | Int8 | Ajouté (1) ou supprimé (-1) |
Exemples de requêtes
Obtenir les événements Transfer USDC récents avec paramètres décodés
SELECT
parameters['from'] AS sender,
parameters['to'] AS to,
parameters['value'] AS amount,
address AS token_address
FROM base.events
WHERE
event_signature = 'Transfer(address,address,uint256)'
AND address = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
AND block_timestamp >= now() - INTERVAL 7 DAY
LIMIT 10
Obtenir les transactions d'une adresse spécifique
npx awal@2.8.2 x402 pay https://x402.cdp.coinbase.com/platform/v2/data/query/run -X POST -d '{"sql": "SELECT transaction_hash, to_address, value, gas, timestamp FROM base.transactions WHERE from_address = lower('\''0xYOUR_ADDRESS'\'') AND timestamp >= now() - INTERVAL 1 DAY LIMIT 10"}' --json
Compter les événements par type pour un contrat au cours de la dernière heure
npx awal@2.8.2 x402 pay https://x402.cdp.coinbase.com/platform/v2/data/query/run -X POST -d '{"sql": "SELECT event_signature, count(*) as cnt FROM base.events WHERE address = lower('\''0xCONTRACT_ADDRESS'\'') AND block_timestamp >= now() - INTERVAL 1 HOUR GROUP BY event_signature ORDER BY cnt DESC LIMIT 20"}' --json
Obtenir les informations du bloc le plus récent
npx awal@2.8.2 x402 pay https://x402.cdp.coinbase.com/platform/v2/data/query/run -X POST -d '{"sql": "SELECT block_number, timestamp, transaction_count, gas_used FROM base.blocks ORDER BY block_number DESC LIMIT 1"}' --json
Adresses de contrats courants (Base)
| Token | Adresse |
|---|---|
| USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| WETH | 0x4200000000000000000000000000000000000006 |
Bonnes pratiques
- Toujours filtrer sur des champs indexés (
event_signature,address,block_timestamp) dans les requêtesbase.events. - *Ne jamais utiliser `SELECT `** - spécifier uniquement les colonnes nécessaires.
- Toujours inclure une clause
LIMITpour limiter la taille des résultats. - Utiliser
event_signatureau lieu deevent_namepour le filtrage - elle est indexée et beaucoup plus rapide. - Utiliser des requêtes limitées dans le temps avec
block_timestamppour réduire l'étendue de l'analyse. - Toujours envelopper les valeurs d'adresses dans
lower()- la base de données stocke les adresses en minuscules mais les utilisateurs peuvent fournir des adresses avec checksum (casse mixte). Utiliseraddress = lower('0xAbC...')et nonaddress = '0xAbC...'. - Signatures d'événements courantes :
Transfer(address,address,uint256),Approval(address,address,uint256),Swap(address,uint256,uint256,uint256,uint256,address).
Prérequis
- Doit être authentifié (
npx awal@2.8.2 statuspour vérifier, voir skillauthenticate-wallet) - Le portefeuille doit avoir un solde suffisant en USDC (
npx awal@2.8.2 balancepour vérifier) - Chaque requête coûte $0,10 (100 000 unités atomiques USDC)
Gestion des erreurs
- « Not authenticated » - Exécuter
awal auth login <email>en premier, ou voir skillauthenticate-wallet - « Insufficient balance » - Approvisionner le portefeuille avec USDC ; voir skill
fund - Timeout ou erreur de requête - Vérifier que vous filtrez sur des champs indexés et utilisez un LIMIT