>_ DevTrendsfr

Langue

Accueil

Langages

Sections

Frontend Backend Mobile DevOps AI / ML GameDev Blockchain Embarqué Sécurité
Rust

Comment écrire des smart contracts pour Solana sans devenir fou à cause du boilerplate

Si vous avez déjà essayé d'écrire des programmes pour Solana en Rust pur, vous vous souvenez probablement de cette sensation où cinq lignes de logique métier nécessitaient l'écriture de cinquante lignes de vérifications de validation de comptes, une désérialisation manuelle via Borsh et une validation de signature. Si vous vous trompiez dans l'ordre des clés dans la transaction — vous obtenez une erreur runtime qui prend parfois des heures à déboguer.

Dans le monde Ethereum, les développeurs sont depuis longtemps habitués à Solidity et aux wrappers prêts à l'emploi comme Hardhat ou Foundry. Sur Solana, le standard analogue est devenu Anchor — un framework qui gère tout le travail répétitif d'analyse de données, de vérifications de contrôle d'accès et de génération de code client.

Ce qu'Anchor gère pour vous

Fondamentalement, Anchor est un DSL (langage spécifique à un domaine) au-dessus de Rust. Il ne modifie pas le modèle d'exécution BPF interne de Solana, mais encapsule les appels de bas niveau dans des macros déclaratives compréhensibles.

Lorsque vous écrivez un programme avec Anchor, le framework résout quatre tâches principales :

  1. Sérialisation et désérialisation des données de comptes sans appels de méthodes de déballage manuels.
  2. Validation des contraintes de comptes directement dans la signature de la structure via des attributs (vérification du propriétaire, vérification de signature, initialisation de la mémoire).
  3. Assemblage de la spécification IDL (Interface Description Language) — l'équivalent de l'ABI d'Ethereum.
  4. Création de clients TypeScript et Rust prêts à l'emploi pour interagir avec le contrat directement depuis le frontend ou les tests.

À quoi ressemble le code en pratique

Regardons un exemple classique de compteur. Dans le SDK Solana pur, vous devriez analyser manuellement le tableau d'octets InstructionData, extraire les tranches de comptes, vérifier is_signer sur l'adresse de l'appelant et valider l'adresse du programme système.

Voici à quoi ressemble le même contrat dans Anchor :

use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
mod counter {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, start: u64) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.authority = *ctx.accounts.authority.key;
        counter.count = start;
        Ok(())
    }

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.count += 1;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = authority, space = 48)]
    pub counter: Account<'info, Counter>,
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut, has_one = authority)]
    pub counter: Account<'info, Counter>,
    pub authority: Signer<'info>,
}

#[account]
pub struct Counter {
    pub authority: Pubkey,
    pub count: u64,
}

La différence est immédiatement visible. Toute la logique de validation est déplacée vers les structures Initialize et Increment.

L'attribut #[account(init, payer = authority, space = 48)] indique au runtime : crée un nouveau compte, alloue 48 octets pour lui et facture le loyer au portefeuille authority.

Le construct #[account(mut, has_one = authority)] vérifie automatiquement que le champ authority à l'intérieur de la structure Counter correspond au compte passé authority, et que ce compte a réellement signé la transaction. S'il n'y a pas de signature ou qu'un autre portefeuille a été passé, l'exécution s'interrompra avant d'entrer dans le corps de la fonction increment.

IDL et Frontend sans douleur

La chose la plus pratique dans le bundle Anchor est le fichier IDL au format JSON. Le compilateur l'assemble automatiquement lors de la construction du projet.

L'IDL décrit toutes les instructions, les structures de données et les types d'erreurs personnalisés possibles du programme. Basé sur ce fichier, la bibliothèque @anchor-lang/core génère une interface typée pour JavaScript ou TypeScript.

Vous n'avez plus besoin de vous souvenir des décalages d'octets lors de l'assemblage d'une transaction côté client. Appeler une méthode depuis le frontend devient un appel de fonction classique :

await program.methods
  .increment()
  .accounts({
    counter: counterPubkey,
    authority: wallet.publicKey,
  })
  .rpc();

TypeScript mettra en évidence les erreurs si vous oubliez de passer un compte requis ou si vous spécifiez le mauvais type d'argument.

Fuzzing intégré pour trouver les vulnérabilités

Dans les smart contracts, le coût d'une erreur est trop élevé, c'est pourquoi les tests jouent un rôle particulier. La CLI inclut une intégration avec l'outil Crucible pour les tests de fuzzing guidés par la couverture.

La commande anchor fuzz init génère un harness de test, et anchor fuzz run l'exécute avec des données d'entrée aléatoires, en essayant de trouver des cas limites qui mènent à des panics ou des états de comptes invalides. Cela aide à détecter les débordements non évidents ou les vérifications manquées avant de déployer sur un testnet.

# Инициализация фазз-тестов
anchor fuzz init program_name

# Запуск тестов в release-сборке
anchor fuzz run program_name test_name --release

Installation et démarrage

Pour gérer les versions du toolchain, les développeurs ont créé un utilitaire spécial appelé AVM (Anchor Version Manager). Cela vous évite les conflits de versions entre le compilateur Solana et le framework lui-même, lorsque différents projets nécessitent différentes sous-versions.

L'utilitaire s'installe avec une seule ligne :

curl -sSfL https://raw.githubusercontent.com/otter-sec/anchor/master/avm/install | sh

Après l'installation, vous pouvez basculer vers les builds nightly ou épingler des releases spécifiques pour vos workspaces :

avm nightly
avm nightly --disable

Qui bénéficiera d'Anchor

Si vous commencez tout juste avec le développement Solana, commencer sans Anchor est pratiquement inutile. Vous passerez des semaines à réinventer la roue pour l'analyse de comptes et la validation des discriminators.

Le framework couvre les besoins principaux :

  • Il donne aux développeurs backend Rust un typage strict et une protection contre les schémas courants de vulnérabilités de validation.
  • Il donne aux développeurs frontend des types TypeScript prêts à l'emploi et des méthodes pratiques pour envoyer des transactions.

Le seul cas où Anchor pourrait sembler excessif est l'écriture de micro-programmes avec une optimisation extrême de la taille binaire (limite du budget de calcul), où littéralement chaque octet d'instructions compte. Dans tous les autres scénarios, c'est le standard de facto qui fait gagner des centaines d'heures de travail.

Projets similaires