Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
:warning: Under heavy development: do not use in production :warning:
zos-lib
is a library for writing upgradeable smart contracts on Ethereum. It can be used to create an upgradeable on-chain distributed application.
Use this library if you want to programmatically develop, deploy or operate an upgradeable smart contract system.
If you want a CLI-aided development experience, see the zOS CLI.
To install zos-lib
simply go to your project's root directory and run:
npm i zos-lib
Next, learn how to:
Note: This shows a low-level manual method of developing a single upgradeable smart contract. You probably want to use the higher-level CLI guide.
To work with a single upgradeable smart contract, we just need to deal with a simple upgradeability proxy. This is a special contract that will hold the storage of our upgradeable contract and redirect function calls to an implementation
contract, which we can change (thus making it upgradeable). Let's do the following example to see how it works:
MyContract.sol
. Most contracts require some sort of initialization, but upgradeable contracts can't use constructors because the proxy won't know about those values. So we need to use the Initializable
pattern provided by zos-lib
:import "zos-lib/contracts/migrations/Initializable.sol";
contract MyContract is Initializable {
uint256 public x;
function initialize(uint256 _x) isInitializer public {
x = _x;
}
}
const myContract_v0 = await MyContract.new();
const proxy = await AdminUpgradeabilityProxy.new(myContract_v0.address);
MyContract
interface, because all calls will be delegated from the proxy to the contract with the implementation.let myContract = await MyContract.at(proxy.address);
const x0 = 42;
await myContract.initialize(x0);
console.log(await myContract.x()); // 42
MyContract.sol
to add a function called y
:import "zos-lib/contracts/migrations/Initializable.sol";
contract MyContract is Initializable {
uint256 public x;
function initialize(uint256 _x) isInitializer public {
x = _x;
}
function y() public pure returns (uint256) {
return 1337;
}
}
Note that when we update our contract's code, we can't change its pre-existing storage structure. This means we can't remove any previously existing contract variable. We can, however, remove functions we don't want to use anymore (in the code shown, all functions were preserved).
const myContract_v1 = await MyContract.new();
await proxy.upgradeTo(myContract_v1.address);
myContract = await MyContract.at(proxy.address);
console.log(await myContract.x()); // 42
console.log(await myContract.y()); // 1337
Wohoo! We've upgraded our contract's behavior while preserving it's storage.
For a fully working project with this example, see the examples/single
folder.
To learn more about how proxies work under the hood, read this post on our blog.
Note: This shows a low-level manual method of developing a complex upgradeable smart contract application. You probably want to use the higher-level CLI guide instead, but feel free to continue reading if you want to understand the core contracts of zos-lib
.
Most real-world applications require more than a single smart contract. Here's how to build a complex upgradeable app with multiple smart contracts and connect it to the zOS standard libraries:
pragma solidity ^0.4.21;
import "openzeppelin-zos/contracts/ownership/Ownable.sol";
import "openzeppelin-zos/contracts/math/SafeMath.sol";
contract DonationsV1 is Ownable {
using SafeMath for uint256;
// Keeps a mapping of total donor balances.
mapping(address => uint256) public donorBalances;
function donate() payable public {
require(msg.value > 0);
// Update user donation balance.
donorBalances[msg.sender] = donorBalances[msg.sender].add(msg.value);
}
function getDonationBalance(address _donor) public view returns (uint256) {
return donorBalances[_donor];
}
function withdraw(address _wallet) onlyOwner {
// Withdraw all donated funds.
_wallet.transfer(this.balance);
}
}
zos-lib
to deploy this contract with upgradeability capabilities. Given this will probably be a complex application and we'll want to use the zOS standard libraries, we'll use the App
contract. This contract will live in the blockchain and manage the different versions of our smart contract code and upgradeability proxies. It's the single entry point to manage our application's contract's upgradeability and instances. Let's create and configure it: // On-chain, single entry point of the entire application.
log.info("<< Setting up App >>")
const initialVersion = '0.0.1'
return await AppDeployer.call(initialVersion)
DonationsV1
in the App
and request it to create a new upgradeable proxy for it. Let's do it: // Register the first implementation of 'Donations', and request a proxy for it.
log.info('<< Deploying version 1 >>')
const DonationsV1 = Contracts.getFromLocal('DonationsV1')
await app.setImplementation(DonationsV1, contractName);
return await app.createProxy(DonationsV1, contractName, 'initialize', [owner])
pragma solidity ^0.4.21;
import "./DonationsV1.sol";
import "openzeppelin-zos/contracts/token/ERC721/MintableERC721Token.sol";
contract DonationsV2 is DonationsV1 {
using SafeMath for uint256;
// ERC721 non-fungible tokens to be emitted on donations.
MintableERC721Token public token;
uint256 public numEmittedTokens;
function setToken(MintableERC721Token _token) external {
require(_token != address(0));
require(token == address(0));
token = _token;
}
function donate() payable public {
super.donate();
// Emit a token.
token.mint(msg.sender, numEmittedTokens);
numEmittedTokens = numEmittedTokens.add(1);
}
}
App
, register a new AppDirectory
containing the new version of our contract implementation, and then set the standard library version of ERC721 to our upgradeable contract. Let's see how: // Create a new version of the app, liked to the ZeppelinOS standard library.
// Register a new implementation for 'Donations' and upgrade it's proxy to use the new implementation.
log.info('<< Deploying version 2 >>')
const secondVersion = '0.0.2'
await app.newVersion(secondVersion, await getStdLib(txParams))
const DonationsV2 = Contracts.getFromLocal('DonationsV2')
await app.setImplementation(DonationsV2, contractName);
await app.upgradeProxy(donations.address, null, contractName)
donations = DonationsV2.at(donations.address)
// Add an ERC721 token implementation to the project, request a proxy for it,
// and set the token on 'Donations'.
log.info(`Creating ERC721 token proxy to use in ${contractName}...`)
const token = await app.createProxy(
MintableERC721Token,
tokenClass,
'initialize',
[donations.address, tokenName, tokenSymbol]
)
log.info(`Token proxy created at ${token.address}`)
log.info('Setting application\'s token...')
await donations.setToken(token.address, txParams)
log.info('Token set succesfully')
return token;
That's it! We now have the same contract, retaining the original balance, and storage, but with an upgraded code. The upgradeable contract is also linked to an on-chain upgradeable standard library containing an implementation of a mintable ERC721 token. State of the art!
FAQs
JavaScript library for the ZeppelinOS smart contract platform
The npm package zos-lib receives a total of 21 weekly downloads. As such, zos-lib popularity was classified as not popular.
We found that zos-lib demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.