Unverified Commit ed5652b0 by Francisco Giordano Committed by GitHub

New documentation setup (#1708)

* initial docsite setup

* switch from pushd to cd

* install and set up solidity-docgen

* use the docsite branch next for now

* make it clear that env var is a repository

* add a clarifying comment about a relative path

* change relative to absolute path in docsite script

* add docgen script

* add first few READMEs for contract documentation

* update solidity-docgen

* add docsite as dependency and adjust script

* update openzeppelin-docsite

* update solidity-docgen

* remove dummy text

* update docgen and docsite

* update openzeppelin-docsite

* add netlify.toml

* udpate tokens guide for 2.2

* add DOCUMENTATION.md

* Update docs/learn-about-utilities.md

Co-Authored-By: frangio <frangio.1@gmail.com>

* fix PaymentSplitter docs wording

* update solidity-docgen

* add missing ERC20 contracts

* update solidity-docgen

* trigger deploy with cleared cache

* update solidity-docgen

* update openzeppelin-docsite

* remove travis docs setup

* update openzeppelin-docsite

* switch to published solidity-docgen
parent 412cdfd0
...@@ -40,3 +40,7 @@ build/ ...@@ -40,3 +40,7 @@ build/
# IntelliJ IDE # IntelliJ IDE
.idea .idea
# docsite artifacts
docsite-build
docs/api
...@@ -35,15 +35,6 @@ jobs: ...@@ -35,15 +35,6 @@ jobs:
script: npm run test script: npm run test
env: SOLC_NIGHTLY=true env: SOLC_NIGHTLY=true
- stage: update docs
if: tag =~ ^v[0-9]+\.[0-9]+\.[0-9]+$
addons:
apt:
packages:
- curl
script:
- ./scripts/ci/trigger_docs_update "${TRAVIS_TAG}"
notifications: notifications:
slack: slack:
rooms: rooms:
......
We're building an improved documentation website. It's still in development and
contributions will be really appreciated.
All of the content for the site is in this repository. The guides are in the
[docs](/docs) directory, and the API Reference is extracted from comments in
the source code. If you want to help improve the content, this is the
repository you should be contributing to.
[`solidity-docgen`](https://github.com/OpenZeppelin/solidity-docgen/tree/next) is the
program that extracts the API Reference from source code.
The [`openzeppelin-docsite`](https://github.com/OpenZeppelin/openzeppelin-docsite/tree/next)
repository hosts the configuration for Docusaurus, the static site generator
that we use.
To run the docsite locally you should run `npm run docsite start` on this
repository. This will live reload as the guides are edited, but not with
changes to the source code comments, for that you need to restart the server.
This should be improved eventually (contributions welcome!).
---
sections:
- title: Library
contracts:
- Roles
- subdirectory: roles
---
---
title: Crowdsales
sections:
- title: Core
contracts:
- Crowdsale
- subdirectory: emission
- subdirectory: price
- subdirectory: validation
- subdirectory: distribution
---
...@@ -5,7 +5,7 @@ import "../math/SafeMath.sol"; ...@@ -5,7 +5,7 @@ import "../math/SafeMath.sol";
/** /**
* @title PaymentSplitter * @title PaymentSplitter
* @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware
* that the Ether will be split in this way, since it is handled purely by the contract. * that the Ether will be split in this way, since it is handled transparently by the contract.
* *
* The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each
* account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim
......
---
sections:
- title: Interfaces
contracts:
- IERC20
- title: Contracts
contracts:
- ERC20
- ERC20Detailed
- ERC20Mintable
- ERC20Burnable
- ERC20Capped
- ERC20Pausable
- title: Utilities
contracts:
- SafeERC20
- TokenTimelock
---
---
id: get-started
title: Get Started
---
OpenZeppelin can be installed directly into your existing node.js project with `npm install --save-exact openzeppelin-solidity`, but OpenZeppelin also integrates directly with [Truffle](https://github.com/ConsenSys/truffle), an Ethereum development environment, which we'll use to get started.
Please install Truffle and initialize your project:
```sh
$ npm install -g truffle
$ mkdir myproject && cd myproject
$ truffle init
```
To install the OpenZeppelin library, run the following in your Solidity project root directory:
```sh
$ npm init -y
$ npm install --save-exact openzeppelin-solidity
```
**Note that OpenZeppelin only lightly follows semantic versioning.** You may encounter breaking changes upon a minor version bump. We recommend pinning the version of OpenZeppelin you use by using the `--save-exact` option.
After that, you'll get all the library's contracts in the `node_modules/openzeppelin-solidity/contracts` folder. Because Truffle and other Ethereum development toolkits understand `node_modules`, you can use the contracts in the library like so:
```js
import 'openzeppelin-solidity/contracts/ownership/Ownable.sol';
contract MyContract is Ownable {
...
}
```
## Next Steps
After installing OpenZeppelin, check out the rest of the guides in the sidebar to learn about the different contracts that OpenZeppelin provides and how to use them.
- [Learn About Access Control](/api/docs/learn-about-access-control.html)
- [Learn About Crowdsales](/api/docs/learn-about-crowdsales.html)
- [Learn About Tokens](/api/docs/learn-about-tokens.html)
- [Learn About Utilities](/api/docs/learn-about-utilities.html)
You may also want to take a look at the guides which cover several common use cases and good practices: https://blog.zeppelin.solutions/guides/home
For example, [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.zeppelin.solutions/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment.
[A Gentle Introduction to Ethereum Programming, Part 1](https://blog.zeppelin.solutions/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform.
For a more in-depth dive, you may read the guide [Designing the architecture for your Ethereum application](https://blog.zeppelin.solutions/designing-the-architecture-for-your-ethereum-application-9cec086f8317), which discusses how to better structure your application and its relationship to the real world.
You may also ask for help or follow OpenZeppelin's progress in the community [forum](https://forum.zeppelin.solutions), or read OpenZeppelin's full API on this website.
---
id: learn-about-access-control
title: Learn About Access Control
---
Access control—that is, "who is allowed to do this thing"—is incredibly important in the world of smart contracts. The access control of your contract governs who can mint tokens, who can vote on proposals, who can [`selfdestruct()`](https://blog.zeppelin.solutions/on-the-parity-wallet-multisig-hack-405a8c12e8f7) the contract, and more, so it's very important to understand how you implement it.
## Ownership & Ownable.sol
The most common and basic form of access control is the concept of _ownership_: there's one account that is the `owner` and can do administrative tasks on contracts. This approach is perfectly reasonable for contracts that only have a single administrative user.
OpenZeppelin provides [contracts/ownership/Ownable.sol](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Ownable.sol) for implementing ownership in your contracts.
```solidity
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
contract MyContract is Ownable {
function normalThing()
public
{
// anyone can call this normalThing()
}
function specialThing()
public
onlyOwner
{
// only the owner can call specialThing()!
}
}
```
By default, the `owner` of an `Ownable` contract is the `msg.sender` of the contract creation transaction, which is usually exactly what you want.
Ownable also lets you:
+ `transferOwnership(address newOwner)` to transfer ownership from one account to another
+ `renounceOwnership()` to remove the owner altogether, useful for decentralizing control of your contract. **⚠ Warning!** Removing the owner altogether will mean that administrative tasks that are protected by `onlyOwner` will no longer be callable!
Note that any contract that supports sending transactions can also be the owner of a contract; the only requirement is that the owner has an Ethereum address, so it could be a Gnosis Multisig or Gnosis Safe, an Aragon DAO, an ERC725/uPort identity contract, or a totally custom contract that _you_ create.
In this way you can use _composability_ to add additional layers of access control complexity to your contracts. Instead of having a single Ethereum Off-Chain Account (EOA) as the owner, you can replace them with a 2/3 multisig run by your project leads, for example.
### Examples in OpenZeppelin
You'll notice that none of the OpenZeppelin contracts use Ownable, though! This is because there are more flexible ways of providing access control that are more in-line with our reusable contract philosophy. For most contracts, We'll use `Roles` to govern who can do what. There are some cases, though—like with `Escrow`—where there's a direct relationship between contracts. In those cases, we'll use [`Secondary`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ownership/Secondary.sol) to create a "secondary" contract that allows a "primary" contract to manage it.
Let's learn about Role-Based Access Control!
## Role-Based Access Control & Roles.sol
An alternative to single-concern `Ownable` is role based access control (RBAC), which, instead of keeping track of a single entity with "admin" level privileges, keeps track of multiple different entities with a variety of roles that inform the contract about what they can do.
For example, a `MintableToken` could have a `minter` role that decides who can mint tokens (which could be assigned to a Crowdsale). It could also have a `namer` role that allows changing the name or symbol of the token (for whatever reason). RBAC gives you much more flexibility over who can do what and is generally recommended for applications that need more configurability. If you're experienced with web development, the vast majority of access control systems are role-based: some users are normal users, some are moderators, and some can be company employee admins.
OpenZeppelin provides [contracts/access/Roles.sol](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/access/Roles.sol) for implementing role-based access control.
Here's an example of using `Roles` in our token example above, we'll use it to implement a token that can be minted by `Minters` and renamed by `Namers`:
```solidity
import "openzeppelin-solidity/contracts/access/Roles.sol";
contract MyToken is DetailedERC20, StandardToken {
using Roles for Roles.Role;
Roles.Role private minters;
Roles.Role private namers;
constructor(
string name,
string symbol,
uint8 decimals,
address[] minters,
address[] namers,
)
DetailedERC20(name, symbol, decimals)
Standardtoken()
public
{
namers.addMany(namers);
minters.addMany(minters);
}
function mint(address to, uint256 amount)
public
{
// only allow minters to mint
require(minters.has(msg.sender), "DOES_NOT_HAVE_MINTER_ROLE");
_mint(to, amount);
}
function rename(string name, string symbol)
public
{
// only allow namers to name
require(namers.has(msg.sender), "DOES_NOT_HAVE_NAMER_ROLE");
name = name;
symbol = symbol;
}
}
```
So clean! You'll notice that the role associations are always the last arguments in the constructor; this is a good pattern to follow to keep your code more organized.
---
id: learn-about-utilities
title: Learn About Utilities
---
OpenZeppelin provides a ton of useful utilities that you can use in your project. Here are some of the more popular ones:
## Cryptography
- [ECDSA.sol](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/cryptography/ECDSA.sol) — provides functions for recovering and managing Ethereum account ECDSA signatures:
- to use it, declare: `using ECDSA for bytes32;`
- signatures are tightly packed, 65 byte `bytes` that look like `{v (1)} {r (32)} {s (32)}`
- this is the default from `web3.eth.sign` so you probably don't need to worry about this format
- recover the signer using `myDataHash.recover(signature)`
- if you are using `eth_personalSign`, the signer will hash your data and then add the prefix `\x19Ethereum Signed Message:\n`, so if you're attempting to recover the signer of an Ethereum signed message hash, you'll want to use `toEthSignedMessageHash`
Use these functions in combination to verify that a user has signed some information on-chain:
```solidity
keccack256(
abi.encodePacked(
someData,
moreData
)
)
.toEthSignedMessageHash()
.recover(signature)
```
- [MerkleProof.sol](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/cryptography/MerkleProof.sol) — provides `verify(...)` for verifying merkle proofs.
## Introspection
In Solidity, it's frequently helpful to know whether or not a contract supports an interface you'd like to use. ERC165 is a standard that helps do runtime interface detection. OpenZeppelin provides some helpers, both for implementing ERC165 in your contracts and querying other contracts:
- [IERC165](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/introspection/IERC165.sol) — this is the ERC165 interface that defines `supportsInterface(...)`. When implementing ERC165, you'll conform to this interface.
- [ERC165](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/introspection/ERC165.sol) — inherit this contract if you'd like to support interface detection using a lookup table in contract storage. You can register interfaces using `_registerInterface(bytes4)`: check out example usage as part of the ERC721 implementation.
- [ERC165Checker](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/introspection/ERC165Checker.sol) — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about.
- include with `using ERC165Checker for address;`
- `myAddress.supportsInterface(bytes4)`
- `myAddress.supportsInterfaces(bytes4[])`
```solidity
contract MyContract {
using ERC165Checker for address;
bytes4 private InterfaceId_ERC721 = 0x80ac58cd;
/**
* @dev transfer an ERC721 token from this contract to someone else
*/
function transferERC721(
address token,
address to,
uint256 tokenId
)
public
{
require(token.supportsInterface(InterfaceId_ERC721), "IS_NOT_721_TOKEN");
IERC721(token).transferFrom(address(this), to, tokenId);
}
}
```
## Math
The most popular math related library OpenZeppelin provides is [SafeMath](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol), which provides mathematical functions that protect your contract from overflows and underflows.
Include the contract with `using SafeMath for uint256;` and then call the functions:
- `myNumber.add(otherNumber)`
- `myNumber.sub(otherNumber)`
- `myNumber.div(otherNumber)`
- `myNumber.mul(otherNumber)`
- `myNumber.mod(otherNumber)`
Easy!
## Payment
Want to split some payments between multiple people? Maybe you have an app that sends 30% of art purchases to the original creator and 70% of the profits to the current owner; you can build that with [`PaymentSplitter`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/payment/PaymentSplitter.sol)!.
In solidity, there are some security concerns with blindly sending money to accounts, since it allows them to execute arbitrary code. You can read up on these security concerns in the [Ethereum Smart Contract Best Practices](https://consensys.github.io/smart-contract-best-practices/) website. One of the ways to fix reentrancy and stalling problems is, instead of immediately sending Ether to accounts that need it, you can use [`PullPayment`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/payment/PullPayment.sol), which offers an `asyncSend` function for sending money to something and requesting that they `withdraw()` it later.
If you want to Escrow some funds, check out [`Escrow`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/payment/escrow/Escrow.sol) and [`ConditionalEscrow`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/payment/escrow/ConditionalEscrow.sol) for governing the release of some escrowed Ether.
### Misc
Want to check if an address is a contract? Use [`Address`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/utils/Address.sol) and `Address#isContract()`.
Want to keep track of some numbers that increment by 1 every time you want another one? Check out [`Counter`](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.1.2/contracts/drafts/Counter.sol). This is especially useful for creating incremental ERC721 tokenIds like we did in the last section.
{
"Overview": [
"get-started"
],
"Guides": [
"learn-about-access-control",
"learn-about-crowdsales",
"learn-about-tokens",
"learn-about-utilities"
],
"API Reference": [
{
"type": "directory",
"directory": "api"
}
]
}
[build]
command = "npm run docsite build"
publish = "docsite-build"
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
"compile": "truffle compile", "compile": "truffle compile",
"console": "truffle console", "console": "truffle console",
"coverage": "scripts/coverage.sh", "coverage": "scripts/coverage.sh",
"docsite": "scripts/docsite.sh",
"docgen": "scripts/docgen.sh",
"lint": "npm run lint:js && npm run lint:sol", "lint": "npm run lint:js && npm run lint:sol",
"lint:fix": "npm run lint:js:fix", "lint:fix": "npm run lint:js:fix",
"lint:js": "eslint .", "lint:js": "eslint .",
...@@ -53,10 +55,11 @@ ...@@ -53,10 +55,11 @@
"ethereumjs-util": "^6.0.0", "ethereumjs-util": "^6.0.0",
"ganache-cli": "^6.4.1", "ganache-cli": "^6.4.1",
"ganache-cli-coverage": "https://github.com/frangio/ganache-cli/releases/download/v6.4.1-coverage/ganache-cli-coverage-6.4.1.tgz", "ganache-cli-coverage": "https://github.com/frangio/ganache-cli/releases/download/v6.4.1-coverage/ganache-cli-coverage-6.4.1.tgz",
"openzeppelin-docsite": "github:OpenZeppelin/openzeppelin-docsite",
"openzeppelin-test-helpers": "^0.3.2", "openzeppelin-test-helpers": "^0.3.2",
"solhint": "^1.5.0", "solhint": "^1.5.0",
"solidity-coverage": "github:rotcivegaf/solidity-coverage#5875f5b7bc74d447f3312c9c0e9fc7814b482477", "solidity-coverage": "github:rotcivegaf/solidity-coverage#5875f5b7bc74d447f3312c9c0e9fc7814b482477",
"solidity-docgen": "^0.2.0-alpha.0",
"truffle": "^5.0.0" "truffle": "^5.0.0"
}, }
"dependencies": {}
} }
#!/bin/bash
#
# Trigger the job that will update the documentation website.
# Argument:
# version: the version of the new release. This should be a tag in the
# https://github.com/OpenZeppelin/openzeppelin-solidity repository.
set -ev
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <version>"
exit 1
fi
readonly VERSION="$1"
readonly BODY="{
\"request\": {
\"branch\": \"master\",
\"config\": {
\"env\": [\"VERSION=${VERSION}\"]
}
}
}"
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Travis-API-Version: 3" \
-H "Authorization: token ${DOCS_TRAVIS_API_TOKEN}" \
-d "${BODY}" \
https://api.travis-ci.com/repo/OpenZeppelin%2Fopenzeppelin-docs/requests
#!/usr/bin/env bash
OUTDIR=docs/api
rm -rf "$OUTDIR"
solidity-docgen -o "$OUTDIR" -i contracts/mocks -i contracts/examples
#!/usr/bin/env bash
# usage: npm run docsite [build|start]
set -o errexit
npm run docgen
npx openzeppelin-docsite-run "$1"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment