Comparing version 0.0.4 to 0.0.5
{ | ||
"name": "zos-lib", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "zeppelin_os library", | ||
@@ -24,2 +24,3 @@ "scripts": { | ||
"author": "Manuel Araoz <manuel@zeppelinos.org>", | ||
"main": "index.js", | ||
"license": "MIT", | ||
@@ -26,0 +27,0 @@ "bugs": { |
105
readme.md
@@ -7,1 +7,106 @@ # zeppelin_os library | ||
: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 and is also used inside [the zOS Kernel](https://github.com/zeppelinos/kernel). | ||
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](https://github.com/zeppelinos/cli). | ||
# Getting Started | ||
To install `zos-lib` simply go to your project's root directory and run: | ||
```sh | ||
npm i zos-lib | ||
``` | ||
Next, learn how to: | ||
- [Develop and deploy a single smart contract which can be upgraded](#single) (for bugfixing or adding new features). | ||
- [Develop and operate a complex upgradeable app](#complex) with multiple smart contracts which are connected to the zOS Kernel upgradeable standard libraries. | ||
- [Develop a zOS Kernel standard library release.](#kernel) | ||
## <a name="single"></a> Develop and deploy a single upgradeable smart contract | ||
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](https://github.com/zeppelinos/zos-cli/blob/master/README.md). | ||
To work with a single upgradeable smart contract, you just need to deal with a simple upgradeability proxy. This is a special contract that will hold the storage of your upgradeable contract and redirect function calls to an `implementation` contract, which you can change (thus making it upgradeable). To learn more about how proxies work under the hood, [read this post on our blog](https://blog.zeppelinos.org/proxy-patterns/). To simply use them, do the following: | ||
1. Write the first implementation of your contract. Let's assume it's located in `MyContract.sol`. Most contracts require some sort of initialization, but upgradeable contracts can't use constructors ([for reasons explained in this blog post](https://blog.zeppelinos.org/proxy-patterns/)), so we need to use the `Initializable` pattern provided in `zos-lib`: | ||
```sol | ||
import "zos-lib/contracts/migrations/Initializable.sol"; | ||
contract MyContract is Initializable { | ||
bool internal initialized; | ||
uint256 public x; | ||
function initialize(uint256 _x) public { | ||
require(!initialized); | ||
x = _x; | ||
initialized = true; | ||
} | ||
} | ||
``` | ||
2. Deploy your first implementation contract: | ||
```js | ||
const implementation_v0 = await MyContract.new(); | ||
``` | ||
3. Now we need to deploy the proxy contract that will manage our contract's upgradeability. We pass the implementation address in the constructor, to set the first version of the behavior. | ||
```js | ||
const proxy = await OwnedUpgradeabilityProxy.new(implementation_v0.address); | ||
``` | ||
4. Next, we call initialize on the proxy, to initialize the storage variables. Note that we wrap the proxy in a `MyContract` interface, because all calls will be delegated to the behavior. | ||
```js | ||
let myContract = await MyContract.at(proxy.address); | ||
const x0 = 42; | ||
await myContract.initialize(x0); | ||
console.log(await myContract.x()); // 42 | ||
``` | ||
5. We now want to add a function to our contract, so we edit the MyContract.sol file and add it: | ||
```sol | ||
import "zos-lib/contracts/migrations/Initializable.sol"; | ||
contract MyContract is Initializable { | ||
bool internal initialized; | ||
uint256 public x; | ||
function initialize(uint256 _x) public { | ||
require(!initialized); | ||
x = _x; | ||
initialized = true; | ||
} | ||
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). | ||
6. Next, we deploy the new implementation contract, and upgrade our proxy to it: | ||
```js | ||
const implementation_v1 = await MyContract.new(); | ||
await proxy.upgradeTo(implementation_v1.address); | ||
myContract = await MyContract_v1.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`](https://github.com/zeppelinos/zos-lib/tree/master/examples/single) folder. | ||
## <a name="complex"></a> Develop and operate a complex upgradeable app | ||
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 Kernel standard libraries. | ||
## <a name="kernel"></a> Develop a zOS Kernel standard library release. |
const AppDirectory = artifacts.require('AppDirectory') | ||
const assertRevert = require('../../helpers/assertRevert') | ||
const assertRevert = require('../../../lib/assertRevert') | ||
const ContractDirectory = artifacts.require('ContractDirectory') | ||
@@ -4,0 +4,0 @@ const shouldBehaveLikeContractDirectory = require('../versioning/ContractDirectory.behavior') |
const Package = artifacts.require('Package') | ||
const PackagedAppManager = artifacts.require('PackagedAppManager') | ||
const encodeCall = require('../../helpers/encodeCall') | ||
const decodeLogs = require('../../helpers/decodeLogs') | ||
const assertRevert = require('../../helpers/assertRevert') | ||
const encodeCall = require('../../../lib/encodeCall') | ||
const decodeLogs = require('../../../lib/decodeLogs') | ||
const assertRevert = require('../../../lib/assertRevert') | ||
const ContractDirectory = artifacts.require('ContractDirectory') | ||
@@ -7,0 +7,0 @@ const InitializableMock = artifacts.require('InitializableMock') |
@@ -1,4 +0,4 @@ | ||
const encodeCall = require('../../helpers/encodeCall') | ||
const decodeLogs = require('../../helpers/decodeLogs') | ||
const assertRevert = require('../../helpers/assertRevert') | ||
const encodeCall = require('../../../lib/encodeCall') | ||
const decodeLogs = require('../../../lib/decodeLogs') | ||
const assertRevert = require('../../../lib/assertRevert') | ||
const InitializableMock = artifacts.require('InitializableMock') | ||
@@ -5,0 +5,0 @@ const ContractDirectory = artifacts.require('ContractDirectory') |
@@ -1,2 +0,2 @@ | ||
const assertRevert = require('../../helpers/assertRevert') | ||
const assertRevert = require('../../../lib/assertRevert') | ||
const ContractDirectory = artifacts.require('ContractDirectory') | ||
@@ -3,0 +3,0 @@ const shouldBehaveLikeOwnable = require('../../ownership/Ownable.behavior') |
@@ -1,2 +0,2 @@ | ||
const assertRevert = require('../../helpers/assertRevert') | ||
const assertRevert = require('../../../lib/assertRevert') | ||
const FreezableContractDirectory = artifacts.require('FreezableContractDirectory') | ||
@@ -3,0 +3,0 @@ const shouldBehaveLikeContractDirectory = require('./ContractDirectory.behavior') |
const Package = artifacts.require('Package') | ||
const assertRevert = require('../../helpers/assertRevert') | ||
const assertRevert = require('../../../lib/assertRevert') | ||
const ContractDirectory = artifacts.require('ContractDirectory') | ||
@@ -4,0 +4,0 @@ const shouldBehaveLikeOwnable = require('../../ownership/Ownable.behavior') |
@@ -1,2 +0,2 @@ | ||
const assertRevert = require('../helpers/assertRevert') | ||
const assertRevert = require('../../lib/assertRevert') | ||
const InitializableMock = artifacts.require('InitializableMock') | ||
@@ -3,0 +3,0 @@ |
const assert = require('chai').assert; | ||
const encodeCall = require('../helpers/encodeCall'); | ||
const decodeLogs = require('../helpers/decodeLogs'); | ||
const assertRevert = require('../helpers/assertRevert'); | ||
const encodeCall = require('../../lib/encodeCall'); | ||
const decodeLogs = require('../../lib/decodeLogs'); | ||
const assertRevert = require('../../lib/assertRevert'); | ||
@@ -6,0 +6,0 @@ const Migratable = artifacts.require('Migratable'); |
@@ -1,2 +0,2 @@ | ||
const assertRevert = require('../helpers/assertRevert') | ||
const assertRevert = require('../../lib/assertRevert') | ||
@@ -3,0 +3,0 @@ function shouldBehaveLikeOwnable(owner, anotherAccount) { |
'use strict' | ||
const encodeCall = require('../helpers/encodeCall') | ||
const assertRevert = require('../helpers/assertRevert') | ||
const encodeCall = require('../../lib/encodeCall') | ||
const assertRevert = require('../../lib/assertRevert') | ||
const MigratableMockV1 = artifacts.require('MigratableMockV1') | ||
@@ -6,0 +6,0 @@ const MigratableMockV2 = artifacts.require('MigratableMockV2') |
'use strict'; | ||
const encodeCall = require('../helpers/encodeCall') | ||
const encodeCall = require('../../lib/encodeCall') | ||
const InitializableMock = artifacts.require('InitializableMock') | ||
@@ -5,0 +5,0 @@ const OwnedUpgradeabilityProxy = artifacts.require('OwnedUpgradeabilityProxy') |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
519436
60
11945
112
1
1