развертывание любого контракта - demonoved/A-trial-run-in-solidity GitHub Wiki
// SPDX-License-Identifier: MIT
// compiler version must be greater than or equal to 0.8.20 and less than 0.9.0
pragma solidity ^0.8.23;
//развернем любой контракт вызвав proxy.deploy
//можно получить байт код контракта вызвав getBytecode
contract Proxy {
event Deploy(address);
receive() external payable {}
function deploy(bytes memory _code) external payable returns (address addr){
assembly {
//cоздаем (v,p,n)
// v = количество ETH для отправки
// p = указатель в памяти на начало кода
// n = размер кода
addr := create(callvalue(), add(_code, 0x20),mload(_code))
}
// обратный адрес 0 при ошибке
require(addr != address(0), "deploy failed"); // сбой развертывания
emit Deploy(addr);
}
function execute(address _target, bytes memory _data) external payable {
(bool success, ) = _target.call{value: msg.value}(_data);
require(success, "failed");
}
}
contract TestContract1 {
address public owner = msg.sender;
function setOwner(address _owner) public {
require(msg.sender == owner, "not owner");
owner = _owner;
}
}
contract TestContract2 {
address public owner = msg.sender;
uint public value = msg.value;
uint public x;
uint public y;
constructor(uint _x, uint _y) payable {
x = _x;
y = _y;
}
}
contract Helper {
function getBytecode1() external pure returns (bytes memory){
bytes memory bytecode = type(TestContract1).creationCode;
return bytecode;
}
function getBytecode2(uint _x, uint _y) external pure returns (bytes memory){
bytes memory bytecode = type(TestContract2).creationCode;
return abi.encodePacked(bytecode, abi.encode(_x, _y));
}
function getCalldata(address _owner) external pure returns (bytes memory){
return abi.encodeWithSignature("setOwner(address)", _owner);
}
}
-
Proxy
Contract:- Объявлен с нужным компилятором (
pragma solidity ^0.8.23
), что означает, что он должен быть скомпилирован с версией Solidity 0.8.23 или выше, но меньше 0.9.0. - Имеет функцию
deploy
, позволяющую развертывать другие контракты. Она использует низкоуровневую функциюcreate
в inline assembly, для создания нового контракта по предоставленному байт-коду и отправляет указанное количество эфиров с транзакцией. - Имеет функцию
execute
, позволяющая выполнять вызовы функций на других контрактах. - Отправляет событие
Deploy
, когда новый контракт успешно развернут.
- Объявлен с нужным компилятором (
-
TestContract1
Contract:- Устанавливает
owner
как отправителя сообщения (адрес, который создал контракт). - Содержит функцию
setOwner
для изменения владельца контракта, с проверкой, что только текущий владелец может это сделать.
- Устанавливает
-
TestContract2
Contract:- Помимо установления
owner
, контракт также имеет значениеvalue
, равное количеству эфиров, отправленных при создании контракта. - У контракта есть две переменные
x
иy
, которые нужно установить при создании контракта. - Контракт имеет конструктор, который принимает
x
иy
в качестве аргументов и должен быть развернут с указанием этих значений.
- Помимо установления
-
Helper
Contract:- Предназначен для вывода байт-кода контрактов
TestContract1
иTestContract2
, чтобы они могли быть развернуты черезProxy
контракт. - Использует функцию
getBytecode1
, чтобы получить байт-кодTestContract1
. - Использует функцию
getBytecode2
, чтобы получить байт-кодTestContract2
и кодирует аргументы конструктора вместе с байт-кодом. - Содержит функцию
getCalldata
, которая кодирует вызов функцииsetOwner
с новым адресом владельца для последующего помещения в функциюexecute
контрактаProxy
.
- Предназначен для вывода байт-кода контрактов
Цель этих контрактов - использовать Proxy
для деплоя других контрактов (TestContract1
и TestContract2
) и последующего взаимодействия с развернутыми контрактами (например, изменения владельца). Это является примером фабрики контрактов и делегирования вызовов в Ethereum smart contracts.