# Solidity 0.8.30 — Nouveautés et Pourquoi Ça Compte
Solidity 0.8.30 est sorti le 2 avril 2026. Pas de révolution, mais des améliorations importantes au niveau du transient storage, optimisations de gas, et meilleurs messages d'erreur.
Voici ce qui change et pourquoi vous devriez upgrader.
1. Transient Storage Amélioré
Le transient storage (EIP-1153, ajouté en 0.8.24) est maintenant plus facile à utiliser.
Avant (0.8.24-0.8.29)
// Syntaxe lourde
assembly {
tstore(slot, value)
let val := tload(slot)
}
Après (0.8.30)
// Nouvelle syntaxe native
transient uint256 counter; // ← Keyword transient
function increment() external {
counter++; // Stocké dans transient storage
// Réinitialisé automatiquement à la fin de la tx
}
Pourquoi c'est important : le transient storage est ~5× moins cher que le storage classique pour des données temporaires (reentrancy guards, compteurs de boucle, etc.).
// Exemple : reentrancy guard optimisé
contract ReentrancyGuard {
// Avant : SSTORE (20,000 gas) + SLOAD (2,100 gas)
// Après : TSTORE (~100 gas) + TLOAD (~100 gas)
transient bool locked;
modifier nonReentrant() {
require(!locked, "Reentrant call");
locked = true;
_;
locked = false;
}
}
Trade-off : les données transient disparaissent à la fin de la transaction (ne persistent pas entre les blocs).
2. Destructuring de Returns Nommés
Vous pouvez maintenant destructurer les returns de fonctions directement.
// Fonction avec named returns
function getPosition(address user) external view returns (
uint256 amount,
uint256 shares,
uint256 debt
) {
// ...
}
// Avant : fallait tout récupérer
(uint256 amount, uint256 shares, uint256 debt) = getPosition(msg.sender);
// Après : destructuring partiel
(uint256 amount,, uint256 debt) = getPosition(msg.sender); // Skip shares
Pourquoi c'est utile : évite de déclarer des variables inutiles.
// Avant (0.8.29)
function harvest() external {
(uint256 rewards, uint256 _unused1, uint256 _unused2) = strategy.claim();
// _unused1 et _unused2 polluent le code
}
// Après (0.8.30)
function harvest() external {
(uint256 rewards,,) = strategy.claim();
// Plus propre
}
3. User-Defined Operators (Expérimental)
Nouvelle feature expérimentale : définir vos propres opérateurs.
// Définir un type custom avec opérateurs
type FixedPoint is int256;
using {add as +, sub as -, mul as *, div as /} for FixedPoint global;
function add(FixedPoint a, FixedPoint b) pure returns (FixedPoint) {
return FixedPoint.wrap(FixedPoint.unwrap(a) + FixedPoint.unwrap(b));
}
function mul(FixedPoint a, FixedPoint b) pure returns (FixedPoint) {
return FixedPoint.wrap(FixedPoint.unwrap(a) * FixedPoint.unwrap(b) / 1e18);
}
// Usage
FixedPoint x = FixedPoint.wrap(5e18);
FixedPoint y = FixedPoint.wrap(3e18);
FixedPoint z = x * y + FixedPoint.wrap(1e18); // Opérateurs custom
Attention : feature expérimentale (peut changer dans les prochaines versions). Ne pas utiliser en production.
4. Meilleurs Messages d'Erreur
Le compilateur donne maintenant des erreurs plus claires.
Exemple 1 : Type Mismatch
// Avant (0.8.29)
uint256 x = "hello";
// Error: Type string memory is not implicitly convertible to uint256
// Après (0.8.30)
uint256 x = "hello";
// Error: Cannot convert string literal to uint256.
// Did you mean to use bytes32 or an address?
Exemple 2 : Missing Return
function getBalance(address user) external view returns (uint256) {
if (user == address(0)) {
revert("Invalid user");
}
// ❌ Oubli de return
}
// Avant (0.8.29)
// Error: Function missing return statement
// Après (0.8.30)
// Error: Function "getBalance" must return a value of type uint256.
// Missing return statement after if-block at line 5.
Pourquoi c'est utile : gain de temps pour les débutants (et les vieux aussi 😅).
5. Gas Optimizations
Plusieurs optimisations de gas internes :
a) Meilleur Inline de Fonctions Internes
// Fonction interne appelée une seule fois
function _helper(uint256 x) internal pure returns (uint256) {
return x * 2 + 1;
}
function compute(uint256 x) external pure returns (uint256) {
return _helper(x);
}
// 0.8.29 : ~24,500 gas
// 0.8.30 : ~23,800 gas (-3%)
// Le compilateur inline _helper directement
b) Optimisation des Boucles
function sum(uint256[] memory values) external pure returns (uint256) {
uint256 total;
for (uint256 i = 0; i < values.length; i++) {
total += values[i];
}
return total;
}
// 0.8.29 : ~2,500 gas/iteration
// 0.8.30 : ~2,300 gas/iteration (-8%)
// Meilleure gestion de la mémoire
Gain moyen : ~2-5% sur la plupart des contrats.
6. Support du Nouvel IR (Yul-based)
Le nouveau IR optimizer (basé sur Yul) est maintenant stable et recommandé.
// foundry.toml
[profile.default]
via_ir = true // Active le nouvel optimizer
Avantages :
- Optimisations plus agressives (~5-15% gas savings)
- Meilleure gestion des structs/arrays
- Plus de contrôle sur le bytecode généré
Inconvénient : compilation plus lente (~2-3× plus long).
Avant/après sur un contrat ERC20 typique :
Sans via_ir (legacy optimizer) :
- Deployment : ~450,000 gas
- Transfer : ~51,000 gas
- Compile time : 2s
Avec via_ir (Yul optimizer) :
- Deployment : ~420,000 gas (-7%)
- Transfer : ~48,000 gas (-6%)
- Compile time : 5s (+150%)
Verdict : activez ``via_ir` pour la production (gains de gas), gardez le legacy pour le dev (compilation rapide).
Breaking Changes
Quelques breaking changes mineurs :
1. `blockhash()` Plus Strict
// Avant (0.8.29) : acceptait n'importe quel uint256
bytes32 h = blockhash(999999999); // Retourne 0x0 (silencieux)
// Après (0.8.30) : warning si out-of-bounds
bytes32 h = blockhash(999999999);
// Warning: blockhash() only works for the 256 most recent blocks
2. `selfdestruct` Deprecated (Encore)
// 0.8.30 : warning plus agressif
selfdestruct(payable(owner));
// Warning: selfdestruct is deprecated and will be removed in a future version.
// Use withdrawAll() pattern instead.
Préparez-vous : `selfdestruct`` sera retiré dans Solidity 0.9.0 (prévu fin 2026).
Quand Upgrader ?
Maintenant si :
- Vous utilisez transient storage (gains de lisibilité)
- Vous cherchez 2-5% de gas savings (via_ir)
- Vous voulez de meilleurs messages d'erreur
Attendre si :
- Projet en production (tester d'abord)
- Dépendances pas encore compatibles (OpenZeppelin, etc.)
- CI/CD pas prêt (via_ir ralentit les builds)
Migration
# 1. Update Solidity
# foundry.toml
[profile.default]
solc_version = "0.8.30"
via_ir = true # Optionnel mais recommandé
# 2. Update pragma
// Avant
pragma solidity ^0.8.24;
// Après
pragma solidity ^0.8.30;
# 3. Run tests
forge test
# 4. Check gas diff
forge snapshot --diff
Si vous utilisez Hardhat :
// hardhat.config.js
module.exports = {
solidity: {
version: "0.8.30",
settings: {
viaIR: true, // Nouvel optimizer
optimizer: {
enabled: true,
runs: 200
}
}
}
}
Conclusion
Solidity 0.8.30 apporte des améliorations quality-of-life importantes :
- ✅ Transient storage plus facile
- ✅ Destructuring de returns
- ✅ Meilleurs messages d'erreur
- ✅ ~2-5% gas savings (via_ir)
- ⚠️ via_ir ralentit la compilation
Pas de raison de ne pas upgrader (sauf dépendances). Les gains sont réels.
Prochaine version (0.8.31) prévue pour juillet 2026 avec support des user-defined value types stables.
Upgrade time. 🚀