Skip to content

Commit

Permalink
feat: implement ERC20External optimization (#14)
Browse files Browse the repository at this point in the history
* add ERC20External

* clean up and release
  • Loading branch information
kassandraoftroy authored Nov 4, 2022
1 parent 5779cb7 commit b10b6d0
Show file tree
Hide file tree
Showing 7 changed files with 607 additions and 23 deletions.
38 changes: 28 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**NOT MEANT FOR PRODUCTION - UNAUDITED - USE AT OWN RISK**

ERC20.sol implementation using only inline assembly YUL. Basically, it is a hyper gas optimized ERC20 base implementation for solidity developers. It improves on gas consupmtion for nearly every `public` / `external` method over the leading ERC20.sol implementations (OpenZeppelin, Solmate). Optimizing view/pure calls can matter too, as many ERC20 view methods get used inside of state changing methods. See below for full gas comparison.
ERC20.sol implementation using only inline assembly YUL. Basically, it is a hyper gas optimized ERC20 base implementation for solidity developers. It improves on gas consupmtion for every `public` / `external` method over the leading ERC20.sol implementations (OpenZeppelin, Solmate). Optimizing view/pure calls can matter too, as many ERC20 view methods get used inside of state changing methods. See below for full gas comparison.

Mostly this is useful as a reference implementation to learn the basics of inline assembly if you are already familiar with canonical solidity ERC20 implementations

Expand All @@ -20,6 +20,12 @@ then you could import this as your base ERC20 contract implementation:
import {ERC20} from "yulerc20/contracts/ERC20.sol";
```

or

```
import {ERC20External} from "yulerc20/contracts/ERC20External.sol";
```

## Test

fill in ALCHEMY_ID in a `.env` (see `.env.example` for all environment vars)
Expand All @@ -42,46 +48,52 @@ yarn test
| ----------------- | --------- |
| OpenZeppelinERC20 | 46232 |
| SolmateERC20 | 46153 |
| YulERC20 | **46080** |
| YulERC20 | 46080 |
| YulERC20Ext | **46008** |

### permit

| Contract | Gas Cost |
| ------------ | --------- |
| SolmateERC20 | 74172 |
| YulERC20 | **73785** |
| YulERC20 | 73785 |
| YulERC20Ext | **73773** |

### transfer

| Contract | Gas Cost |
| ----------------- | --------- |
| OpenZeppelinERC20 | 51496 |
| SolmateERC20 | 51251 |
| YulERC20 | **51167** |
| YulERC20 | 51167 |
| YulERC20Ext | **51073** |

### transferFrom

| Contract | Gas Cost |
| ----------------- | --------- |
| OpenZeppelinERC20 | 33697 |
| SolmateERC20 | 31995 |
| YulERC20 | **31748** |
| YulERC20 | 31748 |
| YulERC20Ext | **31688** |

### allowance

| Contract | Gas Cost |
| ----------------- | --------- |
| OpenZeppelinERC20 | 24578 |
| SolmateERC20 | 24557 |
| YulERC20 | **24557** |
| YulERC20 | 24557 |
| YulERC20Ext | **24503** |

### balanceOf

| Contract | Gas Cost |
| ----------------- | --------- |
| OpenZeppelinERC20 | 23993 |
| SolmateERC20 | **23984** |
| SolmateERC20 | 23984 |
| YulERC20 | 23987 |
| YulERC20Ext | **23939** |

### burn

Expand All @@ -90,14 +102,16 @@ yarn test
| OpenZeppelinERC20 | 28900 |
| SolmateERC20 | 28768 |
| YulERC20 | **28646** |
| YulERC20Ext | **28646** |

### decimals

| Contract | Gas Cost |
| ----------------- | --------- |
| OpenZeppelinERC20 | 21286 |
| SolmateERC20 | 21313 |
| YulERC20 | **21286** |
| YulERC20 | 21286 |
| YulERC20Ext | **21262** |

### mint

Expand All @@ -106,22 +120,25 @@ yarn test
| OpenZeppelinERC20 | 51317 |
| SolmateERC20 | 51194 |
| YulERC20 | **51118** |
| YulERC20Ext | **51118** |

### name

| Contract | Gas Cost |
| ----------------- | --------- |
| OpenZeppelinERC20 | 24284 |
| SolmateERC20 | 24276 |
| YulERC20 | **21571** |
| YulERC20 | 21571 |
| YulERC20Ext | **21281** |

### symbol

| Contract | Gas Cost |
| ----------------- | --------- |
| OpenZeppelinERC20 | 24282 |
| SolmateERC20 | 24274 |
| YulERC20 | **21580** |
| YulERC20 | 21580 |
| YulERC20Ext | **21279** |

### totalSupply

Expand All @@ -130,3 +147,4 @@ yarn test
| OpenZeppelinERC20 | 23413 |
| SolmateERC20 | 23427 |
| YulERC20 | **23413** |
| YulERC20Ext | **23385** |
14 changes: 6 additions & 8 deletions contracts/ERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
// solhint-disable-next-line compiler-version
pragma solidity ^0.8.4;

/// @notice ERC20 using max inline assembly, with solidity translation comments in assembly blocks
/// @notice ERC20 (including EIP-2612 Permit) using max inline assembly.
/// @author kassandra.eth
/// NOTE Inspiration taken from Solmate and OpenZeppelin ERC20 implementations
/// Solmate repo: https://github.com/transmissions11/solmate
/// OZ repo: https://github.com/OpenZeppelin/openzeppelin-contracts
/// @dev name_ and symbol_ string contructor args must be 32 bytes or smaller
/// Do not manually set _balances without updating _supply (could cause math problems)
/// Do not adjust state layout here without fixing hardcoded sload/sstore slots across logic
/// We use custom errors for efficient but useful reverts
/// Solidity translation comments assume same 0.8+ solidity version
/// Inline assembly blocks have solidity translation comments! (Assume same 0.8+ solidity version)

// solhint-disable-next-line max-states-count
abstract contract ERC20 {
Expand Down Expand Up @@ -403,12 +406,7 @@ abstract contract ERC20 {
}

// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR()
public
view
virtual
returns (bytes32 domainSeparator)
{
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return
block.chainid == _initialChainId
? _initialDomainSeparator
Expand Down
Loading

0 comments on commit b10b6d0

Please sign in to comment.