Commit 90831c89 by Francisco Giordano

Squash merge of branch docs-v2.x into master

parent 2187fae1
......@@ -5,8 +5,9 @@ This set of interfaces and contracts deal with [type introspection](https://en.w
Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors.
There are two main ways to approach this.
- Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`.
- Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts.
* Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`.
* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts.
Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security.
......
......@@ -4,6 +4,8 @@ Contract modules for simple authorization and access control mechanisms.
TIP: For more complex needs see xref:access.adoc.
== Contracts
{{Ownable}}
{{Secondary}}
......@@ -5,20 +5,23 @@ This set of interfaces, contracts, and utilities are all related to the https://
TIP: For an overview of ERC20 tokens and a walkthrough on how to create a token contract read our xref:ROOT:tokens.adoc#erc20[ERC20 guide].
There a few core contracts that implement the behavior specified in the EIP:
- {IERC20}: the interface all ERC20 implementations should conform to
- {ERC20}: the base implementation of the ERC20 interface
- {ERC20Detailed}: includes the <<ERC20Detailed-name,`name`>>,
* {IERC20}: the interface all ERC20 implementations should conform to
* {ERC20}: the base implementation of the ERC20 interface
* {ERC20Detailed}: includes the <<ERC20Detailed-name,`name`>>,
<<ERC20Detailed-symbol,`symbol`>> and <<ERC20Detailed-decimals,`decimals`>>
optional standard extension to the base interface
Additionally there are multiple custom extensions, including:
- designation of addresses that can create token supply ({ERC20Mintable}), with an optional maximum cap ({ERC20Capped})
- destruction of own tokens ({ERC20Burnable})
- designation of addresses that can pause token operations for all users ({ERC20Pausable}).
* designation of addresses that can create token supply ({ERC20Mintable}), with an optional maximum cap ({ERC20Capped})
* destruction of own tokens ({ERC20Burnable})
* designation of addresses that can pause token operations for all users ({ERC20Pausable}).
Finally, there are some utilities to interact with ERC20 contracts in various ways.
- {SafeERC20} is a wrapper around the interface that eliminates the need to handle boolean return values.
- {TokenTimelock} can hold tokens for a beneficiary until a specified time.
* {SafeERC20} is a wrapper around the interface that eliminates the need to handle boolean return values.
* {TokenTimelock} can hold tokens for a beneficiary until a specified time.
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
......
......@@ -30,7 +30,7 @@ contract IERC721 is IERC165 {
* - `from`, `to` cannot be zero.
* - `tokenId` must be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this
* NFT by either {approve} or {setApproveForAll}.
* NFT by either {approve} or {setApprovalForAll}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public;
/**
......@@ -39,7 +39,7 @@ contract IERC721 is IERC165 {
*
* Requirements:
* - If the caller is not `from`, it must be approved to move this NFT by
* either {approve} or {setApproveForAll}.
* either {approve} or {setApprovalForAll}.
*/
function transferFrom(address from, address to, uint256 tokenId) public;
function approve(address to, uint256 tokenId) public;
......
......@@ -9,7 +9,7 @@ contract IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a {IERC721-safeTransfer}. This function MUST return the function selector,
* after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer.
......
......@@ -14,8 +14,9 @@ The fully featured token implementing all three interfaces is prepackaged as {ER
Additionally, {IERC721Receiver} can be used to prevent tokens from becoming forever locked in contracts. Imagine sending an in-game item to an exchange address that can't send it back!. When using <<IERC721-safeTransferFrom,`safeTransferFrom`>>, the token 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 needs to receive {ERC721} tokens, you'll want to include this interface.
Finally, some custom extensions are also included:
- {ERC721Mintable} — like the ERC20 version, this allows certain addresses to mint new tokens
- {ERC721Pausable} — like the ERC20 version, this allows addresses to freeze transfers of tokens
* {ERC721Mintable} — like the ERC20 version, this allows certain addresses to mint new tokens
* {ERC721Pausable} — like the ERC20 version, this allows addresses to freeze transfers of tokens
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
......
......@@ -2,46 +2,64 @@
:{{name}}: pass:normal[xref:#{{anchor}}[`{{name}}`]]
{{/linkable}}
[.contract]
[[{{anchor}}]]
== `{{name}}`
=== `{{name}}`
{{natspec.devdoc}}
{{#if modifiers}}
[.contract-index]
.Modifiers
{{#inheritance}}
{{#ownModifiers}}
- xref:#{{anchor}}[{{signature}}]
* xref:#{{anchor}}[`{{signature}}`]
{{/ownModifiers}}
{{/inheritance}}
{{/if}}
{{#if functions}}
[.contract-index]
.Functions
{{#inheritance}}
{{#ownFunctions}}
- xref:#{{anchor}}[{{signature}}]
* xref:#{{anchor}}[`{{signature}}`]
{{/ownFunctions}}
{{/inheritance}}
{{/if}}
{{#if events}}
[.contract-index]
.Events
{{#inheritance}}
{{#ownEvents}}
- xref:#{{anchor}}[{{signature}}]
* xref:#{{anchor}}[`{{signature}}`]
{{/ownEvents}}
{{/inheritance}}
{{/if}}
{{#ownModifiers}}
[.contract-item]
[[{{anchor}}]]
=== {{name}}({{args}})
==== `{{name}}({{args}})`
{{natspec.devdoc}}
{{/ownModifiers}}
{{#ownFunctions}}
[.contract-item]
[[{{anchor}}]]
=== {{name}}({{args}}){{#if outputs}}{{outputs}}{{/if}}
==== `{{name}}({{args}}){{#if outputs}}{{outputs}}{{/if}}`
{{natspec.devdoc}}
{{/ownFunctions}}
{{#ownEvents}}
[.contract-item]
[[{{anchor}}]]
=== {{name}}({{args}})
==== `{{name}}({{args}})`
{{natspec.devdoc}}
......
......@@ -7,7 +7,7 @@ Access control—that is, "who is allowed to do this thing"—is incredibly impo
The most common and basic form of access control is the concept of _ownership_: there's an account that is the `owner` of a contract and can do administrative tasks on it. This approach is perfectly reasonable for contracts that have a single administrative user.
OpenZeppelin provides link:api/ownership#ownable[`Ownable`] for implementing ownership in your contracts.
OpenZeppelin provides xref:api:ownership.adoc#Ownable[`Ownable`] for implementing ownership in your contracts.
[source,solidity]
----
......@@ -26,9 +26,13 @@ contract MyContract is Ownable {
}
----
By default, the link:api/ownership#Ownable.owner()[`owner`] of an `Ownable` contract is the account that deployed it, which is usually exactly what you want.
By default, the xref:api:ownership.adoc#Ownable-owner--[`owner`] of an `Ownable` contract is the account that deployed it, which is usually exactly what you want.
Ownable also lets you: - link:api/ownership#Ownable.transferOwnership(address)[`transferOwnership`] from the owner account to a new one - link:api/ownership#Ownable.renounceOwnership()[`renounceOwnership`] for the owner to lose this administrative privilege, a common pattern after an initial stage with centralized administration is over - *⚠ Warning! ⚠* Removing the owner altogether will mean that administrative tasks that are protected by `onlyOwner` will no longer be callable!
Ownable also lets you:
* xref:api:ownership.adoc#Ownable-transferOwnership-address-[`transferOwnership`] from the owner account to a new one, and
* xref:api:ownership.adoc#Ownable-renounceOwnership--[`renounceOwnership`] for the owner to lose this administrative privilege, a common pattern after an initial stage with centralized administration is over.
WARNING: Removing the owner altogether will mean that administrative tasks that are protected by `onlyOwner` will no longer be callable!
Note that *a contract can also be the owner of another one*! This opens the door to using, for example, a https://github.com/gnosis/MultiSigWallet[Gnosis Multisig] or https://safe.gnosis.io[Gnosis Safe], an https://aragon.org[Aragon DAO], an https://www.uport.me[ERC725/uPort] identity contract, or a totally custom contract that _you_ create.
......@@ -46,9 +50,9 @@ Most of software development uses access control systems that are role-based: so
[[using-roles]]
=== Using `Roles`
OpenZeppelin provides link:api/access#roles[`Roles`] for implementing role-based access control. Its usage is straightforward: for each role that you want to define, you'll store a variable of type `Role`, which will hold the list of accounts with that role.
OpenZeppelin provides xref:api:access.adoc#Roles[`Roles`] for implementing role-based access control. Its usage is straightforward: for each role that you want to define, you'll store a variable of type `Role`, which will hold the list of accounts with that role.
Here's an simple example of using `Roles` in an link:tokens#erc20[`ERC20` token]: we'll define two roles, `namers` and `minters`, that will be able to change the name of the token contract, and mint new tokens, respectively.
Here's an simple example of using `Roles` in an xref:tokens.adoc#ERC20[`ERC20` token]: we'll define two roles, `namers` and `minters`, that will be able to change the name of the token contract, and mint new tokens, respectively.
[source,solidity]
----
......@@ -96,13 +100,13 @@ contract MyToken is ERC20, ERC20Detailed {
So clean! By splitting concerns this way, we can define more granular levels of permission, which was lacking in the _ownership_ approach to access control. Note that an account may have more than one role, if desired.
OpenZeppelin uses `Roles` extensively with predefined contracts that encode rules for each specific role. A few examples are: link:api/token/ERC20#erc20mintable[`ERC20Mintable`] which uses the link:api/access#minterrole[`MinterRole`] to determine who can mint tokens, and link:api/crowdsale#whitelistcrowdsale[`WhitelistCrowdsale`] which uses both link:api/access#whitelistadminrole[`WhitelistAdminRole`] and link:api/access#whitelistedrole[`WhitelistedRole`] to create a set of accounts that can purchase tokens.
OpenZeppelin uses `Roles` extensively with predefined contracts that encode rules for each specific role. A few examples are: xref:api:token/ERC20.adoc#ERC20Mintable[`ERC20Mintable`] which uses the xref:api:access.adoc#MinterRole[`MinterRole`] to determine who can mint tokens, and xref:api:crowdsale.adoc#WhitelistCrowdsale[`WhitelistCrowdsale`] which uses both xref:api:access.adoc#WhitelistAdminRole[`WhitelistAdminRole`] and xref:api:access.adoc#WhitelistedRole[`WhitelistedRole`] to create a set of accounts that can purchase tokens.
This flexibility allows for interesting setups: for example, a link:api/crowdsale#mintedcrowdsale[`MintedCrowdsale`] expects to be given the `MinterRole` of an `ERC20Mintable` in order to work, but the token contract could also extend link:api/token/ERC20#erc20pausable[`ERC20Pausable`] and assign the link:api/access#pauserrole[`PauserRole`] to a DAO that serves as a contingency mechanism in case a vulnerability is discovered in the contract code. Limiting what each component of a system is able to do is known as the https://en.wikipedia.org/wiki/Principle_of_least_privilege[principle of least privilege], and is a good security practice.
This flexibility allows for interesting setups: for example, a xref:api:crowdsale.adoc#MintedCrowdsale[`MintedCrowdsale`] expects to be given the `MinterRole` of an `ERC20Mintable` in order to work, but the token contract could also extend xref:api:token/ERC20.adoc#ERC20Pausable[`ERC20Pausable`] and assign the xref:api:access.adoc#PauserRole[`PauserRole`] to a DAO that serves as a contingency mechanism in case a vulnerability is discovered in the contract code. Limiting what each component of a system is able to do is known as the https://en.wikipedia.org/wiki/Principle_of_least_privilege[principle of least privilege], and is a good security practice.
[[usage-in-openzeppelin]]
== Usage in OpenZeppelin
You'll notice that none of the OpenZeppelin contracts use `Ownable`. `Roles` is a prefferred solution, because it provides the user of the library with enough flexibility to adapt the provided contracts to their needs.
There are some cases, though, where there's a direct relationship between contracts. For example, link:api/crowdsale#refundablecrowdsale[`RefundableCrowdsale`] deploys a link:api/payment#refundescrow[`RefundEscrow`] on construction, to hold its funds. For those cases, we'll use link:api/ownership#secondary[`Secondary`] to create a _secondary_ contract that allows a _primary_ contract to manage it. You could also think of these as _auxiliary_ contracts.
There are some cases, though, where there's a direct relationship between contracts. For example, xref:api:crowdsale.adoc#RefundableCrowdsale[`RefundableCrowdsale`] deploys a xref:api:payment.adoc#RefundEscrow[`RefundEscrow`] on construction, to hold its funds. For those cases, we'll use xref:api:ownership.adoc#Secondary[`Secondary`] to create a _secondary_ contract that allows a _primary_ contract to manage it. You could also think of these as _auxiliary_ contracts.
......@@ -7,7 +7,7 @@ In a nutshell, the API being stable means _if your project is working today, it
[[versioning-scheme]]
== Versioning scheme
We follow https://semver.org/[SemVer], which means API breakage may occur between major releases. Read more about the link:release-schedule[release schedule] to know how often this happens (not very).
We follow https://semver.org/[SemVer], which means API breakage may occur between major releases. Read more about the xref:release-schedule.adoc[release schedule] to know how often this happens (not very).
[[solidity-functions]]
== Solidity functions
......
......@@ -2,9 +2,23 @@
Crowdsales are a popular use for Ethereum; they let you allocate tokens to network participants in various ways, mostly in exchange for Ether. They come in a variety of shapes and flavors, so let's go over the various types available in OpenZeppelin and how to use them.
Crowdsales have a bunch of different properties, but here are some important ones: - Price & Rate Configuration - Does your crowdsale sell tokens at a fixed price? - Does the price change over time or as a function of demand? - Emission - How is this token actually sent to participants? - Validation — Who is allowed to purchase tokens? - Are there KYC / AML checks? - Is there a max cap on tokens? - What if that cap is per-participant? - Is there a starting and ending time frame? - Distribution - Does distribution of funds happen in real-time or after the crowdsale? - Can participants receive a refund if the goal is not met?
To manage all of the different combinations and flavors of crowdsales, OpenZeppelin provides a highly configurable link:api/crowdsale#crowdsale[`Crowdsale`] base contract that can be combined with various other functionalities to construct a bespoke crowdsale.
Crowdsales have a bunch of different properties, but here are some important ones:
* Price & Rate Configuration
* Does your crowdsale sell tokens at a fixed price?
* Does the price change over time or as a function of demand?
* Emission
* How is this token actually sent to participants?
* Validation — Who is allowed to purchase tokens?
* Are there KYC / AML checks?
* Is there a max cap on tokens?
* What if that cap is per-participant?
* Is there a starting and ending time frame?
* Distribution
* Does distribution of funds happen in real-time or after the crowdsale?
* Can participants receive a refund if the goal is not met?
To manage all of the different combinations and flavors of crowdsales, OpenZeppelin provides a highly configurable xref:api:crowdsale.adoc#Crowdsale[`Crowdsale`] base contract that can be combined with various other functionalities to construct a bespoke crowdsale.
[[crowdsale-rate]]
== Crowdsale Rate
......@@ -46,8 +60,8 @@ One more for practice: if I want to issue "1 TKN for every dollar (USD) in Ether
One of the first decisions you have to make is "how do I get these tokens to users?". This is usually done in one of three ways:
* (default) — The `Crowdsale` contract owns tokens and simply transfers tokens from its own ownership to users that purchase them.
* link:api/crowdsale#mintedcrowdsale[`MintedCrowdsale`] — The `Crowdsale` mints tokens when a purchase is made.
* link:api/crowdsale#allowancecrowdsale[`AllowanceCrowdsale`] — The `Crowdsale` is granted an allowance to another wallet (like a Multisig) that already owns the tokens to be sold in the crowdsale.
* xref:api:crowdsale.adoc#MintedCrowdsale[`MintedCrowdsale`] — The `Crowdsale` mints tokens when a purchase is made.
* xref:api:crowdsale.adoc#AllowanceCrowdsale[`AllowanceCrowdsale`] — The `Crowdsale` is granted an allowance to another wallet (like a Multisig) that already owns the tokens to be sold in the crowdsale.
[[default-emission]]
=== Default Emission
......@@ -73,7 +87,7 @@ new Crowdsale(
[[minted-crowdsale]]
=== Minted Crowdsale
To use a link:api/crowdsale#mintedcrowdsale[`MintedCrowdsale`], your token must also be a link:api/token/ERC20#erc20mintable[`ERC20Mintable`] token that the crowdsale has permission to mint from. This can look like:
To use a xref:api:crowdsale.adoc#MintedCrowdsale[`MintedCrowdsale`], your token must also be a xref:api:token/ERC20.adoc#ERC20Mintable[`ERC20Mintable`] token that the crowdsale has permission to mint from. This can look like:
[source,solidity]
----
......@@ -119,7 +133,7 @@ contract MyCrowdsaleDeployer {
[[allowancecrowdsale]]
=== AllowanceCrowdsale
Use an link:api/crowdsale#allowancecrowdsale[`AllowanceCrowdsale`] to send tokens from another wallet to the participants of the crowdsale. In order for this to work, the source wallet must give the crowdsale an allowance via the ERC20 link:api/token/ERC20#IERC20.approve(address,uint256)[`approve`] method.
Use an xref:api:crowdsale.adoc#AllowanceCrowdsale[`AllowanceCrowdsale`] to send tokens from another wallet to the participants of the crowdsale. In order for this to work, the source wallet must give the crowdsale an allowance via the ERC20 xref:api:token/ERC20.adoc#IERC20-approve-address-uint256-[`approve`] method.
[source,solidity]
----
......@@ -151,10 +165,10 @@ IERC20(tokenAddress).approve(CROWDSALE_ADDRESS, SOME_TOKEN_AMOUNT);
There are a bunch of different validation requirements that your crowdsale might be a part of:
* link:api/crowdsale#cappedcrowdsale[`CappedCrowdsale`] — adds a cap to your crowdsale, invalidating any purchases that would exceed that cap
* link:api/crowdsale#individuallycappedcrowdsale[`IndividuallyCappedCrowdsale`] — caps an individual's contributions.
* link:api/crowdsale#whitelistcrowdsale[`WhitelistCrowdsale`] — only allow whitelisted participants to purchase tokens. this is useful for putting your KYC / AML whitelist on-chain!
* link:api/crowdsale#timedcrowdsale[`TimedCrowdsale`] — adds an link:api/crowdsale#TimedCrowdsale.openingTime()[`openingTime`] and link:api/crowdsale#TimedCrowdsale.closingTime()[`closingTime`] to your crowdsale
* xref:api:crowdsale.adoc#CappedCrowdsale[`CappedCrowdsale`] — adds a cap to your crowdsale, invalidating any purchases that would exceed that cap
* xref:api:crowdsale.adoc#IndividuallyCappedCrowdsale[`IndividuallyCappedCrowdsale`] — caps an individual's contributions.
* xref:api:crowdsale.adoc#WhitelistCrowdsale[`WhitelistCrowdsale`] — only allow whitelisted participants to purchase tokens. this is useful for putting your KYC / AML whitelist on-chain!
* xref:api:crowdsale.adoc#TimedCrowdsale[`TimedCrowdsale`] — adds an xref:api:crowdsale.adoc#TimedCrowdsale-openingTime--[`openingTime`] and xref:api:Crowdsale.adoc#TimedCrowdsale-closingTime--[`closingTime`] to your crowdsale
Simply mix and match these crowdsale flavors to your heart's content:
......@@ -194,7 +208,7 @@ OpenZeppelin is here to make that easy!
[[postdeliverycrowdsale]]
=== PostDeliveryCrowdsale
The link:api/crowdsale#postdeliverycrowdsale[`PostDeliveryCrowdsale`], as its name implies, distributes tokens after the crowdsale has finished, letting users call link:api/crowdsale#PostDeliveryCrowdsale.withdrawTokens(address)[`withdrawTokens`] in order to claim the tokens they've purchased.
The xref:api:crowdsale.adoc#PostDeliveryCrowdsale[`PostDeliveryCrowdsale`], as its name implies, distributes tokens after the crowdsale has finished, letting users call xref:api:crowdsale.adoc#PostDeliveryCrowdsale-withdrawTokens_address-[`withdrawTokens`] in order to claim the tokens they've purchased.
[source,solidity]
----
......@@ -221,7 +235,7 @@ contract MyCrowdsale is Crowdsale, TimedCrowdsale, PostDeliveryCrowdsale {
[[refundablecrowdsale]]
=== RefundableCrowdsale
The link:api/crowdsale#refundablecrowdsale[`RefundableCrowdsale`] offers to refund users if a minimum goal is not reached. If the goal is not reached, the users can link:api/crowdsale#RefundableCrowdsale.claimRefund(address%20payable)[`claimRefund`] to get their Ether back.
The xref:api:crowdsale.adoc#RefundableCrowdsale[`RefundableCrowdsale`] offers to refund users if a minimum goal is not reached. If the goal is not reached, the users can xref:api:crowdsale.adoc#RefundableCrowdsale-claimRefund-address-payable-[`claimRefund`] to get their Ether back.
[source,solidity]
----
......
......@@ -25,7 +25,7 @@ To install the OpenZeppelin library, run the following in your Solidity project
$ npm install openzeppelin-solidity
----
_OpenZeppelin features a stable API, which means your contracts won't break unexpectedly when upgrading to a newer minor version. You can read ṫhe details in our link:api-stability[API Stability] document._
NOTE: OpenZeppelin features a stable API, which means your contracts won't break unexpectedly when upgrading to a newer minor version. You can read ṫhe details in our xref:api-stability.adoc[API Stability] document.
[[usage]]
== Usage
......@@ -45,21 +45,19 @@ contract MyContract is Ownable {
Truffle and other Ethereum development toolkits will automatically detect the installed library, and compile the imported contracts.
______________________________________________________________________________________________________________________
You should always use the installed code as-is, and neither copy-paste it from online sources, nor modify it yourself.
______________________________________________________________________________________________________________________
IMPORTANT: You should always use the installed code as-is, and neither copy-paste it from online sources, nor modify it yourself.
[[next-steps]]
== Next Steps
Check out the the guides in the sidebar to learn about different concepts, and how to use the contracts that OpenZeppelin provides.
* link:access-control[Learn about Access Control]
* link:crowdsales[Learn about Crowdsales]
* link:tokens[Learn about Tokens]
* link:utilities[Learn about our Utilities]
* xref:access-control.adoc[Learn about Access Control]
* xref:crowdsales.adoc[Learn about Crowdsales]
* xref:tokens.adoc[Learn about Tokens]
* xref:utilities.adoc[Learn about our Utilities]
OpenZeppelin's link:api/token/ERC20[full API] is also thoroughly documented, and serves as a great reference when developing your smart contract application.
OpenZeppelin's xref:api:token/ERC20.adoc[full API] is also thoroughly documented, and serves as a great reference when developing your smart contract application.
Additionally, you can also ask for help or follow OpenZeppelin's development in the https://forum.openzeppelin.com[community forum].
......
= Release Schedule
OpenZeppelin follows a link:api-stability[semantic versioning scheme].
OpenZeppelin follows a xref:api-stability.adoc[semantic versioning scheme].
[[minor-releases]]
== Minor releases
......
......@@ -5,12 +5,12 @@ OpenZeppelin provides a ton of useful utilities that you can use in your project
[[cryptography]]
== Cryptography
* link:api/cryptography#ecdsa[`ECDSA`] — provides functions for recovering and managing Ethereum account ECDSA signatures:
* xref:api:cryptography.adoc#ECDSA[`ECDSA`] — 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 link:api/cryptography#ECDSA.recover(bytes32,bytes)[`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 link:api/cryptography#ECDSA.toEthSignedMessageHash(bytes32)[`toEthSignedMessageHash`]
* recover the signer using xref:api:cryptography.adoc#ECDSA-recover-bytes32-bytes-[`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 xref:api:cryptography.adoc#ECDSA-toEthSignedMessageHash-bytes32-[`toEthSignedMessageHash`]
Use these functions in combination to verify that a user has signed some information on-chain:
......@@ -26,19 +26,19 @@ keccack256(
.recover(signature)
----
* link:api/cryptography#merkleproof[`MerkleProof`] — provides link:api/cryptography#MerkleProof.verify(bytes32%5B%5D,bytes32,bytes32)[`verify`] for verifying merkle proofs.
* xref:api:cryptography.adoc#MerkleProof[`MerkleProof`] — provides xref:api:cryptography.adoc#MerkleProof-verify-bytes32---bytes32-bytes32-[`verify`] for verifying merkle proofs.
[[introspection]]
== 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:
* link:api/introspection#ierc165[`IERC165`] — this is the ERC165 interface that defines link:api/introspection#IERC165.supportsInterface(bytes4)[`supportsInterface`]. When implementing ERC165, you'll conform to this interface.
* link:api/introspection#erc165[`ERC165`] — inherit this contract if you'd like to support interface detection using a lookup table in contract storage. You can register interfaces using link:api/introspection#ERC165._registerInterface(bytes4)[`_registerInterface(bytes4)`]: check out example usage as part of the ERC721 implementation.
* link:api/introspection#erc165checker[`ERC165Checker`] — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about.
* xref:api:introspection.adoc#IERC165[`IERC165`] — this is the ERC165 interface that defines xref:api:introspection.adoc#IERC165-supportsInterface-bytes4-[`supportsInterface`]. When implementing ERC165, you'll conform to this interface.
* xref:api:introspection.adoc#ERC165[`ERC165`] — inherit this contract if you'd like to support interface detection using a lookup table in contract storage. You can register interfaces using xref:api:introspection.adoc#ERC165-_registerInterface-bytes4-[`_registerInterface(bytes4)`]: check out example usage as part of the ERC721 implementation.
* xref:api:introspection.adoc#ERC165Checker[`ERC165Checker`] — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about.
* include with `using ERC165Checker for address;`
* link:api/introspection#ERC165Checker._supportsInterface(address,bytes4)[`myAddress._supportsInterface(bytes4)`]
* link:api/introspection#ERC165Checker._supportsAllInterfaces(address,bytes4%5B%5D)[`myAddress._supportsAllInterfaces(bytes4[])`]
* xref:api:introspection.adoc#ERC165Checker-_supportsInterface-address-bytes4-[`myAddress._supportsInterface(bytes4)`]
* xref:api:introspection.adoc#ERC165Checker-_supportsAllInterfaces-address-bytes4---[`myAddress._supportsAllInterfaces(bytes4[])`]
[source,solidity]
----
......@@ -66,7 +66,7 @@ contract MyContract {
[[math]]
== Math
The most popular math related library OpenZeppelin provides is link:api/math#safemath[`SafeMath`], which provides mathematical functions that protect your contract from overflows and underflows.
The most popular math related library OpenZeppelin provides is xref:api:math.adoc#SafeMath[`SafeMath`], 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:
......@@ -81,15 +81,15 @@ Easy!
[[payment]]
== 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 link:api/payment#paymentsplitter[`PaymentSplitter`]!
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 xref:api:payment.adoc#PaymentSplitter[`PaymentSplitter`]!
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 https://consensys.github.io/smart-contract-best-practices/[Ethereum 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 link:api/payment#pullpayment[`PullPayment`], which offers an link:api/payment#PullPayment._asyncTransfer(address,uint256)[`_asyncTransfer`] function for sending money to something and requesting that they link:api/payment#PullPayment.withdrawPayments(address%20payable)[`withdrawPayments()`] it later.
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 https://consensys.github.io/smart-contract-best-practices/[Ethereum 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 xref:api:payment.adoc#PullPayment[`PullPayment`], which offers an xref:api:payment.adoc#PullPayment-_asyncTransfer-address-uint256-[`_asyncTransfer`] function for sending money to something and requesting that they xref:api:payment.adoc#PullPayment-withdrawPayments-address-payable-[`withdrawPayments()`] it later.
If you want to Escrow some funds, check out link:api/payment#escrow[`Escrow`] and link:api/payment#conditionalescrow[`ConditionalEscrow`] for governing the release of some escrowed Ether.
If you want to Escrow some funds, check out xref:api:payment.adoc#Escrow[`Escrow`] and xref:api:payment.adoc#ConditionalEscrow[`ConditionalEscrow`] for governing the release of some escrowed Ether.
[[misc]]
=== Misc
Want to check if an address is a contract? Use link:api/utils#address[`Address`] and link:api/utils#Address.isContract(address)[`Address.isContract()`].
Want to check if an address is a contract? Use xref:api:utils.adoc#Address[`Address`] and xref:api:utils.adoc#Address-isContract-address-[`Address.isContract()`].
Want to keep track of some numbers that increment by 1 every time you want another one? Check out link:api/drafts#counter[`Counter`]. This is especially useful for creating incremental ERC721 `tokenId`s like we did in the last section.
Want to keep track of some numbers that increment by 1 every time you want another one? Check out xref:api:drafts.adoc#Counter[`Counter`]. This is especially useful for creating incremental ERC721 `tokenId`s like we did in the last section.
......@@ -187,12 +187,6 @@
"universalify": "^0.1.0"
}
},
"indent-string": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
"integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
......@@ -364,12 +358,6 @@
"supports-color": "^5.3.0"
}
},
"indent-string": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
"integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
......@@ -469,9 +457,9 @@
"dev": true
},
"@types/node": {
"version": "12.0.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
"version": "12.6.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz",
"integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==",
"dev": true
},
"abbrev": {
......@@ -2606,6 +2594,26 @@
"randombytes": "^2.0.0"
}
},
"dir-glob": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
"integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
"dev": true,
"requires": {
"path-type": "^3.0.0"
},
"dependencies": {
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
"pify": "^3.0.0"
}
}
}
},
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
......@@ -5684,6 +5692,12 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"indent-string": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
"integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
......@@ -6431,6 +6445,12 @@
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
"dev": true
},
"lodash.startcase": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
"integrity": "sha1-lDbjTtJgk+1/+uGTYUQ1CRXZrdg=",
"dev": true
},
"lodash.template": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
......@@ -8248,6 +8268,12 @@
"simple-concat": "^1.0.0"
}
},
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
"dev": true
},
"slice-ansi": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
......@@ -8905,12 +8931,12 @@
}
},
"solidity-docgen": {
"version": "0.3.0-beta.2",
"resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.3.0-beta.2.tgz",
"integrity": "sha512-q4X2GuJQVglHHLnvLVHYdJUAGbr5VKHmcRWel+QE8PUwi9m78xAYXg+80p4fDqEfXeI4SPz37wJWhYA51rqpLw==",
"version": "0.3.0-beta.4",
"resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.3.0-beta.4.tgz",
"integrity": "sha512-VTjyJvNjURg6AVhofc84NjNwjyw2PZ1SVxYpdHDynb+xJkgWmK2LL+hIlIxfuhHji+dkMdIhhP80eQxwhPK5kA==",
"dev": true,
"requires": {
"@oclif/command": "^1.5.16",
"@oclif/command": "^1.5.17",
"@oclif/config": "^1.13.2",
"@oclif/errors": "^1.2.2",
"@oclif/plugin-help": "^2.2.0",
......@@ -8925,15 +8951,6 @@
"typescript": "^3.5.3"
},
"dependencies": {
"dir-glob": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
"integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
"dev": true,
"requires": {
"path-type": "^3.0.0"
}
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
......@@ -8996,23 +9013,6 @@
"graceful-fs": "^4.1.6"
}
},
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
"dev": true,
"requires": {
"pify": "^3.0.0"
},
"dependencies": {
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true
}
}
},
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
......@@ -9025,12 +9025,6 @@
"integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==",
"dev": true
},
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
"dev": true
},
"solc": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/solc/-/solc-0.5.10.tgz",
......
#!/usr/bin/env node
const path = require('path');
const proc = require('child_process');
const startCase = require('lodash.startcase');
const baseDir = process.argv[2];
const files = proc.execFileSync(
'find', [baseDir, '-type', 'f'], { encoding: 'utf8' }
).split('\n').filter(s => s !== '');
console.log('.API');
for (const file of files) {
const doc = file.replace(baseDir, '');
const title = path.parse(file).name;
console.log(`* xref:${doc}[${startCase(title)}]`);
}
......@@ -4,10 +4,4 @@ OUTDIR=docs/modules/api/pages/
rm -rf "$OUTDIR"
solidity-docgen -t docs -o "$OUTDIR" -e contracts/mocks,contracts/examples
gen-nav() {
echo '.API'
find "$OUTDIR" -type f | sed -Ee "s:$OUTDIR(.+):* xref\:\1[]:"
}
gen-nav > "$OUTDIR/../nav.adoc"
node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc"
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