I'm trying to deploy new instances of my logic using a factory, but i'm not so sure how to do that. My assumption is that the package creates and deploys a beacon proxy for you, but how does one use that to create a new instance of the logic in a factory.
Code to reproduce
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.6;
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import "./BoxBeacon.sol";
import "./BoxV1.sol";
contract BoxFactory {
mapping(uint32 => address) private boxes;
BeaconProxy public immutable beacon;
constructor(address _beacon, bytes memory data) {
beacon = new BeaconProxy(_beacon, data);
}
function buildBox(
uint256 _age,
string memory _name,
uint32 _boxId
) public {
BeaconProxy box = new BeaconProxy(
address(beacon),
abi.encodeWithSelector(
BoxV1(address(0)).initialize.selector,
_age,
_name
)
);
boxes[_boxId] = address(box);
}
function getBeacon() public view returns (address) {
return address(beacon);
}
function getBoxByIndex(uint32 index) public view returns (address) {
return boxes[index];
}
}
The deployBeacon function deploys up to 2 contracts: an implementation (if it has not already been deployed) and a beacon.
The deployBeaconProxy function does not deploy the implementation or beacon. It only deploys 1 contract: a beacon proxy which points to an existing beacon.
If you are trying to deploy new beacon proxies using a factory, then you would be using your factory instead of deployBeaconProxy. In your example, your immutable beacon variable should not be a BeaconProxy, but it should be an UpgradeableBeacon (which can be the beacon address that was deployed by deployBeacon).
See this post for another example of a beacon proxy factory.
Thank you so much @ericglau, this helps a lot. I have another question though, so I watched your talk at the community meeting where you mentioned that we can create as many proxies as needed using deployBeaconProxy. I tested it out and i can see multiple instances are created which also achieves my aim. Is this the right way to do it or would it be better creating a factory like in the example. Also if this is the right way, do I still need to take care of things like transferring ownership or is that handled already if use my address as the deployer when deploying with the hardhat plugin. Apologies if my questions are too Noob, still getting used to the pattern.
The factory would provide an on-chain way of creating new instances, whereas deployBeaconProxy would need to be called through a script. It depends on your use case or how you want to deploy the new beacon proxies.
Thanks a lot @ericglau .. For anybody interested in how i went about this eventually. I used an hybrid solution.. I deployed a beacon and implementation using deployBeacon, but i wanted an on-chain solution for the factory. So my factory ended up looking like this
in your factory contract is unnecessary, correct? Since "upgrades.deployBeacon" creates an UpgradeableBeacon for us? I was able to deploy everything fine without that import in my factory contract, but want to double check that it's not indeed necessary for some reason @ericglau ?
I tried the same solution for my use case. But I am stuck in ownership of the proxy. In the case of the script, the owner is the sender, but in the case of the factory, the owner of the new proxy is the contract. I am still finding a way to transfer the ownership, the transferOwnership of BeaconProxy is not accessible to my factory.
@gawshinde There are two different contexts for ownership: the owner of your contract is set in the BeaconProxy, but the owner of the beacon (who has permission to upgrade the beacon) is set in UpgradeableBeacon.
Just posting this here for anybody that needs a solution in future. Here is a version of my implementation, still needs some update, but it contains testing and all of the basic things you will need to get started. I will update the README and put things in a better shape once I can find the time. Since its open source contributions are also welcome
Note do your own security checks and maybe add more tests as you see fit.
My use case is to create contracts for my daap users. When I am using a factory, the creator is the factory, not the sender. As my contract is Role-based, I am finding a way to make my user an owner, as the open sea will either take creator or ownable as owner. Hope I am able to explain.
One way is to call the upgrade plugin directly from my web3 app and have user sign it. I do not know if it is possible.
I am passing owner and fixed opensea issue by just providing a public function to get owner as it is not available in non-ownable contracts. But what I really want to do is this,
when I create a beacon proxy with script and plugin, the creator of the contract in the network is the address which runs the script.
But when I do it using a proxy factory (though I am able to solve the ownership issue), The creator address in the transaction would be the address of the factory and not the address of the caller.
Is there a way I can call the script using web3 and have my user sign the trasection?
@gawshinde Did you transfer ownership in the initialize function of the specific contract instance that was created and passed your desired owner to it ?
Yes. But transferring ownership does not change the creator of the contract. I do not want to only transfer ownership, but want to make sure that the creator address is also user's and not factory's (check etherscan for creator address). While using script it works that way but in beacon proxy factory it does not.
Agreed. However, I wanted to understand from this forum how the script can achieve this? As I looked into the code, it is also using a factory. I will dig in more to understand how it works.
Im keep getting same Err over and over again.
VM Exception while processing transaction: reverted with reason string 'Address: low-level delegate call failed'
I change deploy file and Factory.sol many time but its unsuccess.
Does anyone know what it could possibly be?