En 2023, une startup Web3 a lancé une levée de fonds via un contrat intelligent généré par IA. En seulement trois heures, une faille critique est apparue : le contrat continuait d'cacepter des fonds après avoir atteint son plafond, entraînant un surplus non géré de 120 ETH. L'audit post-mortem a révélé que le prompt initial était trop évasif : "Génère un contrat Solidity de crowdfunding où les utilisateurs déposent des fonds et le fondateur retire le total à la fin."
L'IA avait omis la logique de clôture. Ce cas démontre une réalité brutale : la sécurité d'un smart contract dépend directement de la précision du prompt. En tant qu'architecte de prompts, l'objectif n'est pas simplement de coder, mais de définir des contraintes métier strictes et des protocoles de sécurité par le langage.
1. Définir des conditions aux limites strictes
L'une des erreurs les plus fréquentes est de laisser l'IA deviner les limites opérationnelles. Pour un contrat de mint NFT, une instruction vague produira un code sans restriction de quantité.
Prompt optimisé : "Écris un contrat ERC721 en Solidity avec les contraintes suivantes : 1. Limite de 3 tokens par adresse. 2. Prix fixe de 0.05 ETH par mint. 3. Déclenche un revert explicite si l'utilisateur dépasse son quota."
// Structure de contrôle des limites
mapping(address => uint256) private _tokensParUtilisateur;
uint256 public constant LIMITE_INDIVIDUELLE = 3;
function mint() public payable {
require(msg.value == 0.05 ether, "Prix incorrect");
require(_tokensParUtilisateur[msg.sender] < LIMITE_INDIVIDUELLE, "Quota atteint");
_tokensParUtilisateur[msg.sender] += 1;
_safeMint(msg.sender, totalSupply() + 1);
}
2. Simuler des scénarios critiques (Edge Cases)
Les contrats de prêt ou de DeFi échouent souvent à cause d'une mauvaise gestion de la volatilité. Un prompt doit forcer l'IA à intégrer des sources de données externes fiables comme les oracles.
Prompt optimisé : "Conçois un module de liquidation pour un protocole de prêt. Calcule le ratio de collatéral en temps réel en utilisant l'oracle Chainlink pour le prix ETH/USD. Assure-toi que la liquidation ne peut être déclenchée que si le ratio tombe sous les 140%."
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
function verifierSolvabilite(address emprunteur) public view returns (uint256) {
(, int256 prixActuel, , , ) = priceFeed.latestRoundData();
uint256 valeurCollateral = (garantie[emprunteur] * uint256(prixActuel)) / 1e8;
uint256 detteActive = dette[emprunteur];
// Retourne le ratio en pourcentage
return (valeurCollateral * 100) / detteActive;
}
3. Validation croisée par itération logique
Ne validez jamais le premier code généré. Utilisez une appproche multi-étapes pour identifier les failles de réentrance, un classique des hacks DeFi.
- Étape 1 : Génération de la fonction de retrait initiale.
- Étape 2 : Demandez à l'IA : "Analyse cette fonction de retrait. Est-elle vulnérable à une attaque de réentrance ? Si oui, applique le pattern Checks-Effects-Interactions."
// Avant : Vulnérable
function retirer() public {
uint256 montant = soldes[msg.sender];
(bool succes, ) = msg.sender.call{value: montant}("");
require(succes);
soldes[msg.sender] = 0;
}
// Après : Sécurisé (Pattern CEI)
function retirerSecurise() public {
uint256 montant = soldes[msg.sender];
require(montant > 0, "Solde nul");
soldes[msg.sender] = 0; // Mise à jour de l'état d'abord
(bool succes, ) = msg.sender.call{value: montant}("");
require(succes, "Echec transfert");
}
4. Imposer des standards de l'industrie
Réinventer la roue en cryptographie est dangereux. Votre prompt doit exiger l'utilisation de bibliothèques auditées comme OpenZeppelin.
Prompt optimisé : "Génère un token ERC20 nommé 'SecureAsset'. Utilise exclusivement les implémentations d'OpenZeppelin. Intègre 'SafeERC20' pour les transferts et utilise 'Ownable' pour restreindre les fonctions de minting à l'administrateur uniquement."
5. Adoption d'une perspective adverse
Pour anticiper les vecteurs d'attaque, demandez à l'IA de jouer le rôle d'un hacker. Cela permet de découvrir des vulnérabilités logiques comme l'attaque Sybil (multiplication d'identités).
Prompt de simulation : "Agis comme un auditeur de sécurité. Comment pourrais-tu contourner la limite de vote d'un vote par personne dans ce contrat ? Propose ensuite une solution basée sur le staking de tokens pour augmenter le coût d'une telle attaque."
// Solution contre l'attaque Sybil
mapping(address => uint256) public cautionDeposee;
uint256 public constant SEUIL_VOTE = 50 * 10**18; // Nécessite 50 tokens
function voter(uint256 propositionId) public {
require(cautionDeposee[msg.sender] >= SEUIL_VOTE, "Dépôt insuffisant");
require(!aDejaVote[msg.sender], "Vote unique");
aDejaVote[msg.sender] = true;
// Logique de vote...
}
Synthèse du flux de travail
La création d'un smart contract par IA doit suivre un cycle rigoureux :
- Spécification : Définition des bornes (Prompt de contraintes).
- Contextualisation : Intégration de l'environnement (Oracles, Standards).
- Audit IA : Analyse des vulnérabilités par l'IA elle-même (Prompt adverse).
- Refactorisation : Application des patterns de sécurité (CEI, SafeMath).