I have (1) a protocol and (2) a dapp, with the latter being a wrapper around the former. I want the protocol to be non-upgradeable, while the dapp to remain upgradeable.
They are separated as individual packages in a monorepo. In the protocol package, I'm using openzeppelin-solidity
, while for the dapp I'm using openzeppelin-eth
and zos-lib
.
There doesn't seem to be any obvious issue with the aforementioned set-up, but I'm wondering if I can use zos
in the following way?
zos create Dapp --non-upgradeable
If I could, that'd really helpful. I'd have ubiquitous scripts across the monorepo - for instance, running zos compile
in both the protocol and the package instead of truffle compile --all
in one of them.
2 Likes
Hi @PaulRBerg
There is an open issue to support creating non-upgradeable contracts: https://github.com/zeppelinos/zos/issues/802
The 2.4.0 release added experimental support for EIP1167 minimal proxies adding the --minimal
flag to zos create
https://github.com/zeppelinos/zos/releases/tag/v2.4.0
EIP1167 minimal proxies
We have added experimental support for EIP1167 minimal proxies. These proxies rely on the same delegatecall pattern as the usual ZeppelinOS proxies, but have two main differences:
- They cannot be upgraded to a different version of the code
- They are incredibly cheap to deploy: about 1/10th of the standard proxy!
These features make minimal proxies an ideal choice when you want to spawn many copies of the same contract, without worrying about maintaining them in the future. They also play nicely with EVM packages: since the package developer pays the deployment cost of the logic contracts, you only need to pay for the minimal proxies.
You can try deploying one of these proxies by adding the --minimal
flag when running zos create
. Remember that these proxies will not be upgradeable to a different version of the code: the reduced deployment gas fee comes at a cost!
2 Likes
Hi @PaulRBerg
Following up, do minimal proxies meet your needs?
Would appreciate your perspective for your use case.
I just finished reading the EIP-1167 spec on GitHub and it looks good enough for my needs. However, I want to make sure that I got this right:
small operational overhead - adds a single call cost to each call
Will users have to pay 42,000 instead of the base 21,000 gas cost?
1 Like
Hi @PaulRBerg
I deployed a simple Counter contract to test out the overhead of calling a minimal proxy and an upgradeable proxy. The overhead appears relatively small for my example (775 gas for a minimal proxy).
My results are in the same ballpark as what @ylv-io found using a previous version of ZeppelinOS. Gas overhead for proxied function call
You may want to test on one of your contracts.
Vanilla contract (deployed via Truffle)
https://ropsten.etherscan.io/address/0x5cab3e4448e7a8bfd1f74a93cc0a0201a35bd41d
First: 41,653; Subsequent: 26,653
Upgradeable Proxy (deployed via OpenZeppelin SDK)
https://ropsten.etherscan.io/address/0x7e5c2893ba6be6cefa42538738a99bac740eb628
First: 43,239; Subsequent: 28,239
Minimal Proxy (deployed via OpenZeppelin SDK)
https://ropsten.etherscan.io/address/0xbdcd373c6dd40ec92efcac8b1a2e09c3cb0f2feb
First: 42,428; Subsequent: 27,428
Counter.sol (simple contract example)
pragma solidity ^0.5.0;
contract Counter {
uint256 public value;
function increase() public {
value++;
}
}
1 Like
Awesome analysis, @abcoathup! Thanks for looking into it and sharing your numbers! The 775 overhead makes sense, since the base cost for a CALL opcode is 700 gas (see Gcall in Appendix G of the yellow paper).
Nope. The 21000 base cost is that of sending a new transaction to the network. The overhead imposed by the proxy is an extra CALL opcode, which is in the ballpark of 700 gas, as Andy pointed out.
2 Likes
Thanks @abcoathup and @spalladino, greatly appreciate your analysis.
1 Like