1. Qu'est-ce qu'un contrat intelligent
En termes simples, un contrat intelligent est le code écrit sur la blockchain. Le code contient des règles rigoureuses et complètes. Une fois qu'un utilisateur satisfait aux règles et conditions du contrat, le code à l'intérieur sera déclenché pour exécuter une certaine méthode.
2. Pourquoi rendre les contrats intelligents évolutifs
L'une des caractéristiques des contrats intelligents est qu'ils ne peuvent pas être modifiés après leur déploiement sur la chaîne.Ce mécanisme permet aux parties en interaction du contrat de faire confiance au contrat. Mais cela apporte également une série de problèmes, et si le contrat déployé trouve une vulnérabilité, celle-ci ne peut pas être corrigée. Si un bogue est trouvé, fatal, et doit être corrigé, comment le traiter ? Il s'agit d'utiliser le contrat pour réaliser une optimisation évolutive pour répondre à la demande
3. Le principe du mécanisme du contrat de mise à niveau
- Qu'est-ce qu'un surclassement de contrat
Assurez-vous que les contrats qui ont été déployés sur la chaîne peuvent être optimisés et modifiés, tels que le code de la logique métier et les variables d'état sur la chaîne peuvent être ajoutées, supprimées et modifiées.
2. Le principe du mécanisme de réalisation du contrat de mise à niveau
Les méthodes de mise en œuvre actuelles ont différents modes selon la distinction de stockage, mais elles sont toutes indissociables d'un mécanisme de bas niveau, qui consiste à utiliser la fonctionnalité d'appel délégué pour réaliser le contrat évolutif, de manière à obtenir l'effet d'optimisation et de changement durables. du contrat.
Introduction à l'appel délégué
À l'heure actuelle, il existe trois façons principales d'appeler des contrats
- appel
- déléguéAppel
- statiqueAppel
Point commun : ce sont toutes des méthodes pour appeler et exécuter l'adresse du contrat cible
Différence : L'environnement d'exécution de delegationCall est à l'opposé de call et staticCall.De ce fait, cette fonctionnalité peut être utilisée pour réaliser une évolutivité, et elle n'est pas perçue au niveau de l'utilisateur.
Pour une introduction spécifique à l'appel délégué, voir mon autre article
La différence entre Solidity - appel, appel délégué et code d'appel - Blog de Zeke Luo - Blog CSDN
4. Mettre en place des contrats ERC20 évolutifs
Présentation des codes
- Rédigez le contrat de proxy InitializedProxy, la fonction principale de ce contrat est de transmettre et de stocker des données.
Héritez du contrat StorageSlotUpgradeable d'openzeppelin pour les classes d'utilitaires d'emplacement.
// SPDX-License-Identifier: GPL-3.0
import "@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol";
pragma solidity >=0.7.0 <0.9.0;
contract InitializedProxy {
// address of logic contract
// slot bytes32(uint256(keccak256('EIP1967.PROXY.CONFTI.IMPLEMENTATION')) - 1)
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x5f62ce3c9aebd463c7a36ab1b244d2bb94f07a2c13889b3b687940ebc467b9b3;
// ======== Constructor =========
constructor(
address logic,
bytes memory initializationCalldata
) {
require(logic != address(0),"Proxy :: Wrong proxy contract address");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = logic;
// Delegatecall into the logic contract, supplying initialization calldata
(bool _ok, bytes memory returnData) =
logic.delegatecall(initializationCalldata);
// Revert if delegatecall to implementation reverts
require(_ok, string(returnData));
}
// ======== Fallback =========
fallback() external payable {
address _impl = StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())
let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0)
let size := returndatasize()
returndatacopy(ptr, 0, size)
switch result
case 0 {
revert(ptr, size)
}
default {
return(ptr, size)
}
}
}
// ======== Receive ===
receive() external payable {} // solhint-disable-line no-empty-blocks
function upgradeVersion(address newAddress_) public{
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newAddress_;
}
}
1. Le constructeur constructeur a des données d'initialisation et enregistre le contrat de logique métier pointé
2. Fallback transmet la méthode de réception de tous les contrats de logique métier,
Méthode 3.upgradVersion pour la mise à niveau
Remplacer l'ancienne adresse de contrat logique de l'emplacement spécifié par un nouveau contrat logique
- Implémentez votre propre contrat de logique métier (évolutif erc20)
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
contract logicA is ERC20Upgradeable{
function initialize(string memory tokenName_ ,string memory symbol_) initializer external {
__ERC20_init(tokenName_, symbol_);
}
function mint(address account,uint256 amount) external {
if(account != address(0) && amount > 0){
_mint(account,amount);
}
}
function burn(address account,uint256 amount) external {
if(account != address(0) && amount > 0){
_burn(account,amount);
}
}
}
- déployer le contrat d'usine
Le rôle principal de ce contrat est de créer des contrats logiques évolutifs et de gérer les mises à niveau, etc.
contract testtFactory{
address public logicProxy;
function createProxy(address logiAddress_,string memory tokenName_,string memory symbol_) public {
bytes memory _initializationCalldata = abi.encodeWithSignature(
"initialize(string,string)",
tokenName_,
symbol_
);
logicProxy = address (new InitializedProxy(logiAddress_,_initializationCalldata));
}
function updateLogicProxy(address updataTemplate_) public {
(bool _ok, bytes memory returnData) = logicProxy.call(abi.encodeWithSignature(
"upgradeVersion(address)",
updataTemplate_
));
require(_ok, string(returnData));
}
}
createProxy : génère un contrat de proxy évolutif
updateLogicProxy : met à jour le contrat
- Le déploiement du contrat V2 est le contrat après la mise à niveau
contract logicA2 is ERC20Upgradeable{
function mint(address account,uint256 amount) external {
require (amount <= 10 ,"must be <= 10" );
if(account != address(0) && amount > 0){
_mint(account,amount);
}
}
function burn(address account,uint256 amount) external {
if(account != address(0) && amount > 0){
_burn(account,amount);
}
}
}
Le montant de menthe modifié par ce contrat doit être inférieur ou égal à 10 pour une vérification logique après la mise à niveau.
5. Introduction à la logique d'utilisation du code ci-dessus
Prenez remix comme cas à utiliser :
1. Déployer le contrat de logique métier (le contrat erc20 peut évoluer)
Étape 2. Déployer le contrat d'usine
La troisième étape appelle le contrat d'usine pour créer un contrat erc20Token évolutif
Appelez createProxy pour transmettre l'adresse du contrat erc20 évolutif créé à la première étape
Une fois la création réussie, cliquez sur logicProxy pour afficher l'adresse proxy générée
Appelez ensuite la méthode at et sélectionnez le contrat logique correspondant à appeler (l'utilisation et le principe d'at peuvent être consultés par vous-même).
Étape 4 : Mettre à niveau le contrat erc20 actuel
Ouvrez le contrat d'usine et appelez updateLogicProxy pour transmettre l'adresse du nouveau contrat afin de terminer la mise à niveau.
(Les utilisateurs n'hésitez pas à mettre à niveau)
5. Logique de mise à niveau
⚠️ Notes de mise à niveau
1. Risque de conflit de créneaux horaires
2. Relation d'héritage après la mise à niveau
Résumer
Le risque de mise à niveau du contrat sera relativement important, essayez d'être strict, et la mise à niveau ne devrait qu'augmenter, ne pas diminuer et ne pas se modifier.
Ce qui précède est ce dont je veux parler aujourd'hui. Cet article ne présente que brièvement la mise à niveau et l'utilisation de delegationCall. En ce qui concerne la sécurité, vous devez encore ajouter des restrictions en fonction de votre entreprise. Si vous avez d'autres erreurs, veuillez le signaler, ou DM