Use Cases

The following use cases were considered during the creation of this specification.

owned

A package which contains contracts which are not meant to be used by themselves but rather as base contracts to provide functionality to other contracts through inheritance.

See full description.

transferable

A package which has a single dependency.

See full description.

standard-token

A package which contains a reusable contract.

See full description.

safe-math-lib

A package which contains deployed instance of one of the package contracts.

See full description.

piper-coin

A package which contains a deployed instance of a reusable contract from a dependency.

See full description.

escrow

A package which contains a deployed instance of a local contract which is linked against a deployed instance of a local library.

See full description.

wallet

A package with a deployed instance of a local contract which is linked against a deployed instance of a library from a dependency.

See full description.

wallet-with-send

A package with a deployed instance which links against a deep dependency.

See full description.

Each use case builds incrementally on the previous one.

Stand Alone Package with an Inheritable Contract

For the first example we’ll look at a package which only contains contracts which serve as base contracts for other contracts to inherit from but do not provide any real useful functionality on their own. The common owned pattern is a example for this use case.

For this example we will assume this file is located in the solidity source file ./contracts/owned.sol

The owned package contains a single solidity source source file which is intended to be used as a base contract for other contracts to be inherited from. The package does not define any pre-deployed addresses for the owned contract.

The smallest Package for this example looks like this:

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "owned",
  "sources": {
    "./contracts/owned.sol": "ipfs://QmUjYUcX9kLv2FQH8nwc3RLLXtU3Yv5XFpvEjFcAKXB6xD"
  }
}

A Package which includes more than the minimum information would look like this.

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "owned",
  "meta": {
    "license": "MIT",
    "authors": [
      "Piper Merriam <pipermerriam@gmail.com>"
    ],
    "description": "Reusable contracts which implement a privileged 'owner' model for authorization.",
    "keywords": [
      "authorization"
    ],
    "links": {
      "documentation": "ipfs://QmUYcVzTfSwJoigggMxeo2g5STWAgJdisQsqcXHws7b1FW"
    }
  },
  "sources": {
    "./contracts/Owned.sol": "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGV"
  }
}

This fully fleshed out Package is meant to demonstrate various pieces of optional data that can be included. However, for the remainder of our examples we will be using minimalistic Packages to keep our examples as succinct as possible.

Package with an Inheritable Contract and a Dependency

Now that we’ve seen what a simple package looks like, let’s see how to declare dependencies.

The next package will implement the transferable pattern and will depend on our owned package for the authorization mechanism to ensure that only the contract owner may transfer ownership. The transferable package will contain a single solidity source file ./contracts/transferable.sol.

pragma solidity ^0.4.24;

import {Owned} from "owned/contracts/Owned.sol";

contract Transferable is Owned {
    event OwnerChanged(address indexed prevOwner, address indexed newOwner);

    function transferOwner(address newOwner) public onlyOwner returns (bool) {
        emit OwnerChanged(owner, newOwner);
        owner = newOwner;
        return true;
    }
}

The EPM spec is designed to provide as high a guarantee as possible that builds are deterministic and reproducable. To ensure that each package you install gets the exact dependencies it needs, all dependencies are declared as content addressed URIs. This ensures that when a package manager fetches a dependency it always gets the right one.

The IPFS URI for the previous owned Package turns out to be ipfs://QmXDf2GP67otcF2gjWUxFt4AzFkfwGiuzfexhGuotGTLJH which is what we will use in our transferable package to declare the dependency. The Package looks like the following.

{
  "manifest_version":"2",
  "version":"1.0.0",
  "package_name":"transferable",
  "meta":{
    "license":"MIT",
    "authors":[
      "Piper Merriam <pipermerriam@gmail.com>"
    ],
    "description":"Reusable contracts which implement a privileged 'owner' model for authorization with functionality for transfering ownership.",
    "keywords":[
      "authorization"
    ]
  },
  "sources":{
    "./contracts/Transferable.sol":"ipfs://QmZM6vXzwoenmCEU4zVQW44LPt2nEyYXAw9fhftiyEvfDC"
  },
  "build_dependencies":{
    "owned":"ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGV"
  }
}

It will be up to the package management software to determine how the owned dependency actually gets installed as well as handling any import remappings necessary to make the import statement work.

Stand Alone Package with a Reusable Contract

In this next example we’ll look at a package which contains a reusable contract. This means that the package provides a contract which can be on its own in some manner. For this example we will be creating a package which includes a reusable standard ERC20 token contract.

The source code for these contracts was pulled from the SingularDTV github repository. Thanks to them for a very well written contract.

This package will contain two solidity source files:

Given that these source files are relatively large they will not be included here within the guide but can be found in the ./examples/standard-token/ directory within this repository.

Since this package includes a contract which may be used as-is, our Package is going to contain additional information from our previous examples, specifically, the contract_types section. Since we expect people to compile this contract theirselves we won’t need to include any of the contract bytecode, but it will be useful to include the contract ABI and Natspec information. Our Package will look something like the following. The contract ABI and NatSpec sections have been truncated to improve legibility. The full Package can be found here

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "standard-token",
  "sources": {
    "./contracts/AbstractToken.sol": "ipfs://QmQMXDprXxCunfQjA42LXZtzL6YMP8XTuGDB6AjHzpYHgk",
    "./contracts/StandardToken.sol": "ipfs://QmNLr7DzmiaQvk25C8bADBnh9bF5V3JfbwHS49kyoGGEHz"
  },
  "contract_types": {
    "StandardToken": {
      "abi": [
        "..."
      ],
      "natspec": {
        "author": "Stefan George - <stefan.george@consensys.net>",
        "title": "Standard token contract",
        "methods": {
          "allowance(address,address)": {
            "details": "Returns number of allowed tokens for given address.",
            "params": {
              "_owner": "Address of token owner.",
              "_spender": "Address of token spender."
            }
          },
          "...": "..."
        }
      }
    }
  }
}

While it is not required to include the contract ABI and NatSpec information, it does provide those using this package with the data they would need to interact with an instance of this contract without having to regenerate this information from source.

Stand Alone Package with a Deployed Contract

Now that we’ve seen what a package looks like which includes a fully functional contract that is ready to be deployed, lets explore a package that also includes a deployed instance of that contract.

Solidity Libraries are an excellent example of this type of package, so for this example we are going to write a library for safe math operations called safe-math-lib. This library will implement functions to allow addition and subtraction without needing to check for underflow or overflow conditions. Our package will have a single solidity source file ./contracts/SafeMathLib.sol

pragma solidity ^0.4.0;


/// @title Safe Math Library
/// @author Piper Merriam <pipermerriam@gmail.com>
library SafeMathLib {
    /// @dev Subtracts b from a, throwing an error if the operation would cause an underflow.
    /// @param a The number to be subtracted from
    /// @param b The amount that should be subtracted
    function safeAdd(uint a, uint b) returns (uint) {
        if (a + b > a) {
            return a + b;
        } else {
            throw;
        }
    }

    /// @dev Adds a and b, throwing an error if the operation would cause an overflow.
    /// @param a The first number to add
    /// @param b The second number to add
    function safeSub(uint a, uint b) returns (uint) {
        if (b <= a) {
            return a - b;
        } else {
            throw;
        }
    }
}

This will be our first package which includes the deployments section which is the location where information about deployed contract instances is found. Lets look at the Package, some parts have been truncated for readability but the full file can be found here

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "safe-math-lib",
  "sources": {
    "./contracts/SafeMathLib.sol": "ipfs://QmVN1p6MmMLYcSq1VTmaSDLC3xWuAUwEFBFtinfzpmtzQG"
  },
  "contract_types": {
    "SafeMathLib": {
      "deployment_bytecode": {
        "bytecode": "0x606060405234610000575b60a9806100176000396000f36504062dabbdf050606060405260e060020a6000350463a293d1e88114602e578063e6cb901314604c575b6000565b603a600435602435606a565b60408051918252519081900360200190f35b603a6004356024356088565b60408051918252519081900360200190f35b6000828211602a57508082036081566081565b6000565b5b92915050565b6000828284011115602a57508181016081566081565b6000565b5b9291505056"
      },
      "runtime_bytecode": {
        "bytecode": "0x6504062dabbdf050606060405260e060020a6000350463a293d1e88114602e578063e6cb901314604c575b6000565b603a600435602435606a565b60408051918252519081900360200190f35b603a6004356024356088565b60408051918252519081900360200190f35b6000828211602a57508082036081566081565b6000565b5b92915050565b6000828284011115602a57508181016081566081565b6000565b5b9291505056"
      },
      "abi": [
        "..."
      ],
      "compiler": {
        "name": "solc",
        "version": "0.4.6+commit.2dabbdf0.Darwin.appleclang",
        "settings": {
          "optimize": true
        }
      },
      "natspec": {
        "title": "Safe Math Library",
        "author": "Piper Merriam <pipermerriam@gmail.com>",
        "...": "..."
      }
    }
  },
  "deployments": {
    "blockchain://41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d/block/1e96de11320c83cca02e8b9caf3e489497e8e432befe5379f2f08599f8aecede": {
      "SafeMathLib": {
        "contract_type": "SafeMathLib",
        "address": "0x8d2c532d7d211816a2807a411f947b211569b68c",
        "transaction": "0xaceef751507a79c2dee6aa0e9d8f759aa24aab081f6dcf6835d792770541cb2b",
        "block": "0x420cb2b2bd634ef42f9082e1ee87a8d4aeeaf506ea5cdeddaa8ff7cbf911810c"
      }
    }
  }
}

The first thing to point out is that unlike our standard-token contract, we’ve included the bytecode, runtime_bytecode and compiler information in the SafeMathLib section of the contract_type definition. This is because we are also including a deployed instance of this contract and need to require adequate information for package managers to verify that the contract found at the deployed address is in fact from the source code included in this package.

The next thing to look at is the deployments section. The first thing you should see is the BIP122 URI.

blockchain://41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d/block/1e96de11320c83cca02e8b9caf3e489497e8e432befe5379f2f08599f8aecede

This URI defines the chain on which the SafeMathLib library was deployed. The first hash you see, 41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d is the genesis block hash for the Ropsten test network. The later hash 1e96de11320c83cca02e8b9caf3e489497e8e432befe5379f2f08599f8aecede is the block hash for block number 168,238 from the Ropsten chain.

Under that URI there is a single Contract Instance. It specifies that it’s Contract Type is SafeMathLib, the address that the contract instance can be found at, the transaction hash for the transaction that deployed the contract, and the block hash in which the deploying transaction was mined.

Package which uses a Reusable Contract from a depenency

For our next example we’ll be creating a package includes a deployed instance of a Contract Type from that comes from a package dependency. This differs from our previous safe-math-lib example where our deployment is referencing a local contract from the local contract_types. In this package we will be referencing a contract_type from one of the build_dependencies

We are going to use the standard-token package we created earlier and include a deployed version of the StandardToken contract.

Our package will be called piper-coin and will not contain any source files since it merely makes use of the contracts from the standard-token package. The Package is listed below, and can be found at ./examples/piper-coin/1.0.0.json

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "piper-coin",
  "deployments": {
    "blockchain://41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d/block/cff59cd4bc7077ae557eb39f84f869a1ea7955d52071bad439f0458383a78780": {
      "PiperCoin": {
        "contract_type": "standard-token:StandardToken",
        "address": "0x11cbb0604e47e0f8501b8f56c1c05f92088dc1b0",
        "transaction": "0x1f8206683e4b1dea1fd2e7299b7606ff27440f33cb994b42b4ecc4b0f83a210f",
        "block": "0xe94a700ef9aa2d7a1b07321838251ea4ade8d4d682121f67899f401433a0d910",
        "deployment_bytecode": {
          "bytecode": "0x606060405234610000576040516020806106f4833981016040528080519060200190919050505b8060028190555080600060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35b505b610638806100bc6000396000f360606040523615610070576000357c010000000000000000000000000000000000000000000000000000000090048063095ea7b31461007557806318160ddd146100b157806323b872dd146100d457806370a0823114610119578063a9059cbb1461014a578063dd62ed3e14610186575b610000565b346100005761009960048080359060200190919080359060200190919050506101c0565b60405180821515815260200191505060405180910390f35b34610000576100be610287565b6040518082815260200191505060405180910390f35b3461000057610101600480803590602001909190803590602001909190803590602001909190505061028d565b60405180821515815260200191505060405180910390f35b34610000576101346004808035906020019091905050610478565b6040518082815260200191505060405180910390f35b346100005761016e60048080359060200190919080359060200190919050506104ac565b60405180821515815260200191505060405180910390f35b34610000576101aa60048080359060200190919080359060200190919050506105dc565b6040518082815260200191505060405180910390f35b600081600160003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a3600190505b92915050565b60025481565b600081600060008673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610318575081600160008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b80156103245750600082115b156104675781600060008573ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600060008673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061047156610470565b60009050610471565b5b9392505050565b6000600060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b600081600060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101580156104e75750600082115b156105cc5781600060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600060008573ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190506105d6566105d5565b600090506105d6565b5b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b9291505056"
        },
        "runtime_bytecode": {
          "bytecode": "0x60606040523615610070576000357c010000000000000000000000000000000000000000000000000000000090048063095ea7b31461007557806318160ddd146100b157806323b872dd146100d457806370a0823114610119578063a9059cbb1461014a578063dd62ed3e14610186575b610000565b346100005761009960048080359060200190919080359060200190919050506101c0565b60405180821515815260200191505060405180910390f35b34610000576100be610287565b6040518082815260200191505060405180910390f35b3461000057610101600480803590602001909190803590602001909190803590602001909190505061028d565b60405180821515815260200191505060405180910390f35b34610000576101346004808035906020019091905050610478565b6040518082815260200191505060405180910390f35b346100005761016e60048080359060200190919080359060200190919050506104ac565b60405180821515815260200191505060405180910390f35b34610000576101aa60048080359060200190919080359060200190919050506105dc565b6040518082815260200191505060405180910390f35b600081600160003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a3600190505b92915050565b60025481565b600081600060008673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610318575081600160008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b80156103245750600082115b156104675781600060008573ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254019250508190555081600060008673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061047156610470565b60009050610471565b5b9392505050565b6000600060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b919050565b600081600060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101580156104e75750600082115b156105cc5781600060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600060008573ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190506105d6566105d5565b600090506105d6565b5b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b9291505056"
        },
        "compiler": {
          "name": "solc",
          "version": "0.4.6+commit.2dabbdf0.Darwin.appleclang"
        }
      }
    }
  },
  "build_dependencies": {
    "standard-token": "ipfs://QmegJYswSDXUJbKWBuTj7AGBY15XceKxnF1o1Vo2VvVPLQ"
  }
}

Most of this should be familiar but it’s worth pointing out how we reference Contract Types from dependencies. Under the PiperCoin entry within the deployments you should see that the contract_type key is set to standard-token:StandardToken. The first portion represents the name of the package dependency within the build_dependencies that should be used. The later portion indicates the contract type that should be used from that dependencies contract types.