Files
openzeppelin-contracts/docs/tokens.md
Francisco Giordano e41daba7b4 merge api docs changes
Squashed commit of the following:

commit 06243c3e8e86074ff8e9e3f22b7829a2c315d707
Merge: 991882ec 99373558
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 18:15:37 2019 -0300

    Merge branch 'api-docs' into api-docs-merge

commit 991882eca5bb8a3391995154bfb9d53d8a69cb4f
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 18:08:02 2019 -0300

    manually apply docs changes and renamings

commit fa1f6e97dd67a76c3cd828d0a5e19b4ac6c37acb
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 17:36:03 2019 -0300

    move functions to new order

commit 99373558e3af4905d29bc6f3f542ba93d28a24ab
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 16:23:40 2019 -0300

    add missing docs links

commit d180d6c36a6f5460e85473ee5a18992d1449a6ff
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 16:14:12 2019 -0300

    update solidity-docgen dependency

    fixes uri encoded links

commit faab0e50da91cd2f0a409e3ad32e2db127ad319a
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 16:05:03 2019 -0300

    update openzeppelin-docsite and solidity-docgen dependencies

    add visibility specifiers

commit ef305268bb2735e488e35d16819a4b432b3a35e3
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Thu May 23 15:36:45 2019 -0300

    Fix guide links.

commit 339b20dbfa2d5f6ea02e63c2f3fdcba0fe879c3c
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Thu May 23 13:37:51 2019 -0300

    Fix typos.

commit 6c7b97460578b9eea90b53c280454e361f8f0052
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 15:26:29 2019 -0300

    fix utilities guide links

commit 0e7692a8fd8516a11becc4121d77d792439600b1
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 15:23:19 2019 -0300

    update solidity-docgen dependency

commit ebb8a8651516ece21736c6c3b2577eb1b3487651
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 15:15:01 2019 -0300

    fix utilities guide links

commit 5ec47d62785e1d6e5f8e91edca58f2dc7f87d7a3
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 15:14:49 2019 -0300

    fix escrow docs ordering

commit cdcdc909b16f219a9a3272036b6a8f21e34b48ef
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 13:35:07 2019 -0300

    add wip notice

commit 987e2951ae93211c8c70c8288e30573555c57830
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 13:09:35 2019 -0300

    update openzeppelin-docsite dependency

    fixes links to old versions

commit b00d22c0affac2e2108df8b773dfa1706afcb44e
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 23 13:09:28 2019 -0300

    fix guide links

commit f112a9400c5e5ad495c8e0fdb972e26987b34244
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 20:42:37 2019 -0300

    update docsite

commit 68aacdd56a29e35a84f6732f9293612bbcaf7520
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Wed May 22 20:00:39 2019 -0300

    ERC20Capped

commit 4edce78bab2c6d140f3ea3f33db71e92ca4d8aaf
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Wed May 22 19:52:30 2019 -0300

    Unnecessary polish on token docs.

commit 2a4c91cf49c2736dc09c1c03cf383911def1a1b2
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 19:20:05 2019 -0300

    rename guides

commit 61dd818ea76d4c170c4ab175c6be0d6067d21a29
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Wed May 22 17:04:09 2019 -0300

    ERC1820 docs.

commit 77b5f0353123b76358dc6d86bdc646c86c9b0bea
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Wed May 22 16:17:34 2019 -0300

    Introspection and ERC165.

commit 76641a253b3b70279802c5134dd107532eea4b2c
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 17:59:53 2019 -0300

    update docgen

commit 7be98bc3fbd3566231f943f01b9acb58567d755b
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 17:23:50 2019 -0300

    update solidity-docgen

commit f7268e6e010f8ef9ac83df241a803f91efc08c0c
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 16:58:31 2019 -0300

    update docgen

commit 2a8c7a378e8962a5baeb334b2492815f05075f98
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Wed May 22 14:36:35 2019 -0300

    Util docs.

commit 327ae8ff45a1a523c7591bf4996c4a9b52d7ec7a
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 13:08:50 2019 -0300

    add missing drafts

commit 5e7f71335ac8423c0e363ae8c7ad9b2977f202f8
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 12:47:41 2019 -0300

    tweak ierc20 docs

commit cd0e86a0b712f74ffd406e072d4b1fbf4dd2c176
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 12:46:45 2019 -0300

    add some erc721 docs

commit e081184159417f71da14bc0fc110b7b11e29d75d
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 12:41:46 2019 -0300

    update docsite

commit 0beb75784022419d47123c2a9fe7a5f1eb87f9b2
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 12:22:27 2019 -0300

    correct drafts structure

commit 2e94b287c7cead7a6c0603205670566461c31abb
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 11:56:25 2019 -0300

    fix docsite-start script

commit 0fa4160484309d0851584fe57c0d81a3600977db
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 11:47:44 2019 -0300

    improve docsite start script (automatically watch docgen)

commit 9d571897cc03bee92035964cf7a2cfeda1e2f690
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 22 11:30:37 2019 -0300

    update solidity-docgen

commit 82980f5aefbdfb8a9815a3b7b0e88e970b65dd5d
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue May 21 19:15:13 2019 -0300

    edit docs for Secondary

commit 00d7a005b0530bee730b77a1b69a95f1b4ffe315
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue May 21 19:15:13 2019 -0300

    edit docs for ownable

commit b0c4c2bdf83eca5d4a71792daac603236733d46e
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue May 21 18:27:13 2019 -0300

    change title of Math section

commit deb788583f191780e55b7f673520eaf13a5c7e23
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue May 21 18:26:59 2019 -0300

    capitalization

commit f2bcf85d343ea4a0739fe22a77b1e22c2296ddea
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue May 21 18:26:06 2019 -0300

    edit docs for Pausable

commit 73ba0cf43dbb44c39c1bf2ee63ef9fe558faa919
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Sat May 18 19:08:06 2019 -0300

    Crypto docs.

commit 9d6fc6223f51cf2321b2e3217c512579654c3917
Merge: 7e21f8f7 9f1cec12
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Fri May 17 17:23:15 2019 -0300

    Merge branch 'api-docs-777' into api-docs

commit 9f1cec12e3351fb1b5fc0b59f5ded39928064a56
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Fri May 17 17:22:54 2019 -0300

    ERC777 done.

commit 7e21f8f7b6982d2f92df302cdf6ec62522d8ffff
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Fri May 17 16:39:47 2019 -0300

    add math docs

commit f18d1f17023b6e5b42ae04fc38aa1170e6863864
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Thu May 16 20:01:46 2019 -0300

    First draft of ERC777 docs.

commit 985c5d3053
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Thu May 16 19:14:32 2019 -0300

    Final draft for IERC777.

commit bf53f133d987b67f938a329e6d659ba3483aab0b
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 16 19:13:37 2019 -0300

    more work on ERC20 api docs

commit b7c250b7cb
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Thu May 16 17:08:47 2019 -0300

    Fix typo.

commit 197bbfbfc6
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Thu May 16 17:05:14 2019 -0300

    Initial draft of IERC777.

commit 7dc3b55161c860437a8f13a2ce5808b1c3dd70a2
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Thu May 16 11:58:32 2019 -0300

    add payment docs structure

commit da16fc4480
Author: Nicolás Venturo <nicolas.venturo@gmail.com>
Date:   Thu May 16 16:05:33 2019 -0300

    Initial ERC777 docstrings.

commit 9f6a7e35bd
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed May 15 22:13:17 2019 -0300

    partial pass through ERC20 docs

(cherry picked from commit 2f9ae975c8)
2019-05-23 18:24:31 -03:00

10 KiB

id, title
id title
tokens Tokens

Ah, the "token": the world's most powerful and most misused tool. In this section we'll learn to harness the power of native units of account for good and world peace!

But First, Coffee a Primer on Tokens

Simply put, a token isn't anything special. In Ethereum, pretty much everything is a contract, and that includes what we call tokens. "Sending a token" is the same as "calling a method on a smart contract that someone wrote and deployed". And, at the end of the day, a token is just a mapping of addresses to balances and some nice methods to add and subtract from those balances.

That's it! These balances could be considered money, or they could be voting rights or they could be experience points in your game.

Even though the concept of a token is simple, they have a variety of complexities in the implementation. Because everything in Ethereum is just a smart contract, and there are no rules about what smart contracts have to do, the community has developed a variety of standards (called EIPs or ERCs) for documenting how a contract can interoperate with other contracts.

You've probably heard of the ERC20 standard, and that's why you're here.

ERC20

An ERC20 token is a contract that keeps track of a mapping(address => uint256) that represents a user's balance. These tokens are fungible in that any one token is exactly equal to any other token; no tokens have special rights or behavior associated with them. This makes ERC20 useful for things like a medium of exchange currency, general voting rights, staking, and more.

OpenZeppelin provides a few different ERC20-related contracts. Here are the core contracts you'll almost definitely be using:

  • IERC20 — defines the interface that all ERC20 token implementations should conform to
  • ERC20 — the base implementation of the ERC20 interface
  • ERC20Detailed — the name(), symbol(), and decimals() getters are optional in the original standard, so ERC20Detailed adds that information to your token.

After that, OpenZeppelin provides a few extra properties that you may want depending on your use-case:

  • ERC20MintableERC20Mintable allows users with the MinterRole to call the mint() function and mint tokens to users.
  • ERC20Burnable — if your token can be burned (aka, it can be destroyed), include this one.
  • ERC20CappedERC20Capped is a type of ERC20Mintable that enforces a maximum cap on tokens; this is really useful if you want to ensure network participants that there will always be a maximum number of tokens, and is useful for making sure that multiple different minting methods don't accidentally create more tokens than you expected.
  • ERC20PausableERC20Pausable allows anyone with the Pauser role to pause the token, freezing transfers to and from users. This is useful if you want to stop trades until the end of a crowdsale, or if you want to have an emergency switch for freezing your tokens in the event of a large bug. Note that there are inherent decentralization tradeoffs when using a pausable token; users may not expect that their unstoppable money can be frozen by a single address!

Finally, if you're working with ERC20 tokens, OpenZeppelin provides some utility contracts:

  • SafeERC20 — provides safeTransfer, safeTransferFrom, and safeApprove that are helpful wrappers around the normal ERC20 functions. Using SafeERC20 forces transfers and approvals to succeed, or the entire transaction is reverted.
  • TokenTimelock — is an escrow contract for ERC20 tokens that will release some tokens after a specified timeout. This is useful for simple vesting schedules like "advisors get all of their tokens after 1 year". For a better vesting schedule, though, see TokenVesting

Constructing a Nice ERC20 Token

Now that we know what all of the contracts do (you should read the code! It's open source!), we can make our ERC20 token that will revolutionize dogsitting by reducing human beings to organic machines that act entirely based on rational monetary incentives, fueled by the DOGGO token.

Here's what a good DOGGO token might look like.

contract DoggoToken is ERC20, ERC20Detailed, ERC20Mintable, ERC20Burnable {

    constructor(
        string memory name,
        string memory symbol,
        uint8 decimals
    )
        ERC20Burnable()
        ERC20Mintable()
        ERC20Detailed(name, symbol, decimals)
        ERC20()
        public
    {}
}

ERC20Mintable allows to add minters via addMinter(addr), so they (like the DOGGO Network multisig) can mint tokens to the dogsitters in exchange for watching the nice doggos while their owners leave for vacation. The token is ERC20Burnable we want to have the ability to stake DOGGO tokens on our reputation—if the dogsitter does a bad job, their tokens get burned!

A Note on decimals

You might remember from the previous chapter about crowdsales about how math is performed in financial situations: all currency math is done in the smallest unit of that currency.

That means that the totalSupply of a token is actually in what we call TKNbits, not what you see as TKN. So if my total supply is 1 and we have 5 decimals in the token, that's actually 1 TKNbit and will be displayed as 0.00001 TKN.

You probably want to use a decimals of 18, just like Ether, unless you have a special reason not to, so when you're minting tokens to people or transferring them around, you're actually sending the number numTKN * 10^(decimals). So if I'm sending you 5 tokens using a token contract with 18 decimals, the method I'm executing actually looks like transfer(yourAddress, 5 * 10^18).

ERC721

We've discussed how you can make a fungible token using ERC20, but what if not all tokens are alike? This comes up in situations like company stock; some stock is common stock and some stock is investor shares, etc. It also comes up in a bunch of other places like in-game items, time, property, and so on.

ERC721 is a standard for representing ownership that is non-fungible aka, each token has unique properties.

Let's see what contracts OpenZeppelin provides for helping us work with ERC721:

  • The IERC721, IERC721Metadata, IERC721Enumerable contracts document the interfaces.
  • ERC721 — is the full implementation of ERC721, and the contract you'll most likely be inheriting from.
  • IERC721Receiver — in some cases, it's beneficial to be 100% certain that a contract knows how to handle ERC721 tokens (imagine sending an in-game item to an exchange address that can't send it back!). When using safeTransferFrom(), the contract checks to see that the receiver is an IERC721Receiver, which implies that it knows how to handle ERC721 tokens. If you're writing a contract that accepts ERC721 tokens, you'll want to implement this interface.
  • ERC721Mintable — like the ERC20 version, ERC721Mintable allows addresses with the Minter role to mint tokens.
  • ERC721Pausable — like the ERC20 version, ERC721Pausable allows addresses with the Pauser role to freeze transfers of tokens.

We'll use these contracts to tokenize the time of our dogsitters: when a dogsitter wants to sell an hour of their time to watch a dog, they can mint an ERC721 token that represents that hour slot and then sell this token on an exchange. Then they'll go to the owner's house at the right time to watch their doggos.

Here's what tokenized dogsitter timeframes might look like:

contract DoggoTime is ERC721Full {
    using Counters for Counters.Counter;
    Counters.Counter private tokenId;

    constructor(
        string memory name,
        string memory symbol
    )
        ERC721Full(name, symbol)
        public
    {}

    function createDoggoTimeframe(
        string memory tokenURI
    )
        public
        returns (bool)
    {
        tokenId.increment();
        uint256 doggoTokenId = tokenId.current();
        _mint(msg.sender, doggoTokenId);
        _setTokenURI(doggoTokenId, tokenURI);
        return true;
    }
}```

Now anyone who wants to sell their time in exchange for DOGGO tokens can call:

```solidity
DoggoTime(doggoTimeAddress).createDoggoTimeframe("https://example.com/doggo.json")

where the tokenURI should resolve to a json document that might look something like:

{
    "name": "Alex's DOGGO Dogsitting Time — 1 Hour on Thursday the 5th at 6pm",
    "description": "Alex agrees to dog sit for 1 hour of her time on Thursday the 5th at 6pm.",
    "image": "https://example.com/doggo-network.png"
}

For more information about tokenURI metadata, check out the finalized ERC721 spec.

Note: you'll also notice that the date information is included in the metadata, but that information isn't on-chain! So Alex the dogsitter could change the time and scam some people out of their money! If you'd like to put the dates of the dogsitting hours on-chain, you can extend ERC721 to do so. You could also leverage IPFS to pin the tokenURI information, which lets viewers know if Alex has changed the metadata associated with her tokens, but these techniques are out of the scope of this overview guide.