A step towards a more complex Smart Contract architecture

In the last blog, we talked about building upgradable Smart Contacts using ZeppelinOS (zOS). Today, we’ll look at building EVM packages using zOS. Using Zeppelin, we can create an EVM package which can be used by other developers. Your EVM package will be deployed on the Ethereum Blockchain and any developer can link your package in their Smart Contracts.

What is an EVM package?

An EVM package is an upgradable dependency for your Smart Contracts. In simple words: it’s an upgradable deployed Smart Contact on Ethereum blockchain which anyone can use as a dependency for their project.

Building an EVM Package

Building an EVM package is similar to building an upgradable project as we have seen in our last tutorial. If you didn’t check that one, I strongly recommend you to check it out first.

In this tutorial, we will build a basic upgradable Smart Contract and publish it to the local network using Ganache.

As we’ve already detailed how to build an upgradable Smart Contract in the last tutorial, we will skip that part and just see how to publish it on a local network:

pragma solidity ^ 0.4 .24;
import "zos-lib/contracts/Initializable.sol";
contract Random is Initializable {
uint256 public seed;
function initialize(uint256 mySeed) initializer public {
        seed = mySeed;
    }
function getRandom(uint256 number) public view returns(uint8) {
        return uint8(uint256(keccak256(abi.encodePacked(block.timestamp, block.difficulty, number, seed))) % 251);
    }
}

Once we add and push the package using zos add and zos push, we are now ready to publish it to the local network using below commands:

zos publish --network local

** if you create a production-ready EVM package, you can push it to NPM.

Using a published EVM package in your project

Now let’s see how we can use an already-published EVM package in our project. We will build an ERC721 token using openzeppelin-eth EVM package.

So, build a zos project (as we learned in the last tutorial) and add below ERC721 Smart Contract:

pragma solidity ^0.4.24;
import "openzeppelin-eth/contracts/token/ERC721/ERC721Mintable.sol";
contract SIMPLEToken{
  ERC721Mintable private _token;
function setToken(ERC721Mintable token) external {
    require(token != address(0));
    _token = token;
  }
}

We are importingopenzeppelin-eth instead of openzeppelin-solidity . The main difference is that openzeppelin-solidity is an open-source library without deployed contracts and openzeppelin-eth is an open-source library with already deployed code, hence an EVM package.

Now, let’s link our project to the openzeppelin-eth package by running:

zos link openzeppelin-eth

This will install openzeppelin-eth contracts and also update the zos.json file with the referenced package. So all the packages we will use, this command will insert references for those contracts in zos.json. We still need to compile these contracts.

Now let’s add our contract to the project:

zos add SIMPLEToken

** make sure that your zos session is established, and if any of the commands have failed, recreated your session using:

zos session --network local --from 0x1df62f291b2e969fb0849d99d9ce41e2f137006e --expires 3600

Now, let’s push our changes to our local blockchain:

zos push --deploy-dependencies

The --deploy-dependencies flag is used mainly if you are using a network (no matter which) which doesn’t already have the deployed EVM package you are using in your project (openzeppelin-eth in our case). So as we are using local blockchain we will use this flag, but we will only use this flag once… next time we’ll already have openzeppelin-eth package deployed locally.

Let’s create an upgradable instance of our SIMPLEToken contract:

zos create SIMPLEToken

We also need an instance of the ERC721 token from the EVM package:

zos create openzeppelin-eth/StandaloneERC721 --init initialize --args SIMPLEToken,BTS,[<address>],[<address>]

<address> will be the minter and pauser address of the token. For local development, you can use one of the 10 addresses which are created by ganache-cli . Remember, you can add more than 1 address as [<address>] in an array.

Now we can start the Truffle console to interact with Smart Contact:

npx truffle console --network local

Next, let’s jump to that Truffle console and connect our two deployed upgradeable contracts:

truffle(local)> SIMPLEToken.at('<my-linked-contract-address>').setToken('<my-erc721-address>')

Here, replace:

  • <my-linked-contract-address> with the address you got while running zos create SIMPLEToken
  • <my-erc721-address> with the address you got while creating StandaloneERC721 instance (check above command)

Remember that the addresses of both, your contract and the token, can also be found in the zos.dev-<network_id>.json configuration file.

You can find more examples and list of all available package here.

Conclusion

zOS provides a new paradigm for Smart Contract development. It paves the way for more complex Smart Contract architecture with the power of upgradability. In the future, you’ll be able to plug & play many Smart Contracts’ functionalities without worrying about each and every detail. It will create rapid growth in Smart Contract development as more developers can use these packages and Solidity libraries, and participate in building more complex systems.

zOS also provides a way to build upgradable Solidity libraries, and we will discuss them in our future tutorials. Meanwhile, if you are Smart Contract developer, check out the ZeppelinOS project and you can find more details in their docs.

About QuikNode

QuikNode is building infrastructure to support the future of Web3. Since 2017, we’ve worked with hundreds of developers & companies, helping scale dApps and providing high-performance Ethereum nodes. We’re working on something interesting from the past few months and will be launching soon, so subscribe our newsletter for more updates!! 😃