-
Notifications
You must be signed in to change notification settings - Fork 361
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added ERC20 draft * changed bullet point * added example usage section * added gas benchmarks and Api reference section * fixed formatting * added documentation up to totalSupply(), committing changes so I can see how it looks like * fixed grammar and standardized structure * added documentation for balanceOf and allowance * added documentation for the approve function * added documentation for transfer * added revert condition for transfer function * standardize * Added documentation on nonces * added documentation for permit * added documentation for DOMAIN_SEPERATOR * added section for events * fixed events table format * fixed small typo * added benchmarks for ERC20
- Loading branch information
0xlgtm
authored
Nov 6, 2023
1 parent
02ffa0a
commit 7443a01
Showing
1 changed file
with
393 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,395 @@ | ||
# ERC20 | ||
|
||
Under construction | ||
Source: [`tokens/ERC20.sol`](https://github.com/Vectorized/solady/blob/main/src/tokens/ERC20.sol) | ||
|
||
Solady's ERC20 token implementation is an opinionated and highly optimized implementation of the [ERC20 standard](https://eips.ethereum.org/EIPS/eip-20). It also inherits the [ERC2612 standard](https://eips.ethereum.org/EIPS/eip-2612) which enables permit-based approvals. | ||
|
||
## Things to note | ||
|
||
- The ERC20 standard does not impose any restriction on the addresses and amounts used. As such, this implementation **WILL NOT** revert for the following: | ||
- mint to the zero address | ||
- transfer to and from the zero address | ||
- transfer zero tokens | ||
- self approvals | ||
- Every function can be overridden with the `override` keyword if a custom implementation is required. | ||
- The `permit` function uses the ecrecover precompile (0x1). | ||
|
||
## Example usage | ||
|
||
### Foundry | ||
|
||
1. Create a new [foundry](https://github.com/foundry-rs/foundry) repository and navigate to the root folder. | ||
|
||
```bash | ||
$ forge init <name of project> | ||
$ cd <name of project> | ||
``` | ||
|
||
2. Install the Solady library | ||
|
||
```bash | ||
$ forge install vectorized/solady | ||
``` | ||
|
||
3. Create a file called `MyToken.sol` in the `<project name>/src` folder. | ||
|
||
```bash | ||
$ touch src/MyToken.sol | ||
``` | ||
|
||
4. Copy the following implementation into the `MyToken.sol` file. | ||
|
||
```solidity | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.4; | ||
import {ERC20} from "solady/src/tokens/ERC20.sol"; | ||
contract MyToken is ERC20 { | ||
function name() public view override returns (string memory) { | ||
return "Mytoken"; | ||
} | ||
function symbol() public view override returns (string memory) { | ||
return "MYT"; | ||
} | ||
} | ||
``` | ||
|
||
## Gas Benchmarks | ||
|
||
| Function name | [Solady](https://github.com/Vectorized/solady/blob/main/src/tokens/ERC20.sol) | [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Permit.sol) | | ||
| ---------------- | ------ | ------------ | | ||
| DOMAIN_SEPERATOR | 488 | 386 | | ||
| allowance | 700 | 814 | | ||
| approve | 24403 | 24762 | | ||
| burn | 2141 | 2439 | | ||
| decimals | 222 | 222 | | ||
| mint | 24649 | 24978 | | ||
| name | 494 | 3241 | | ||
| nonces | 555 | 616 | | ||
| permit | 50437 | 51478 | | ||
| symbol | 542 | 3306 | | ||
| transfer | 2235 | 2613 | | ||
| transferFrom | 2577 | 3295 | | ||
|
||
## API Reference | ||
|
||
### Functions | ||
|
||
| Name | Description | | ||
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | ||
| [name](#name) | The name of the token. | | ||
| [symbol](#symbol) | The symbol of the token. | | ||
| [decimals](#decimals) | The number of decimals of the token. | | ||
| [totalSupply](#totalsupply) | The amount of tokens in existence. | | ||
| [balanceOf](#balanceof) | The amount of tokens owned by `owner`. | | ||
| [allowance](#allowance) | The amount of tokens that `spender` can spend on behalf of `owner`. | | ||
| [approve](#approve) | Sets `amount` as the allowance of `spender` over the caller's tokens. | | ||
| [transfer](#transfer) | Transfer `amount` tokens from the caller to `to`. | | ||
| [transferFrom](#transferfrom) | Transfers `amount` tokens from `from` to `to`. | | ||
| [nonces](#nonces) | The current nonce for `owner`. | | ||
| [permit](#permit) | Sets `value` as the allowance of `spender` over the tokens of `owner`, authorized by a signed approval by `owner`. | | ||
| [DOMAIN_SEPARATOR](#domain_seperator) | The EIP-712 domain separator for the EIP-2612 permit. | | ||
|
||
--- | ||
|
||
#### name | ||
|
||
Returns the name of the token. | ||
|
||
```solidity | ||
function name() public view virtual returns (string memory) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- None | ||
|
||
##### Return Value(s) | ||
|
||
- The name of the token. | ||
|
||
##### Note(s) | ||
|
||
- Must override or the contract will not compile. | ||
|
||
--- | ||
|
||
#### symbol | ||
|
||
Returns the symbol of the token. | ||
|
||
```solidity | ||
function symbol() public view virtual returns (string memory) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- None | ||
|
||
##### Return Value(s) | ||
|
||
- The symbol of the token. | ||
|
||
##### Note(s) | ||
|
||
- Must override or the contract will not compile. | ||
|
||
--- | ||
|
||
#### decimals | ||
|
||
Returns the number of decimals of the token. | ||
|
||
```solidity | ||
function decimals() public view virtual returns (uint8) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- None | ||
|
||
##### Return Value(s) | ||
|
||
- The number of decimals of the token. | ||
|
||
##### Note(s) | ||
|
||
- None | ||
|
||
--- | ||
|
||
#### totalSupply | ||
|
||
Returns the amount of tokens in existence. | ||
|
||
```solidity | ||
function totalSupply() public view virtual returns (uint256 result) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- None | ||
|
||
##### Return Value(s) | ||
|
||
- `result`: The number of tokens in existence. | ||
|
||
##### Note(s) | ||
|
||
- None | ||
|
||
--- | ||
|
||
#### balanceOf | ||
|
||
Returns the amount of tokens owned by `owner`. | ||
|
||
```solidity | ||
function balanceOf(address owner) public view virtual returns (uint256 result) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- `owner`: The address to query the token balance of. | ||
|
||
##### Return Value(s) | ||
|
||
- `result`: The amount of tokens owned by `owner`. | ||
|
||
##### Note(s) | ||
|
||
- None | ||
|
||
--- | ||
|
||
#### allowance | ||
|
||
Returns the amount of tokens that `spender` can spend on behalf of `owner`. | ||
|
||
```solidity | ||
function allowance(address owner, address spender) public view virtual returns (uint256 result) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- `owner`: The owner of the tokens. | ||
- `spender`: The spender of the tokens. | ||
|
||
##### Return Value(s) | ||
|
||
- `result`: The amount of tokens that `spender` can spend on behalf of `owner`. | ||
|
||
##### Note(s) | ||
|
||
- None | ||
|
||
--- | ||
|
||
#### approve | ||
|
||
Sets `amount` as the allowance of `spender` over the caller's tokens. | ||
|
||
```solidity | ||
function approve(address spender, uint256 amount) public virtual returns (bool) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- `spender`: The spender of the tokens. | ||
- `amount`: The amount to set as spender's allowance. | ||
|
||
##### Return Value(s) | ||
|
||
- `true` if `spender`'s allowance is updated successfully. | ||
|
||
##### Note(s) | ||
|
||
- Emits the `Approval` event if `spender`'s allowance is updated successfully. | ||
|
||
--- | ||
|
||
#### transfer | ||
|
||
Transfer `amount` tokens from the caller to `to`. | ||
|
||
```solidity | ||
function transfer(address to, uint256 amount) public virtual returns (bool) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- `to`: The address to receive the tokens. | ||
- `amount`: The amount of tokens to transfer from the caller. | ||
|
||
##### Return Value(s) | ||
|
||
- `true` if `amount` tokens are transferred from the caller to `to` successfully. | ||
|
||
##### Note(s) | ||
|
||
- Emits the `Transfer` event if `amount` of tokens are transferred from the caller to `to` successfully. | ||
- Reverts with the `InsufficientBalance` error if caller does not have enough tokens. | ||
|
||
--- | ||
|
||
#### transferFrom | ||
|
||
Transfers `amount` tokens from `from` to `to`. | ||
|
||
```solidity | ||
transferFrom(address from, address to, uint256 amount) public virtual returns (bool) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- `from`: The address to transfer the tokens from. | ||
- `to`: The address to transfer the tokens to. | ||
- `amount`: The amount of tokens to be transferred. | ||
|
||
##### Return Value(s) | ||
|
||
- `true` if `amount` of tokens are transferred from `from` to `to`. | ||
|
||
##### Note(s) | ||
|
||
- Emits the `Transfer` event if `amount` of tokens are transferred from `from` to `to` successfully. | ||
- Does not update caller's allowance if allowance is `type(uint256).max`. | ||
- Reverts with `InsufficientAllowance` error if the caller does not have enough allowance. | ||
- Reverts with `InsufficientBalance` error if `from` does not have enough tokens. | ||
|
||
--- | ||
|
||
#### nonces | ||
|
||
Returns the current nonce for `owner`. | ||
|
||
```solidity | ||
function nonces(address owner) public view virtual returns (uint256 result) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- `owner`: The address to query the nonce of. | ||
|
||
##### Return Value(s) | ||
|
||
- `result`: The current nonce of the `owner`. | ||
|
||
##### Note(s) | ||
|
||
- This value is used to compute the signature for [EIP-2612 permit](https://eips.ethereum.org/EIPS/eip-2612). | ||
|
||
--- | ||
|
||
#### permit | ||
|
||
Sets `value` as the allowance of `spender` over the tokens of `owner`, authorized by a signed approval by `owner`. | ||
|
||
```solidity | ||
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- `owner`: The owner of the tokens. | ||
- `spender`: The spender of the tokens. | ||
- `value`: The amount to set as spender's allowance. | ||
- `deadline`: The deadline of the signature. | ||
- `v`: The v component of the signature. | ||
- `r`: The r component of the signature. | ||
- `s`: The s component of the signature. | ||
|
||
##### Return Value(s) | ||
|
||
- None | ||
|
||
##### Note(s) | ||
|
||
- Emits the `Approval` event if `spender`'s allowance is updated successfully. | ||
- `owner`'s nonce will be incremented by 1 if `permit` is successful. | ||
- Reverts with `PermitExpired` error if the current timestamp is greater than `deadline`. | ||
- Reverts with `InvalidPermit` error if the address recovered does not match the `owner`. | ||
|
||
--- | ||
|
||
#### DOMAIN_SEPERATOR | ||
|
||
Returns the EIP-712 domain separator for the EIP-2612 permit. | ||
|
||
```solidity | ||
function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) | ||
``` | ||
|
||
##### Parameter(s) | ||
|
||
- None | ||
|
||
##### Return Value(s) | ||
|
||
- `result`: The EIP-712 domain separator for the EIP-2612 permit. | ||
|
||
##### Note(s) | ||
|
||
- None | ||
|
||
--- | ||
|
||
### Errors | ||
|
||
| Name | Description | Selector | | ||
| ------------------- | -------------------------------------------- | ------------ | | ||
| TotalSupplyOverflow | Thrown when the total supply has overflowed. | `0xe5cfe957` | | ||
| AllowanceOverflow | Thrown when the allowance has overflowed. | `0xf9067066` | | ||
| AllowanceUnderflow | Thrown when the allowance has underflowed. | `0x8301ab38` | | ||
| InsufficientBalance | Thrown when there is insufficient balance. | `0xf4d678b8` | | ||
| InvalidPermit | Thrown when the permit is invalid. | `0xddafbaef` | | ||
| PermitExpired | Thrown when the permit has expired. | `0x1a15a3cc` | | ||
|
||
### Events | ||
|
||
| Name | Description | | ||
| --------------------------------- | ------------------------------------ | | ||
| Transfer(address,address,uint256) | Emitted when tokens are transferred. | | ||
| Approval(address,address,uint256) | Emitted when allowances are updated. | |