utilities.adoc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. = Utilities
  2. The OpenZeppelin Contracs provide a ton of useful utilities that you can use in your project. Here are some of the more popular ones.
  3. [[cryptography]]
  4. == Cryptography
  5. === Checking Signatures On-Chain
  6. xref:api:cryptography.adoc#ECDSA[`ECDSA`] provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via https://web3js.readthedocs.io/en/v1.2.4/web3-eth.html#sign[`web3.eth.sign`], and are a 65 byte array (of type `bytes` in Solidity) arranged the follwing way: `[[v (1)], [r (32)], [s (32)]]`.
  7. The data signer can be recovered with xref:api:cryptography.adoc#ECDSA-recover-bytes32-bytes-[`ECDSA.recover`], and its address compared to verify the signature. Most wallets will hash the data to sign and add the prefix '\x19Ethereum Signed Message:\n', so when attempting to recover the signer of an Ethereum signed message hash, you'll want to use xref:api:cryptography.adoc#ECDSA-toEthSignedMessageHash-bytes32-[`toEthSignedMessageHash`].
  8. [source,solidity]
  9. ----
  10. using ECDSA for bytes32;
  11. function _verify(bytes32 data, address account) pure returns (bool) {
  12. return keccack256(data)
  13. .toEthSignedMessageHash()
  14. .recover(signature) == account;
  15. }
  16. ----
  17. WARNING: Getting signature verification right is not trivial: make sure you fully read and understand xref:api:cryptography.adoc#ECDSA[`ECDSA`]'s documentation.
  18. === Verifying Merkle Proofs
  19. xref:api:cryptography.adoc#MerkleProof[`MerkleProof`] provides xref:api:cryptography.adoc#MerkleProof-verify-bytes32---bytes32-bytes32-[`verify`], which can prove that some value is part of a https://en.wikipedia.org/wiki/Merkle_tree[Merkle tree].
  20. [[introspection]]
  21. == Introspection
  22. 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. Contracts provides helpers both for implementing ERC165 in your contracts and querying other contracts:
  23. * 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.
  24. * 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.
  25. * xref:api:introspection.adoc#ERC165Checker[`ERC165Checker`] — ERC165Checker simplifies the process of checking whether or not a contract supports an interface you care about.
  26. * include with `using ERC165Checker for address;`
  27. * xref:api:introspection.adoc#ERC165Checker-_supportsInterface-address-bytes4-[`myAddress._supportsInterface(bytes4)`]
  28. * xref:api:introspection.adoc#ERC165Checker-_supportsAllInterfaces-address-bytes4---[`myAddress._supportsAllInterfaces(bytes4[])`]
  29. [source,solidity]
  30. ----
  31. contract MyContract {
  32. using ERC165Checker for address;
  33. bytes4 private InterfaceId_ERC721 = 0x80ac58cd;
  34. /**
  35. * @dev transfer an ERC721 token from this contract to someone else
  36. */
  37. function transferERC721(
  38. address token,
  39. address to,
  40. uint256 tokenId
  41. )
  42. public
  43. {
  44. require(token.supportsInterface(InterfaceId_ERC721), "IS_NOT_721_TOKEN");
  45. IERC721(token).transferFrom(address(this), to, tokenId);
  46. }
  47. }
  48. ----
  49. [[math]]
  50. == Math
  51. The most popular math related library OpenZeppelin Contracts provides is xref:api:math.adoc#SafeMath[`SafeMath`], which provides mathematical functions that protect your contract from overflows and underflows.
  52. Include the contract with `using SafeMath for uint256;` and then call the functions:
  53. * `myNumber.add(otherNumber)`
  54. * `myNumber.sub(otherNumber)`
  55. * `myNumber.div(otherNumber)`
  56. * `myNumber.mul(otherNumber)`
  57. * `myNumber.mod(otherNumber)`
  58. Easy!
  59. [[payment]]
  60. == Payment
  61. 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`]!
  62. 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.
  63. 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.
  64. [[collections]]
  65. == Collections
  66. If you need support for more powerful collections than Solidity's native arrays and mappings, take a look at xref:api:utils.adoc#EnumerableSet[`EnumerableSet`]. It is similar to a mapping in that it stores and removes elements in constant time and doesn't allow for repeated entries, but it also supports _enumeration_, which means you can easily query all elements of the set both on and off-chain.
  67. [[misc]]
  68. == Misc
  69. 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()`].
  70. 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 useful for lots of things, like creating incremental identifiers, as shown on the xref:721.adoc[ERC721 guide].