Use Cases

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

Stand Alone Package with an Inheritable Contract

e.g. owned

See full description.

Dependent Package with an Inheritable Contract

e.g. transferable

See full description.

Stand Alone Package with a Reusable Contract

e.g. standard-token

See full description.

Stand Alone Package with a Deployed Contract

e.g. safe-math-lib

See full description.

Dependent Package with a Reusable Contract

e.g. piper-coin

See full description.

Stand Alone Package with a Deployed Contract Linked against a Deployed Library

e.g. escrow

See full description.

Dependent Package with a Deployed Contract Linked against a Package Dependency

e.g. wallet

See full description.

Dependent Package with a Deployed Contract Linked Against a Deep Dependency

e.g. wallet-with-send

See full description.

Each use case builds incrementally on the previous one.

Keywords

Stand Alone:Package has no external dependencies (i.e. no build_dependencies), contains all contract data needed without reaching into another package.
Dependent:Package does not contain all necessary contract data (i.e. has build_dependencies), must reach into a package dependency to retrieve data.
Inheritable:Contract doesn’t provide useful functionality on it’s own and is meant to serve as a base contract for others to inherit from.
Reusable:Contract is useful on it’s own, meant to be used as-is.
Deployed Contract/Library:
 Refers to an instance of a contract/library that has already been deployed to a specific address on a chain.
Package Dependency:
 External dependency directly referenced via the build_dependencies of a package.
Deep Dependency:
 External dependency referenced via the build_dependencies of a package dependency (or by reaching down dependency tree as far as necessary).

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.

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.8;

contract Owned {
    address owner;
    
    modifier onlyOwner { require(msg.sender == owner); _; }

    constructor() public {
        owner = msg.sender;
    }
}
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","meta":{"authors":["Piper Merriam <pipermerriam@gmail.com>"],"description":"Reusable contracts which implement a privileged 'owner' model for authorization.","keywords":["authorization"],"license":"MIT","links":{"documentation":"ipfs://QmUYcVzTfSwJoigggMxeo2g5STWAgJdisQsqcXHws7b1FW"}},"package_name":"owned","sources":{"./contracts/Owned.sol":"ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGV"},"version":"1.0.0"}

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.

Dependent Package with an Inheritable Contract

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.

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.8;

import {Owned} from "owned/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.

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

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

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.8;


/// @title Safe Math Library
/// @author Piper Merriam <pipermerriam@gmail.com>
library SafeMathLib {
    /// @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 safeAdd(uint256 a, uint256 b) public pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
    }

    /// @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 safeSub(uint256 a, uint256 b) public pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }
}

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.

Dependent Package with a Reusable Contract

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

{"build_dependencies":{"standard-token":"ipfs://QmVu9zuza5mkJwwcFdh2SXBugm1oSgZVuEKkph9XLsbUwg"},"deployments":{"blockchain://41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d/block/4803939cf88aaf46fb7c9fb771cda4e4072c6c5fe3aaad1860f7064ef18f50b9":{"PiperCoin":{"address":"0xC70871869Ff35e9d08e650b49F23891DB462F181","block":"0xb21dda724b6f14bcdde1db9703a5c1bfb088763acdb725be2429c1ef8ce0a4e1","compiler":{"name":"solc","settings":{"optimize":true},"version":"0.4.24+commit.e67f0147.Emscripten.clang"},"contract_type":"standard-token:StandardToken","deployment_bytecode":{"bytecode":"0x608060405234801561001057600080fd5b5060405160208061045383398101604081815291516002819055336000818152602081815285822084905583855294519294919390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3506103d2806100816000396000f3006080604052600436106100775763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663095ea7b3811461007c57806318160ddd146100b457806323b872dd146100db57806370a0823114610105578063a9059cbb14610126578063dd62ed3e1461014a575b600080fd5b34801561008857600080fd5b506100a0600160a060020a0360043516602435610171565b604080519115158252519081900360200190f35b3480156100c057600080fd5b506100c96101d8565b60408051918252519081900360200190f35b3480156100e757600080fd5b506100a0600160a060020a03600435811690602435166044356101de565b34801561011157600080fd5b506100c9600160a060020a03600435166102c9565b34801561013257600080fd5b506100a0600160a060020a03600435166024356102e4565b34801561015657600080fd5b506100c9600160a060020a036004358116906024351661037b565b336000818152600160209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60025481565b600160a060020a03831660009081526020819052604081205482118015906102295750600160a060020a03841660009081526001602090815260408083203384529091529020548211155b80156102355750600082115b156102be57600160a060020a0380841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060016102c2565b5060005b9392505050565b600160a060020a031660009081526020819052604090205490565b3360009081526020819052604081205482118015906103035750600082115b15610373573360008181526020818152604080832080548790039055600160a060020a03871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35060016101d2565b5060006101d2565b600160a060020a039182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820cf9d6a3f751ca1e6b9bc2324e42633a4cde513d64c3e6cc32d6359629249e90200290000000000000000000000000000000000000000000000000000000000000001"},"runtime_bytecode":{"bytecode":"0x6080604052600436106100775763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663095ea7b3811461007c57806318160ddd146100b457806323b872dd146100db57806370a0823114610105578063a9059cbb14610126578063dd62ed3e1461014a575b600080fd5b34801561008857600080fd5b506100a0600160a060020a0360043516602435610171565b604080519115158252519081900360200190f35b3480156100c057600080fd5b506100c96101d8565b60408051918252519081900360200190f35b3480156100e757600080fd5b506100a0600160a060020a03600435811690602435166044356101de565b34801561011157600080fd5b506100c9600160a060020a03600435166102c9565b34801561013257600080fd5b506100a0600160a060020a03600435166024356102e4565b34801561015657600080fd5b506100c9600160a060020a036004358116906024351661037b565b336000818152600160209081526040808320600160a060020a038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b60025481565b600160a060020a03831660009081526020819052604081205482118015906102295750600160a060020a03841660009081526001602090815260408083203384529091529020548211155b80156102355750600082115b156102be57600160a060020a0380841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060016102c2565b5060005b9392505050565b600160a060020a031660009081526020819052604090205490565b3360009081526020819052604081205482118015906103035750600082115b15610373573360008181526020818152604080832080548790039055600160a060020a03871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35060016101d2565b5060006101d2565b600160a060020a039182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820cf9d6a3f751ca1e6b9bc2324e42633a4cde513d64c3e6cc32d6359629249e9020029"},"transaction":"0x93f6c5fbdb4c62f1bff8bace3ec2f80267b6cdd3710c36f9b1445031175d9f6f"}}},"manifest_version":"2","package_name":"piper-coin","version":"1.0.0"}

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.

Stand Alone Package with a Deployed Contract Linked against a Deployed Library

In the previous safe-math-lib package we demonstrated what a package with a deployed instance of one of it’s local contracts looks like. In this example we will build on that concept with a package which includes a library and a contract which uses that library as well as deployed instances of both.

The package will be called escrow and will implementing a simple escrow contract. The escrow contract will make use of a library to safely send ether. Both the contract and library will be part of the package found in the following two solidity source files.

The full source for these files can be found here: ./examples/escrow/.

The Package is listed below with some sections truncated for improved readability. The full Package can be found at ./examples/escrow/1.0.0.json

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "escrow",
  "sources": {
    "./contracts/SafeSendLib.sol": "ipfs://QmcnzhWjaV71qzKntv4burxyix9W2yBA2LrJB4k99tGqkZ",
    "./contracts/Escrow.sol": "ipfs://QmSwmFLT5B5aag485ZWvHmfdC1cU5EFdcqs1oqE5KsxGMw"
  },
  "contract_types": {
    "SafeSendLib": {
      "...": "..."
    },
    "Escrow": {
      "...": "..."
    }
  },
  "deployments": {
    "blockchain://41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d/block/e76cf1f29a4689f836d941d7ffbad4e4b32035a441a509dc53150c2165f8e90d": {
      "SafeMathLib": {
        "contract_type": "SafeSendLib",
        "address": "0x80d7f7a33e551455a909e1b914c4fd4e6d0074cc",
        "transaction": "0x74561167f360eaa20ea67bd4b4bf99164aabb36b2287061e86137bfa0d35d5fb",
        "block": "0x46554e3cf7b768b1cc1990ad4e2d3a137fe9373c0dda765f4db450cd5fa64102"
      },
      "Escrow": {
        "contract_type": "Escrow",
        "address": "0x35b6b723786fd8bd955b70db794a1f1df56e852f",
        "transaction": "0x905fbbeb6069d8b3c8067d233f58b0196b43da7a20b839f3da41f69c87da2037",
        "block": "0x9b39dcab3d665a51755dedef56e7c858702f5817ce926a0cd8ff3081c5159b7f",
        "runtime_bytecode": {
          "link_dependencies": [
            {
              "offsets": [
                262,
                412
              ],
              "type": "reference",
              "value": "SafeSendLib"
            }
          ]
        }
      }
    }
  }
}

This Package is the first one we’ve seen thus far that include the link_dependencies section within one of the Contract Instances. The runtime_bytecode value for the Escrow contract has been excluded from the example above for readability, but the full value is as follows (wrapped to 80 characters).

0x606060405260e060020a600035046366d003ac811461003457806367e404ce1461005d5780636
9d8957514610086575b610000565b3461000057610041610095565b60408051600160a060020a03
9092168252519081900360200190f35b34610000576100416100a4565b60408051600160a060020
a039092168252519081900360200190f35b34610000576100936100b3565b005b600154600160a0
60020a031681565b600054600160a060020a031681565b60005433600160a060020a03908116911
6141561014857600154604080516000602091820152815160e260020a6324d048c7028152600160
a060020a03938416600482015230909316316024840152905173000000000000000000000000000
000000000000092639341231c926044808301939192829003018186803b156100005760325a03f4
1561000057506101e2915050565b60015433600160a060020a039081169116141561002f5760008
05460408051602090810193909352805160e260020a6324d048c7028152600160a060020a039283
1660048201523090921631602483015251730000000000000000000000000000000000000000926
39341231c9260448082019391829003018186803b156100005760325a03f41561000057506101e2
915050565b610000565b5b5b56

This bytecode is unlinked, meaning it has missing portions of data, populated instead with zeroes (0000000000000000000000000000000000000000). This section of zeroes is referred to as a Link Reference. The entries in the link_dependencies section of a Contract Instance describe how these link references should be filled in.

The offsets value specifies the locations (as byte offset) where the replacement should begin. The value defines what should be used to replace the link reference. In this case, the value is referencing the SafeSendLib contract instance from this Package.

Dependent Package with a Deployed Contract Linked against a Package Dependency

Now that we’ve seen how we can handle linking dependencies that rely on deployed Contract Instances from the local package we’ll explore an example with link dependencies that rely on contracts from the package dependencies.

In this example we’ll be writing the wallet package which includes a wallet contract which makes use of the previous safe-math-lib package. We will also make use of the owned package from our very first example to handle authorization. Our package will contain a single solidity source file ./contracts/Wallet.sol, shown below.

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.8;


import {SafeMathLib} from "./safe-math-lib/SafeMathLib.sol";
import {Owned} from "./owned/Owned.sol";


/// @title Contract for holding funds in escrow between two semi trusted parties.
/// @author Piper Merriam <pipermerriam@gmail.com>
contract Wallet is Owned {
    using SafeMathLib for uint;

    mapping (address => uint) allowances;

    /// @dev Fallback function for depositing funds
    fallback() external {
    }

    /// @dev Sends the recipient the specified amount
    /// @notice This will send the reciepient the specified amount.
    function send(address payable recipient, uint value) public onlyOwner returns (bool) {
        return recipient.send(value);
    }

    /// @dev Sets recipient to be approved to withdraw the specified amount
    /// @notice This will set the recipient to be approved to withdraw the specified amount.
    function approve(address recipient, uint value) public onlyOwner returns (bool) {
        allowances[recipient] = value;
        return true;
    }

    /// @dev Lets caller withdraw up to their approved amount
    /// @notice This will withdraw provided value, deducting it from your total allowance.
    function withdraw(uint value) public returns (bool) {
        allowances[msg.sender] = allowances[msg.sender].safeSub(value);
        if (!msg.sender.send(value))
            revert();
        return true;
    }
}

The Package for our wallet package can been seen below. It has been trimmed to improve readability. The full Package can be found at ./examples/wallet/1.0.0.json

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "wallet",
  "sources": {
    "./contracts/Wallet.sol": "ipfs://QmYKibsXPSTR5UjywQHX8SM4za1K3QHadtFGWmZqGA4uE9"
  },
  "contract_types": {
    "Wallet": {
      "deployment_bytecode": {
        "...": "..."
      },
      "runtime_bytecode": {
        "...": "..."
      },
      "...": "..."
    }
  },
  "deployments": {
    "blockchain://41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d/block/3ececfa0e03bce2d348279316100913c42ca2dcd51b8bc8d2d87ef2dc6a479ff": {
      "Wallet": {
        "contract_type": "Wallet",
        "address": "0xcd0f8d7dab6c682d3726693ef3c7aaacc6431d1c",
        "transaction": "0x5c113857925ae0d866341513bb0732cd799ebc1c18fcec253bbc41d2a029acd4",
        "block": "0xccd130623ad3b25a357ead2ecfd22d38756b2e6ac09b77a37bd0ecdf16249765",
        "runtime_bytecode": {
          "link_dependencies": [
            {
              "offsets": [
                340
              ],
              "type": "reference",
              "value": "safe-math-lib:SafeMathLib"
            }
          ]
        }
      }
    }
  },
  "build_dependencies": {
    "owned": "ipfs://QmUwVUMVtkVctrLDeL12SoeCPUacELBU8nAxRtHUzvtjND",
    "safe-math-lib": "ipfs://QmfUwis9K2SLwnUh62PDb929JzU5J2aFKd4kS1YErYajdq"
  }
}

Just like our previous example, the runtime_bytecode has been omitted for improved readability, but the full value is as follows (wrapped to 80 characters).

0x606060405236156100355760e060020a6000350463095ea7b381146100435780632e1a7d4d146
1006a578063d0679d341461008e575b34610000576100415b5b565b005b34610000576100566004
356024356100b5565b604080519115158252519081900360200190f35b346100005761005660043
56100f8565b604080519115158252519081900360200190f35b3461000057610056600435602435
6101da565b604080519115158252519081900360200190f35b6000805433600160a060020a03908
1169116146100d157610000565b50600160a060020a038216600090815260016020819052604090
91208290555b5b92915050565b600160a060020a033316600090815260016020908152604080832
0548151830184905281517fa293d1e8000000000000000000000000000000000000000000000000
0000000081526004810191909152602481018590529051730000000000000000000000000000000
0000000009263a293d1e89260448082019391829003018186803b156100005760325a03f4156100
00575050604080518051600160a060020a033316600081815260016020529384209190915592508
4156108fc0291859190818181858888f1935050505015156101d157610000565b5060015b919050
565b6000805433600160a060020a039081169116146101f657610000565b604051600160a060020
a0384169083156108fc029084906000818181858888f19450505050505b5b9291505056

As you can see, this bytecode contains missing link references, in this case to the SafeMathLib library from the safe-math-lib package dependency. If you look in the link_dependencies section of our Wallet contract you’ll see it’s items are similar to the ones from our previous example.

{
  "link_dependencies": [
    {
      "offsets": [
        340
      ],
      "type": "reference",
      "value": "safe-math-lib:SafeMathLib"
    }
  ]
}

However, unlike the previous example which linked against a local contract type, value portion is prefixed with the name of the package which contains the address of the contract instance that this should be linked against.

Dependent Package with a Deployed Contract Linked against a Deep Dependency

In the previous example we saw how link dependencies against direct package dependencies are handled. In this example we will look at how this works when the link dependency is against a package deeper in the dependency tree.

This package will contain a single solidity source file ./contracts/WalletWithSend.sol which extends our previous Wallet contract, adding a new approvedSend function.

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.8;


import {Wallet} from "./wallet/Wallet.sol";


/// @title Wallet contract with simple send and approval spending functionality
/// @author Piper Merriam <pipermerriam@gmail.com>
contract WalletWithSend is Wallet {
    /// @dev Sends funds that have been approved to the specified address
    /// @notice This will send the reciepient the specified amount.
    function approvedSend(uint value, address payable to) public {
        allowances[msg.sender] = allowances[msg.sender].safeSub(value);
        if (!to.send(value))
            revert();
    }
}

This new approvedSend function allows spending an address’s provided allowance by sending it to a specified address.

The Package for our wallet-with-send package can been seen below. It has been trimmed to improve readability. The full Package can be found at ./examples/wallet-with-send/1.0.0.json

{
  "manifest_version": "2",
  "version": "1.0.0",
  "package_name": "wallet-with-send",
  "sources": {
    "./contracts/WalletWithSend.sol": "ipfs://QmWAKLzXaxES3tszDXDPP9xvf7xqsB9FU3W7MtapQ47naU"
  },
  "contract_types": {
    "WalletWithSend": {
      "deployment_bytecode": {
        "...": "..."
      },
      "runtime_bytecode": {
        "...": "..."
      },
      "...": "..."
    }
  },
  "deployments": {
    "blockchain://41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d/block/bfb631d770940a93296e9b93f034f9f920ae311a8b37acd57ff0b55605beee73": {
      "Wallet": {
        "contract_type": "WalletWithSend",
        "address": "0x7817d93f681a72758335398913136069c945d34b",
        "transaction": "0xe37d5691b58472f9932545d1d44fc95463a69adb1a3da5b06da2d9f3ff5c2939",
        "block": "0x5479e2f948184e13581d13e6a3d5bd5e5263d898d4514c5ec6fab37e2a1e9d6c",
        "runtime_bytecode": {
          "link_dependencies": [
            {
              "offsets": [
                383,
                587
              ],
              "type": "reference",
              "value": "wallet:safe-math-lib:SafeMathLib"
            }
          ]
        }
      }
    }
  },
  "build_dependencies": {
    "wallet": "ipfs://QmSg2QvGhQrYgQqbTGVYjGmF9hkEZrxQNmSXsr8fFyYtD4"
  }
}

The important part of this Package is the link_dependencies section.

{
  "link_dependencies": [
    {
      "offsets": [
        383,
        587
      ],
      "type": "reference",
      "value": "wallet:safe-math-lib:SafeMathLib"
    }
  ]
}

The value portion here means that the bytecode for this contract is linked against the SafeMathLib deployed instance from the safe-math-lib dependency from the wallet dependency of this package. This defines the traversal path through the dependency tree to the deployed instance of the SafeMathLib library which was used for linking during deployment.