-
-
Save yurenju/ef4c901a48c523ac74bf942b50ab5108 to your computer and use it in GitHub Desktop.
pragma solidity 0.8.7; | |
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | |
contract Ship is Initializable { | |
string public name; | |
uint256 public fuel; | |
function initialize(string memory _name, uint256 _fuel) external initializer { | |
name = _name; | |
fuel = _fuel; | |
} | |
function move() public { | |
require(fuel > 0, "no feul"); | |
fuel--; | |
} | |
} |
pragma solidity 0.8.7; | |
import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
contract ShipBeacon is Ownable { | |
UpgradeableBeacon immutable beacon; | |
address public blueprint; | |
constructor(address _initBlueprint) { | |
beacon = new UpgradeableBeacon(_initBlueprint); | |
blueprint = _initBlueprint; | |
transferOwnership(tx.origin); | |
} | |
function update(address _newBlueprint) public onlyOwner { | |
beacon.upgradeTo(_newBlueprint); | |
blueprint = _newBlueprint; | |
} | |
function implementation() public view returns (address){ | |
return beacon.implementation(); | |
} | |
} |
pragma solidity 0.8.7; | |
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; | |
import "./ShipBeacon.sol"; | |
import "./Ship.sol"; | |
contract ShipFactory { | |
mapping(uint32 => address) private ships; | |
ShipBeacon immutable beacon; | |
constructor(address _initBlueprint) { | |
beacon = new ShipBeacon(_initBlueprint); | |
} | |
function buildShip(string memory _name, uint256 _fuel, uint32 shipId) public { | |
BeaconProxy ship = new BeaconProxy( | |
address(beacon), | |
abi.encodeWithSelector(Ship(address(0)).initialize.selector, _name, _fuel) | |
); | |
ships[shipId] = address(ship); | |
} | |
function getShipAddress(uint32 shipId) external view returns (address) { | |
return ships[shipId]; | |
} | |
function getBeacon() public view returns (address) { | |
return address(beacon); | |
} | |
function getImplementation() public view returns (address) { | |
return beacon.implementation(); | |
} | |
} |
pragma solidity 0.8.7; | |
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | |
contract ShipV2 is Initializable { | |
string public name; | |
uint256 public fuel; | |
function initialize(string memory _name, uint256 _fuel) external initializer { | |
name = _name; | |
fuel = _fuel; | |
} | |
function move() public { | |
require(fuel > 0, "no feul"); | |
fuel--; | |
} | |
function refuel() public { | |
fuel++; | |
} | |
} |
yurenju
commented
Jan 6, 2022
Hey @yurenju, your solution looks very clean, but I have a question: If I wanted to call a ship method in buildShip after the deployment, what should I write? ship.move() is not working.
@allurco I push all source code with hardhat configuration to BeaconShip repository and modify buildShip()
with move()
for your reference.
@yurenju thank you, so its the proxy that needs to be invoked. Very clear now.
👍
Thnks! Awesome explanation!
I am deploying almost the same contract in Hardhat, and keep getting the same Error: VM Exception while processing transaction: reverted with reason string 'Address: low-level delegate call failed'
I have change the create func in Solidity tons of time and deployment code, and still have no clue how can i fix this
@chubidursel few things you can try:
- clone BeaconShip can deploy to see if any error, if not you can modify from the source code
- use tenderly to execute your function to trace the stack
@yurenju Thanks for the advice
Im deploying via hardhat. Maybe my deployment code is broken. I just copied your code and trynna deploy it in lockhost, but it gets err in last function where we create new ship contract. Deployment code below:
async function main() {
const Contract = await ethers.getContractFactory("Ship");
const beacon = await upgrades.deployBeacon(Contract);
await beacon.deployed();
console.log("beacon deployed: ", beacon.address);
const Factory = await ethers.getContractFactory("ShipFactory");
const factory = await Factory.deploy(beacon.address);
console.log("Factory deployed: ", factory.address);
await factory.buildShip("Bob", 10, 1) // ERR > 'Address: low-level delegate call failed'
}
@chubidursel I have no idea about the error. you also can use a separated terminal and execute hardhat console
, and execute your deployment code again to see if the terminal running hardhat console
print more error details.
@chubidursel your error occurs because you are deploying the beacon twice and initializing the beacon deployed in the ShipFactory constructor with your own beacon. With the example code there is no need to deploy the beacon before deploying ShipFactory (because it is done in the constructor), instead, just deploy the Ship and pass that as an argument to the ShipFactory and the error should go away :)