From c7742258228525be6212f5f2fe1680c649c00207 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Sat, 26 May 2018 20:22:45 -0400 Subject: [PATCH 01/11] A few fixes and two rewrites for clarity. --- docs/docs/basil.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index 6c4215b..4f0fbd2 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -103,7 +103,7 @@ Next, let's add the implementation of our Basil contract: zos add Basil ``` -To have your `zos.json` file always up-to-date, run `zos add` for every +To have your `zos.json` file always up-to-date, run the `zos add` command for every new contract you add to your project. By now, the json files looks like this: @@ -118,7 +118,7 @@ By now, the json files looks like this: } ``` -OpenZeppelin will use this file to track your project's contracts on chain, making them upgradeable and dynamically linkable to pre-deployed libraries, as well see soon. +OpenZeppelin will use this file to track your project's contracts on chain, making them upgradeable and dynamically linkable to pre-deployed libraries, as we'll see soon. ## Deploying our first version of Basil, locally @@ -128,7 +128,7 @@ Let's start a local ethereum network: ganache-cli --deterministic ``` -This will print 10 accounts. Copy the address of the first one, and then back into the initial terminal, export it as the `OWNER` because it will be useful for us later: +This will print 10 accounts. Copy the address of the first one and then go back to the terminal window that you used to launch the Ganache client. Export the address you just copied to an environment variable named `OWNER`. You will need easy access to that address as you complete this tutorial: ```sh export OWNER=
@@ -148,7 +148,7 @@ of your project in that specific network, including contract logic and instance Notice how the file `zos.local.json` lists a series of "contracts" and "proxies". The first are the logic contracts for a specific contract name, while the second are the actual contract instances that our users will interact with in the blockchain. -A proxy is a wrapper for a contract's logic, that allows it to be updated, while mainting its state. We need to create an upgradeable instance (proxy) for Basil. +A proxy is a wrapper for a contract's logic, that allows it to be updated, while maintaining its state. We need to create an upgradeable instance (proxy) for Basil. ```sh zos create Basil --from $OWNER --network local --init --args $OWNER @@ -239,7 +239,7 @@ zos link openzeppelin-zos zos push --from $OWNER --deploy-stdlib --network local ``` -Notice the `--deploy-stdlib` option we've used. What this does is inject a version of the standard lib in our development network. Since we're working on a local blockchain, ZeppelinOS's contracts don't exist. This handy option solves that problem for us quite conveniently ^^ +Notice the `--deploy-stdlib` option we've used. What this does is inject a version of the standard lib into our development network. Since we're working on a local blockchain, the smart contracts that make up the ZeppelinOS library don't exist there. This handy option solves that problem for us quite nicely. Now, to create a proxy for the token: From ed4577661357bc7e22d661c2c3664d97166eb725 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Tue, 29 May 2018 17:39:53 -0400 Subject: [PATCH 02/11] Enhanced Ganache deployment instructions. The tutorial did not instruct the user on how to add a section to their Truffle configuration file that describes the Ganache network. This version has those instructions. Also instead of using "local" for the deployment command, this version uses "development" as the network mnemonic since that is the default label used in Truffle's documentation on the Truffle configuration file. --- docs/docs/basil.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index 4f0fbd2..fee06f2 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -134,10 +134,26 @@ This will print 10 accounts. Copy the address of the first one and then go back export OWNER=
``` -Then, to deploy our app: +Before deploying, make sure your Truffle configuration file contains an entry for a network configuration named `development`. Your Truffle configuratiom file is named `truffle.js`. You should see an entry in the `networks` section of that file like the following: + +``` +module.exports = { + networks: { + development: { + host: "127.0.0.1", + port: 8545, + network_id: "*" // Match any network id + } + } +}; +``` + +If you don't, use your favorite editor to add an entry to the `networks` section like the one shown above. If your `truffle.js` file is empty except for a couple of comment lines, just replace the entire contents of that file with that shown above. Now Truffle knows where to find the Ganache client. + +Next, we deploy our app to Ganache: ```sh -zos push --from $OWNER --network local +zos push --from $OWNER --network development ``` The first time you run this command for a specific network, a new From 7328db3ab4c6b66b067c29e124716c2eb324a693 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Tue, 29 May 2018 17:54:13 -0400 Subject: [PATCH 03/11] Finished replacement of "local" with "development" Completed document wide replacement of the "local" network designation with "development". --- docs/docs/basil.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index fee06f2..88df8e3 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -162,15 +162,15 @@ of your project in that specific network, including contract logic and instance ## Contract logic and upgradeable instances -Notice how the file `zos.local.json` lists a series of "contracts" and "proxies". The first are the logic contracts for a specific contract name, while the second are the actual contract instances that our users will interact with in the blockchain. +Notice how the file `zos.development.json` lists a series of "contracts" and "proxies". The first are the logic contracts for a specific contract name, while the second are the actual contract instances that our users will interact with in the blockchain. A proxy is a wrapper for a contract's logic, that allows it to be updated, while maintaining its state. We need to create an upgradeable instance (proxy) for Basil. ```sh -zos create Basil --from $OWNER --network local --init --args $OWNER +zos create Basil --from $OWNER --network development --init --args $OWNER ``` -Take a look at `zos.local.json` again. You will see that we now have a proxy for Basil. This is the address to use in our app. +Take a look at `zos.development.json` again. You will see that we now have a proxy for Basil. This is the address to use in our app. ## Upgrading the contract @@ -227,7 +227,7 @@ Let's add this version to our ZeppelinOS application and push to the network aga ```sh truffle compile zos add BasilERC721:Basil -zos push --from $OWNER --network local +zos push --from $OWNER --network development ``` This will print the address of the deployed Basil contract. Let's export this value to use it later: @@ -239,7 +239,7 @@ export BASIL_ADDRESS=
Now, to upgrade our proxy: ```sh -zos upgrade Basil --from $OWNER --network local +zos upgrade Basil --from $OWNER --network development ``` By now, Basil's proxy will use the new implementation, but it will revert on every donation because it's token is not set. We'll do that next. @@ -252,7 +252,7 @@ The first thing we need to do, is tell our app to link to the `openzeppelin-zos` ```sh zos link openzeppelin-zos -zos push --from $OWNER --deploy-stdlib --network local +zos push --from $OWNER --deploy-stdlib --network development ``` Notice the `--deploy-stdlib` option we've used. What this does is inject a version of the standard lib into our development network. Since we're working on a local blockchain, the smart contracts that make up the ZeppelinOS library don't exist there. This handy option solves that problem for us quite nicely. @@ -260,14 +260,14 @@ Notice the `--deploy-stdlib` option we've used. What this does is inject a versi Now, to create a proxy for the token: ```sh -zos create MintableERC721Token --from $OWNER --init --args \"$BASIL_ADDRESS\",\"BasilToken\",\"BSL\" --network local +zos create MintableERC721Token --from $OWNER --init --args \"$BASIL_ADDRESS\",\"BasilToken\",\"BSL\" --network development ``` This command will output the token's new proxy address. Lets use it to set it in our new BasilERC721 version: ```sh export TOKEN_ADDRESS=
-echo "BasilERC721.at(\"$BASIL_ADDRESS\").setToken(\"$TOKEN_ADDRESS\", {from: \"$OWNER\"})" | npx truffle console --network local +echo "BasilERC721.at(\"$BASIL_ADDRESS\").setToken(\"$TOKEN_ADDRESS\", {from: \"$OWNER\"})" | npx truffle console --network development ``` That's it! Now you know how to use ZeppelinOS to develop upgradeable apps. Have a look at the scripts `deploy/deploy_with_cli_v1.sh` and `deploy/deploy_with_cli_v2.sh` to review what we've gone over in the guide. From ac35f32ad5d467611297d5d669be79648a1b8597 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Tue, 29 May 2018 19:48:18 -0400 Subject: [PATCH 04/11] Uppercased Basil in zos init command The original document used lowercase "basil" in the "zos init" command. This led to the generated "zos.json" having a lowercase "basil" for the "name" field, which didn't match the tutorial. --- docs/docs/basil.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index 88df8e3..cec6af1 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -91,7 +91,7 @@ Now, to get the niceties that ZeppelinOS provides, let's install the `zos` comma ```sh npm install zos -zos init basil 0.0.1 +zos init Basil 0.0.1 ``` This will create a `zos.json` file where ZeppelinOS will keep track of From a543f2bd8def92a8eceb02fccb835b610244354d Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Wed, 13 Jun 2018 22:10:00 -0400 Subject: [PATCH 05/11] Overhaul of the original Basil documentation. Note: This is an interim commit. I have asked a Solidity professional to go through the tutorial on a fresh machine. Once I get their review of this new revision I will do a final commit of this document. Included in this version: - The tutorial is now completely stand-alone including setup and installation of: `truffle`, `ganache-cli`, the necessary auxiliary packages, and the contents of the initial `truffle.js` file. The user does not have to have anything but a working Linux station with the usual tools. - It fixes the most significant problem with the tutorial. The original version told the user immediately after the `zos push` command to assign the output address of that to the BASIL_ADDRESS environment variable. These instructions should have been after the tutorial asks the user to do the `zos create` command since that command outputs the the Basil proxy address. The `zos push` command outputs the `app` package address. This resulted in the the `setToken()` call to fail at the end of the tutorial with a `revert` exception. - Numerous enhancements of various sections of the tutorial to include additional explanations and file snapshots. - Many rewrites of the some of the text to improve clarity and specificity. - Renamed the BASIL_ADDRESS and TOKEN_ADDRESS environment variables to BASIL_PROXY_ADDRESS and TOKEN_PROXY_ADDRESS since that is what they actually contain. --- docs/docs/basil.md | 283 +++++++++++++++++++++++++++++---------------- 1 file changed, 183 insertions(+), 100 deletions(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index cec6af1..d5bc1e3 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -12,105 +12,150 @@ However, after a few days we started having conflicts. Who gets the honor to set ## Creating an app with ZeppelinOS -In this guide, we will build a simple dapp on top of ZeppelinOS. To see the end product, please visit: +In this guide, we will build a simple dApp on top of ZeppelinOS. To see the end product, please visit: * Source code: [zeppelinos/basil](https://github.com/zeppelinos/basil) * App: [basil.zeppelin.solutions](https://basil.zeppelin.solutions) -First we will need to [install Node.js following the instructions from their website](https://nodejs.org/en/download/package-manager/). Then, let's set up a directory for our project and initialize the npm package: +First we will need to [install Node.js following the instructions from their website](https://nodejs.org/en/download/package-manager/). Next we set up a directory for our project including a `contracts` sub-directory to hold our smart contract. Then we initialize the npm package: ```sh mkdir basil cd basil +mkdir contracts npm init --yes ``` -## The sample contract +## Truffle -Next, let's write the contract to control the light bulb in `contracts/Basil.sol`: +We install Truffle, a crucial tool set for creating Solidity contracts and deploying them: -```sol -pragma solidity ^0.4.21; +```sh +npm install -g truffle +``` -import "openzeppelin-zos/contracts/ownership/Ownable.sol"; +## Truffle configuration file -/** - * @title Basil - */ -contract Basil is Ownable { +Before we can do any contract deployments Truffle needs to know where to deploy our smart contracts. Using your favorite editor, create a file named `truffle.js` and put the following content in it: - // color - uint256 public r; - uint256 public g; - uint256 public b; +``` +module.exports = { + networks: { + local: { + host: "127.0.0.1", + port: 8545, + network_id: "*" // Match any network id + } + } +}; +``` - // highest donation in wei - uint256 public highestDonation; +The `networks` section has entries for each destination network that we intend to use for smart contract deployments. Currently we have a single entry in that section for a Ganache client running locally using the default port number `8545`. Now Truffle knows where to find the Ganache client when we use `local` as the destination for a smart contract deployment. - event Withdrawal(address indexed wallet, uint256 value); - event NewDonation(address indexed donor, uint256 value, uint256 r, uint256 g, uint256 b); +## Prerequisites - function donate(uint256 _r, uint256 _g, uint256 _b) public payable { - require(_r < 256); - require(_g < 256); - require(_b < 256); - require(msg.value > highestDonation); - - r = _r; - g = _g; - b = _b; - highestDonation = msg.value; - NewDonation( - msg.sender, msg.value, - r, g, b); - } +We install the `ZOS` command line interface globally with the following command: - function withdraw(address wallet) public onlyOwner { - require(this.balance > 0); - require(wallet != address(0)); - uint256 value = this.balance; - wallet.transfer(value); - Withdrawal(wallet, value); - } +```sh +npm install --global zos +``` + +Next we install the Open Zeppelin contracts library: + +```sh +npm install openzeppelin-zos +``` + +Then we install the ZeppelinOS contract library: + +```sh +npm install zos-lib +``` + +## The sample contract + +Let's write the contract to control the light bulb. Create a file named `Basil.sol` in the `contracts` sub-directory and put the code shown below in it: + +```sol +/** + * @title Basil + */ + +pragma solidity ^0.4.21; + + +import "openzeppelin-zos/contracts/ownership/Ownable.sol"; + +contract Basil is Ownable { + + // color + uint256 public r; + uint256 public g; + uint256 public b; + + // highest donation in wei + uint256 public highestDonation; + + event Withdrawal(address indexed wallet, uint256 value); + event NewDonation(address indexed donor, uint256 value, uint256 r, uint256 g, uint256 b); + + function donate(uint256 _r, uint256 _g, uint256 _b) public payable { + require(_r < 256); + require(_g < 256); + require(_b < 256); + + r = _r; + g = _g; + b = _b; + + // Donation must be higher than the current highest + require(msg.value > highestDonation); + + emit NewDonation(msg.sender, msg.value, r, g, b); + } + + function withdraw(address wallet) public onlyOwner { + require(address(this).balance > 0); + require(wallet != address(0)); + uint256 value = address(this).balance; + wallet.transfer(value); + emit Withdrawal(wallet, value); + } } ``` -The contract is super simple. If somebody wants to set the light color, they have to make a donation. If the donation is higher than the previous one, it is accepted, the light color changes and an event is emitted. Of course, a withdraw method allows the Zeppelin team to collect all donations, which are safely put away in the plant's own education fund. +Save the file and make sure you're back in the `basil` sub-directory afterwards. The contract is super simple. If somebody wants to set the light color, they have to make a donation. If the donation is higher than the previous one, it is accepted, the light color changes and an event is emitted. Of course, the `withdraw` method allows the Zeppelin team to collect all donations, which are safely put away in the plant's own education fund. -We need to install the `openzeppelin-zos` dependency and to compile the contract: +We compile the contract we just created: ```sh -npm install openzeppelin-zos -npx truffle compile +truffle compile ``` > NOTE: If you're familiar with the `openzeppelin-solidity` library, note that we're using something different here. We're using the `openzeppelin-zos` library, which is the OpenZeppelin version for ZeppelinOS. ## Using ZeppelinOS -Now, to get the niceties that ZeppelinOS provides, let's install the `zos` command line interface and initialize our application with the version 0.0.1: + We initialize our application with the version 0.0.1 using the ZOS command line interface: ```sh -npm install zos -zos init Basil 0.0.1 +zos init basil 0.0.1 ``` This will create a `zos.json` file where ZeppelinOS will keep track of the contracts of your application. -Next, let's add the implementation of our Basil contract: +Next, add the Basil contract to the list of contracts in `zos.json`: ```sh zos add Basil ``` To have your `zos.json` file always up-to-date, run the `zos add` command for every -new contract you add to your project. - -By now, the json files looks like this: +new contract you add to your project. The json file should look like this now: ```json { - "name": "Basil", + "name": "basil", "version": "0.0.1", "contracts": { "Basil": "Basil" @@ -122,38 +167,28 @@ OpenZeppelin will use this file to track your project's contracts on chain, maki ## Deploying our first version of Basil, locally -Let's start a local ethereum network: +Let's start a local Ethereum network. If you have never done this before, you will need to install the Ganache client using the following command: ```sh -ganache-cli --deterministic +npm install -g ganache-cli ``` -This will print 10 accounts. Copy the address of the first one and then go back to the terminal window that you used to launch the Ganache client. Export the address you just copied to an environment variable named `OWNER`. You will need easy access to that address as you complete this tutorial: +Open a new Terminal window and execute the following command to start the Ganache client: ```sh -export OWNER=
+ganache-cli --deterministic ``` -Before deploying, make sure your Truffle configuration file contains an entry for a network configuration named `development`. Your Truffle configuratiom file is named `truffle.js`. You should see an entry in the `networks` section of that file like the following: +This will print 10 accounts. Copy the address of the first one and then go back to the terminal window that you used to create the Basil project. Export the address you just copied to an environment variable named `OWNER` (see below). You will need easy access to that address as you work through this tutorial: +```sh +export OWNER=
``` -module.exports = { - networks: { - development: { - host: "127.0.0.1", - port: 8545, - network_id: "*" // Match any network id - } - } -}; -``` - -If you don't, use your favorite editor to add an entry to the `networks` section like the one shown above. If your `truffle.js` file is empty except for a couple of comment lines, just replace the entire contents of that file with that shown above. Now Truffle knows where to find the Ganache client. Next, we deploy our app to Ganache: ```sh -zos push --from $OWNER --network development +zos push --from $OWNER --network local ``` The first time you run this command for a specific network, a new @@ -162,23 +197,59 @@ of your project in that specific network, including contract logic and instance ## Contract logic and upgradeable instances -Notice how the file `zos.development.json` lists a series of "contracts" and "proxies". The first are the logic contracts for a specific contract name, while the second are the actual contract instances that our users will interact with in the blockchain. +Notice how the file `zos.local.json` lists a series of "contracts" and "proxies". The `contracts` entry contains a list of each logic contract for each contract name. The `address` field contains the deployment address of the logic contract and the `byteCodeHash` field contains the hash code for the contract. Currently the `proxies` list is empty since we have not created any proxies yet. A proxy is a wrapper for a logic contract. By having a proxy, you can change or update a logic contract while maintaining its state. + +We need to create an upgradeable instance (proxy) for Basil now. We use the `zos create` command to create a proxy: + +``` +zos create Basil --from $OWNER --network local --init --args $OWNER +``` -A proxy is a wrapper for a contract's logic, that allows it to be updated, while maintaining its state. We need to create an upgradeable instance (proxy) for Basil. +Copy the address this command outputs to the clipboard. It should match the address in the line that is printed after the text `Basil proxy:`. This is the address for the contract that is proxying our Basil contract. We will need it later so export it to the environment with the following command: ```sh -zos create Basil --from $OWNER --network development --init --args $OWNER +export BASIL_PROXY_ADDRESS=0x9431db860bb727f7695ea8af6a4dc1d2cf34344d ``` -Take a look at `zos.development.json` again. You will see that we now have a proxy for Basil. This is the address to use in our app. +We now have an entry in the `proxies` list for our Basil contract. A proxy entry contains the deployment address for a specific logic contract, the current version number of that contract, and its implementation address. Notice that the implementation address field in the proxy entry matches the deployment address field for the Basil entry in the `contracts list. If contracts were mail, the implementation field could be considered the current "forwarding" address for the Basil logic contract. When we upgrade the Basil contract later in this tutorial. You can see this in the updated `zos.local.json` file, shown below: + +```json +{ + "contracts": { + "Basil": { + "address": "0x1b88bdb8269a1ab1372459f5a4ec3663d6f5ccc4", + "bytecodeHash": "089769261b0c6e1ab9eb20f3321f7cb959c4bbf9156bbfde92a31d2000a44689" + } + }, + "proxies": { + "Basil": [ + { + "address": "0x9431db860bb727f7695ea8af6a4dc1d2cf34344d", + "version": "0.0.1", + "implementation": "0x1b88bdb8269a1ab1372459f5a4ec3663d6f5ccc4" + } + ] + }, + "app": { + "address": "0xaf5c4c6c7920b4883bc6252e9d9b8fe27187cf68" + }, + "version": "0.0.1", + "package": { + "address": "0x2d8be6bf0baa74e0a907016679cae9190e80dd0a" + }, + "provider": { + "address": "0x970e8f18ebfea0b08810f33a5a40438b9530fbcf" + } +} +``` ## Upgrading the contract -If we ever found a bug in Basil, we would need to upgrade our zos package, provide a new implementation for Basil with a fix and tell our proxy to upgrade to the new implementation. This would preserve all the previous donation history, while seamlessly patching the bug. +If we ever found a bug in Basil we would need to upgrade our zos package, provide a new implementation for Basil with a fix, and tell our proxy to upgrade to the new implementation. This would preserve all the previous donation history while seamlessly patching the bug. -Another common thing that happens when developing smart contracts for Ethereum is that new standards appear, all the new kids implement them in their contracts, and a very cool synergy between contracts starts to happen. Developers who have already deployed immutable contracts will miss all the fun. For example, it would be very nice to encourage donations to Basil by emitting a unique ERC721 token in exchange. Well, let's upgrade the contract with ZeppelinOS to do just that. +Another common thing that happens when developing smart contracts for Ethereum is that new standards appear. All the new kids implement them in their contracts and a very cool synergy between contracts starts to happen. Developers who have already deployed immutable contracts will miss all the fun. For example, it would be very nice to encourage donations to Basil by emitting a unique ERC721 token in exchange for the donation. Let's upgrade the contract with ZeppelinOS to do just that. -We could modify `contracts/Basil.sol`. But now let's try something else. Let's make a new contract in `contracts/BasilERC721.sol`, that inherits from our initial version of Basil: +We could modify `contracts/Basil.sol`, but now let's try something else. We'll make a new contract name `BasilERC721.sol` in the `contracts` sub-directory that inherits from our initial version of Basil. Create that file now and put the content shown below in it: ```sol pragma solidity ^0.4.21; @@ -213,63 +284,75 @@ contract BasilERC721 is Basil { ``` A few things to note: + * This new version extends from the previous one. This is a very handy pattern, because the proxy used in ZeppelinOS requires new versions to preserve the state variables. - * We can add new state variables and new functions. The only thing that we can't do on a contract upgrade is to remove state variables. + * We can add new state variables and new functions. The only thing that we can't do during a contract upgrade is to remove state variables. -Let's create a new version of our app, with the new contracts: +Let's create a new version of our app, with the new contracts. Make sure you are back in the `basil` directory before executing this command. This command simply changes the current version number for the app to "0.0.2" in the `zos.json` file: ```sh zos bump 0.0.2 ``` -Let's add this version to our ZeppelinOS application and push to the network again: +Let's add this version to our ZeppelinOS application and push to the network again. Notice that we reference our base smart contract `Basil` when adding our new `BasilERC721` smart contract when using the `zos add` command. We do this by appending the base contract's name prefixed by a colon to the new contract's name as the primary argument tor the `zos add` command: ```sh truffle compile zos add BasilERC721:Basil -zos push --from $OWNER --network development +zos push --from $OWNER --network local ``` - -This will print the address of the deployed Basil contract. Let's export this value to use it later: +Now to upgrade our proxy and let it know about the new implementation: ```sh -export BASIL_ADDRESS=
+zos upgrade Basil --from $OWNER --network local ``` -Now, to upgrade our proxy: - -```sh -zos upgrade Basil --from $OWNER --network development -``` +Let's look a `zos.local.json` again. Notice that the deployment address field for the Basil logic contract has changed to the new deployment address. Because of this, the implementation field for the Basil proxy contract changed to match that new deployment address, thus preserving the linkage between the logic contract and the proxy contract. -By now, Basil's proxy will use the new implementation, but it will revert on every donation because it's token is not set. We'll do that next. +From here on Basil's proxy will use the new implementation. In its current state, Basil will revert on every donation because it doesn't have a token set for it yet. We'll do that next. ## Connecting to OpenZeppelin's standard library -So far, we've used ZeppelinOS to seamlessly upgrade our app's contracts. We will now use it to create a proxy for a pre-deployed ERC721 token implementation. +So far, we've used ZeppelinOS to seamlessly upgrade our app's contracts. We will now use it to create a proxy for a pre-deployed ERC721 token implementation. -The first thing we need to do, is tell our app to link to the `openzeppelin-zos` standard library release: +The first thing we need to do is to tell our app to link to the `openzeppelin-zos` standard library release. Note, the link command may take a little while to complete: ```sh zos link openzeppelin-zos -zos push --from $OWNER --deploy-stdlib --network development +zos push --from $OWNER --deploy-stdlib --network local ``` +If you look at the `zos.json` file now, you will see a new entry named `stdlib` that keeps track of the package name and current version number for the `openzeppelin-zos` package we just linked to: -Notice the `--deploy-stdlib` option we've used. What this does is inject a version of the standard lib into our development network. Since we're working on a local blockchain, the smart contracts that make up the ZeppelinOS library don't exist there. This handy option solves that problem for us quite nicely. +```json{ + "name": "basil", + "version": "0.0.2", + "contracts": { + "Basil": "BasilERC721" + }, + "stdlib": { + "name": "openzeppelin-zos", + "version": "1.9.1" + } +} +``` -Now, to create a proxy for the token: +Notice the `--deploy-stdlib` option we used during the deployment using the `zos push` command. This option injects a version of the ZeppelinOS standard library of contracts into our development network. Since we're working on a local blockchain the smart contracts that make up the ZeppelinOS library don't exist there. This handy option solves that problem for us quite nicely. + +Now we create a proxy for the token: ```sh -zos create MintableERC721Token --from $OWNER --init --args \"$BASIL_ADDRESS\",\"BasilToken\",\"BSL\" --network development +zos create MintableERC721Token --from $OWNER --init --args \"$BASIL_PROXY_ADDRESS\",\"BasilToken\",\"BSL\" --network local ``` -This command will output the token's new proxy address. Lets use it to set it in our new BasilERC721 version: +This command will output the token's new proxy address. It should match the address from the line that begins with the label `MintableERC721Token proxy`. The command below conveniently fills in the needed values from the environment variables we set earlier, and then passes that command to a new Truffle console session, to be executed immediately: ```sh -export TOKEN_ADDRESS=
-echo "BasilERC721.at(\"$BASIL_ADDRESS\").setToken(\"$TOKEN_ADDRESS\", {from: \"$OWNER\"})" | npx truffle console --network development +export TOKEN_PROXY_ADDRESS=
+echo "BasilERC721.at(\"$BASIL_PROXY_ADDRESS\").setToken(\"$TOKEN_PROXY_ADDRESS\", {from: \"$OWNER\"})" | truffle console --network local ``` +You will see the result of the transaction in JSON format with some interesting details like how much gas was used, the block number, and other information. + That's it! Now you know how to use ZeppelinOS to develop upgradeable apps. Have a look at the scripts `deploy/deploy_with_cli_v1.sh` and `deploy/deploy_with_cli_v2.sh` to review what we've gone over in the guide. -Stay tuned for more advanced turorials! +Stay tuned for more advanced tutorials! From 52da54b636fb3de54fad6118c6eb2199a2419903 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Wed, 13 Jun 2018 22:18:31 -0400 Subject: [PATCH 06/11] Added not about sample addresses. Added a small note that tells the user that the addresses found in this tutorial document are only samples and will not match what they see on their system monitor as the execute the commands in this tutorial. --- docs/docs/basil.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index d5bc1e3..f60fabd 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -16,6 +16,8 @@ In this guide, we will build a simple dApp on top of ZeppelinOS. To see the end * Source code: [zeppelinos/basil](https://github.com/zeppelinos/basil) * App: [basil.zeppelin.solutions](https://basil.zeppelin.solutions) +> NOTE: You will see several Ethereum addresses output by the commands you execute as you follow along with this tutorial. Do not be concerned if they don't match the addresses you see in this document. + First we will need to [install Node.js following the instructions from their website](https://nodejs.org/en/download/package-manager/). Next we set up a directory for our project including a `contracts` sub-directory to hold our smart contract. Then we initialize the npm package: ```sh From c02ccbca1f763a33ecd54b2476537a2d6f004a55 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Wed, 13 Jun 2018 22:22:32 -0400 Subject: [PATCH 07/11] Fixed missing backward quote Closed off a backward quoted text element that was missing. --- docs/docs/basil.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index f60fabd..497c0dd 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -213,7 +213,7 @@ Copy the address this command outputs to the clipboard. It should match the add export BASIL_PROXY_ADDRESS=0x9431db860bb727f7695ea8af6a4dc1d2cf34344d ``` -We now have an entry in the `proxies` list for our Basil contract. A proxy entry contains the deployment address for a specific logic contract, the current version number of that contract, and its implementation address. Notice that the implementation address field in the proxy entry matches the deployment address field for the Basil entry in the `contracts list. If contracts were mail, the implementation field could be considered the current "forwarding" address for the Basil logic contract. When we upgrade the Basil contract later in this tutorial. You can see this in the updated `zos.local.json` file, shown below: +We now have an entry in the `proxies` list for our Basil contract. A proxy entry contains the deployment address for a specific logic contract, the current version number of that contract, and its implementation address. Notice that the implementation address field in the proxy entry matches the deployment address field for the Basil entry in the `contracts` list. If contracts were mail, the implementation field could be considered the current "forwarding" address for the Basil logic contract. When we upgrade the Basil contract later in this tutorial. You can see this in the updated `zos.local.json` file, shown below: ```json { From 0e5679171c478b54006936669516910c3b726a6d Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Wed, 13 Jun 2018 22:47:48 -0400 Subject: [PATCH 08/11] Several minor improvements Replaced the hard coded address in one of the address export statements with a substitution label. Enhanced and cleaned up the text involving the exporting of the mintable token and the `setToken()` command. --- docs/docs/basil.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index 497c0dd..6c38e20 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -210,7 +210,7 @@ zos create Basil --from $OWNER --network local --init --args $OWNER Copy the address this command outputs to the clipboard. It should match the address in the line that is printed after the text `Basil proxy:`. This is the address for the contract that is proxying our Basil contract. We will need it later so export it to the environment with the following command: ```sh -export BASIL_PROXY_ADDRESS=0x9431db860bb727f7695ea8af6a4dc1d2cf34344d +export BASIL_PROXY_ADDRESS=
``` We now have an entry in the `proxies` list for our Basil contract. A proxy entry contains the deployment address for a specific logic contract, the current version number of that contract, and its implementation address. Notice that the implementation address field in the proxy entry matches the deployment address field for the Basil entry in the `contracts` list. If contracts were mail, the implementation field could be considered the current "forwarding" address for the Basil logic contract. When we upgrade the Basil contract later in this tutorial. You can see this in the updated `zos.local.json` file, shown below: @@ -346,10 +346,14 @@ Now we create a proxy for the token: zos create MintableERC721Token --from $OWNER --init --args \"$BASIL_PROXY_ADDRESS\",\"BasilToken\",\"BSL\" --network local ``` -This command will output the token's new proxy address. It should match the address from the line that begins with the label `MintableERC721Token proxy`. The command below conveniently fills in the needed values from the environment variables we set earlier, and then passes that command to a new Truffle console session, to be executed immediately: +This command will output the token's new proxy address. It should match the address from the line that begins with the label `MintableERC721Token proxy`. Export the token address to the environment so we can use it later: ```sh export TOKEN_PROXY_ADDRESS=
+``` +The command below conveniently fills in the needed values from the environment variables we set earlier, and then passes that command to a new Truffle console session, to be executed immediately. This command sets the token address of the token we just created a proxy for into our BasilERC721 contract: + +```sh echo "BasilERC721.at(\"$BASIL_PROXY_ADDRESS\").setToken(\"$TOKEN_PROXY_ADDRESS\", {from: \"$OWNER\"})" | truffle console --network local ``` You will see the result of the transaction in JSON format with some interesting details like how much gas was used, the block number, and other information. From d4ae3b52f9523b5bc6bff71766b986b16a03b9c2 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Wed, 13 Jun 2018 22:49:05 -0400 Subject: [PATCH 09/11] Removed unnecessary repetition of "token". --- docs/docs/basil.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index 6c38e20..1b012ae 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -346,7 +346,7 @@ Now we create a proxy for the token: zos create MintableERC721Token --from $OWNER --init --args \"$BASIL_PROXY_ADDRESS\",\"BasilToken\",\"BSL\" --network local ``` -This command will output the token's new proxy address. It should match the address from the line that begins with the label `MintableERC721Token proxy`. Export the token address to the environment so we can use it later: +This command will output the token's new proxy address. It should match the address from the line that begins with the label `MintableERC721Token proxy`. Export the address to the environment so we can use it later: ```sh export TOKEN_PROXY_ADDRESS=
From f188c02ad54e91a39a3a240555f61be897b91384 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Fri, 15 Jun 2018 09:59:07 -0400 Subject: [PATCH 10/11] Removed truffle.js section Removed the section on creating a truffle.js file since `zos init` creates one. --- docs/docs/basil.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index 1b012ae..fe869af 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -34,25 +34,6 @@ We install Truffle, a crucial tool set for creating Solidity contracts and deplo ```sh npm install -g truffle ``` - -## Truffle configuration file - -Before we can do any contract deployments Truffle needs to know where to deploy our smart contracts. Using your favorite editor, create a file named `truffle.js` and put the following content in it: - -``` -module.exports = { - networks: { - local: { - host: "127.0.0.1", - port: 8545, - network_id: "*" // Match any network id - } - } -}; -``` - -The `networks` section has entries for each destination network that we intend to use for smart contract deployments. Currently we have a single entry in that section for a Ganache client running locally using the default port number `8545`. Now Truffle knows where to find the Ganache client when we use `local` as the destination for a smart contract deployment. - ## Prerequisites We install the `ZOS` command line interface globally with the following command: From 85dc65d67e006e0b57ebf024e6074c5959aeb3b6 Mon Sep 17 00:00:00 2001 From: Robert Oschler Date: Fri, 15 Jun 2018 10:12:48 -0400 Subject: [PATCH 11/11] Push being done solely to update pull request history. --- docs/docs/basil.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/basil.md b/docs/docs/basil.md index fe869af..3743cfd 100644 --- a/docs/docs/basil.md +++ b/docs/docs/basil.md @@ -11,7 +11,7 @@ Here at the Zeppelin headquarters we have a basil plant. She is a good mascot, a However, after a few days we started having conflicts. Who gets the honor to set the light color for our friendly plant? What if they choose their favorite color instead of the one that's best for the plant? For how long do they get to keep their chosen color? We also found that somebody kept resetting the color back to an ugly lime green every morning. We are ok with anarchy, but we want transparency, so we decided to control the light bulb through a contract on the Ethereum blockchain. ## Creating an app with ZeppelinOS - + In this guide, we will build a simple dApp on top of ZeppelinOS. To see the end product, please visit: * Source code: [zeppelinos/basil](https://github.com/zeppelinos/basil) * App: [basil.zeppelin.solutions](https://basil.zeppelin.solutions)