-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from charlie-g-cowan/cleanup
- Loading branch information
Showing
17 changed files
with
717 additions
and
89 deletions.
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 |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/node_modules | ||
.huff |
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 |
---|---|---|
@@ -0,0 +1,51 @@ | ||
module.exports = { | ||
"extends": "airbnb-base", | ||
"env": { | ||
"mocha": true, | ||
"node": true, | ||
"browser": true | ||
}, | ||
"rules": { | ||
"strict": 0, | ||
"arrow-body-style": 0, | ||
"comma-dangle": [ | ||
"error", | ||
{ | ||
"arrays": "always-multiline", | ||
"objects": "always-multiline", | ||
"imports": "always-multiline", | ||
"exports": "always-multiline", | ||
"functions": "never" | ||
} | ||
], | ||
"import/no-extraneous-dependencies": 0, | ||
"indent": [ | ||
"error", | ||
4, | ||
{ | ||
"SwitchCase": 1 | ||
} | ||
], | ||
"linebreak-style": 0, | ||
"no-console": 0, | ||
"no-underscore-dangle": [ | ||
"error", | ||
{ | ||
"allow": [ | ||
"_id" | ||
] | ||
} | ||
], | ||
"prefer-template": 0, | ||
"max-len": [ | ||
"warn", | ||
130, | ||
{ | ||
"ignoreComments": true | ||
}, | ||
{ | ||
"ignoreTrailingComments": true | ||
} | ||
] | ||
} | ||
}; |
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,2 +1,3 @@ | ||
node_modules | ||
.nyc_output | ||
.nyc_output | ||
yarn.lock |
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 |
---|---|---|
@@ -0,0 +1,6 @@ | ||
node_modules | ||
example | ||
testData | ||
*.spec.js | ||
.eslintignore | ||
.eslintrc.js |
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
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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
## Mintable ERC20 implementation in Huff | ||
|
||
This is an ERC20 contract implemented in Huff to demonstrate the language's (very basic) syntax. It consists of three files: | ||
|
||
| filename | description | | ||
| -------------------- | --------------------------------------------------------------------------------------------------------------- | | ||
| `erc20.huff` | Huff source file | | ||
| `erc20_interface.js` | JavaScript methods allowing the user to easily run Huff macros corresponding to ERC20 methods (e.g. `transfer`) | | ||
| `erc20.spec.js` | Unit tests -- the Huff code really works! | | ||
|
||
(Example unit tests can be run from `/huff/` with `yarn exampletest`.) | ||
|
||
The process by which the Huff code was created is documented in a series of blog posts on Medium: | ||
1. [About Huff, constructor, and function selector](https://medium.com/aztec-protocol/from-zero-to-nowhere-smart-contract-programming-in-huff-1-2-ba2b6de7fa83) | ||
2. [Events, mappings, and `transfer`](https://medium.com/aztec-protocol/from-zero-to-nowhere-smart-contract-programming-in-huff-2-3-5438ef7e5beb) | ||
3. [`totalSupply`, `balanceOf`, and `mint`](https://medium.com/aztec-protocol/from-zero-to-nowhere-smart-contract-programming-in-huff-3-4-6b347e23d66e) | ||
4. [Nested mappings, `allowance`, `approve`, and `transferFrom`](https://medium.com/aztec-protocol/from-zero-to-nowhere-smart-contract-programming-in-huff-4-4-9e6c34648992) |
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 |
---|---|---|
@@ -0,0 +1,270 @@ | ||
#define macro BALANCE_LOCATION = takes(0) returns(1) { | ||
0x00 // do not change! | ||
} | ||
|
||
#define macro OWNER_LOCATION = takes(0) returns(1) { | ||
0x01 | ||
} | ||
|
||
#define macro TOTAL_SUPPLY_LOCATION = takes(0) returns(1) { | ||
0x02 | ||
} | ||
|
||
#define macro ALLOWANCE_LOCATION = takes(0) returns(1) { | ||
0x03 | ||
} | ||
|
||
#define macro ADDRESS_MASK = takes(1) returns(1) { | ||
0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff | ||
and | ||
} | ||
|
||
#define macro TRANSFER_EVENT_SIGNATURE = takes(0) returns(1) { | ||
0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF | ||
} | ||
|
||
#define macro APPROVAL_EVENT_SIGNATURE = takes(0) returns(1) { | ||
0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 | ||
} | ||
|
||
template <error_location> | ||
#define macro UTILS__NOT_PAYABLE = takes(0) returns(0) { | ||
callvalue <error_location> jumpi | ||
} | ||
|
||
#define macro UTILS__ONLY_OWNER = takes(0) returns(0) { | ||
OWNER_LOCATION() sload caller eq is_owner jumpi | ||
0x00 0x00 revert | ||
is_owner: | ||
} | ||
|
||
#define macro ERC20 = takes(0) returns(0) { | ||
caller OWNER_LOCATION() sstore | ||
} | ||
|
||
template <transfer, transfer_from, balance_of, allowance, approve, total_supply, mint, error_location> | ||
#define macro ERC20__FUNCTION_SIGNATURE = takes(0) returns(0) { | ||
0x00 calldataload 224 shr // function signature | ||
dup1 0x095ea7b3 eq <approve> jumpi | ||
dup1 0x18160ddd eq <total_supply> jumpi | ||
dup1 0x23b872dd eq <transfer_from> jumpi | ||
dup1 0x40c10f19 eq <mint> jumpi | ||
dup1 0x70a08231 eq <balance_of> jumpi | ||
dup1 0xa9059cbb eq <transfer> jumpi | ||
dup1 0xdd62ed3e eq <allowance> jumpi | ||
UTILS__NOT_PAYABLE<error_location>() | ||
0x00 0x00 return | ||
} | ||
|
||
#define macro ERC20__TRANSFER_INIT = takes(0) returns(6) { | ||
0x04 calldataload ADDRESS_MASK() | ||
caller | ||
TRANSFER_EVENT_SIGNATURE() | ||
0x20 | ||
0x00 | ||
0x24 calldataload | ||
// value 0x00 0x20 signature from to | ||
} | ||
|
||
#define macro ERC20__TRANSFER_GIVE_TO = takes(6) returns(7) { | ||
// value 0x00 0x20 signature from to | ||
dup6 0x00 mstore | ||
0x40 0x00 sha3 | ||
// key(balances[to]) value 0x00 0x20 signature from to | ||
dup1 sload | ||
// balances[to] key value 0x00 0x20 signature from to | ||
dup3 // v b k v 0x00 0x20 sig f t | ||
add // v+b k v 0x00 0x20 sig f t | ||
dup1 // v+b v+b k v 0x00 0x20 sig f t | ||
dup4 // v v+b v+b k v 0x00 0x20 sig f t | ||
gt // v>v+b v+b k v 0x00 0x20 sig f t | ||
swap2 // k v+b v>v+b v 0x00 0x20 sig f t | ||
sstore // v>v+b v 0x00 0x20 sig f t | ||
} | ||
|
||
template <from> | ||
#define macro ERC20__TRANSFER_TAKE_FROM = takes(7) returns(8) { | ||
// error_code value 0x00 0x20 signature from to | ||
<from> 0x00 mstore | ||
0x40 0x00 sha3 | ||
// key(balances[from]) error_code value 0x00 0x20 signature from to | ||
dup1 sload // balances[from] key error value 0x00 0x20 sig f t | ||
// b k e1 v 0 2 s f t | ||
dup4 dup2 // b v b k e1 v 0 2 s f t | ||
sub dup5 // v (b-v) b k e1 v 0 2 s f t | ||
swap3 // k (b-v) b v e1 v 0 2 s f t | ||
sstore // b v e1 v 0 2 s f t | ||
lt // error2 error1 value 0x00 0x20 signature from to | ||
} | ||
|
||
template <error_location> | ||
#define macro ERC20__TRANSFER = takes(0) returns(0) { | ||
ERC20__TRANSFER_INIT() | ||
ERC20__TRANSFER_GIVE_TO() | ||
ERC20__TRANSFER_TAKE_FROM<caller>() | ||
// error2 error1 value 0x00 0x20 signature from to | ||
callvalue or or <error_location> jumpi | ||
// value 0x00 0x20 signature from to | ||
0x00 mstore // value must be stored at 0x00 | ||
log3 | ||
0x01 0x00 mstore | ||
0x20 0x00 return | ||
} | ||
|
||
#define macro ERC20__TRANSFER_FROM_INIT = takes(0) returns(6) { | ||
0x24 calldataload ADDRESS_MASK() // stack: to | ||
0x04 calldataload ADDRESS_MASK() // stack: from to | ||
TRANSFER_EVENT_SIGNATURE() | ||
0x20 | ||
0x00 | ||
0x44 calldataload | ||
// stacK: value 0x00 0x20 signature from to | ||
} | ||
|
||
#define macro ERC20__TRANSFER_SUB_ALLOWANCE = takes(8) returns (9) { | ||
// stack: error2 error1 value 0x00 0x20 signature from to | ||
dup7 0x00 mstore | ||
ALLOWANCE_LOCATION() 0x20 mstore | ||
0x40 0x00 sha3 | ||
0x20 mstore | ||
caller 0x00 mstore | ||
0x40 0x00 sha3 | ||
// stack: key(allowances[from][msg.sender]) error2 error1 value 0x00 0x20 signature from to | ||
dup1 sload // allowance key e2 e1 v 0x00 0x20 s f t | ||
dup5 dup2 // a v a k e2 e1 v 0 2 s f t | ||
sub dup6 // v a-v a k e2 e1 v 0 2 s f t | ||
swap3 sstore // a v e2 e1 v 0 2 s f t | ||
lt // stack: error3 error2 error1 value 0x00 0x20 signature from to | ||
} | ||
|
||
template <error_location> | ||
#define macro ERC20__TRANSFER_FROM = takes(0) returns(0) { | ||
ERC20__TRANSFER_FROM_INIT() | ||
ERC20__TRANSFER_GIVE_TO() | ||
ERC20__TRANSFER_TAKE_FROM<dup6>() | ||
ERC20__TRANSFER_SUB_ALLOWANCE() | ||
// error3 error2 error1 value 0x00 0x20 signature from to | ||
callvalue or or or <error_location> jumpi | ||
// value 0x00 0x20 signature from to | ||
0x00 mstore | ||
log3 | ||
0x01 0x00 mstore | ||
0x20 0x00 return | ||
} | ||
|
||
template <error_location> | ||
#define macro ERC20__BALANCE_OF = takes(0) returns(0) { | ||
UTILS__NOT_PAYABLE<error_location>() | ||
0x04 calldataload ADDRESS_MASK() | ||
0x00 mstore | ||
0x40 0x00 sha3 // stacK: key(balances[owner]) | ||
sload // stack: balances[owner] | ||
0x00 mstore | ||
0x20 0x00 return | ||
} | ||
|
||
template <error_location> | ||
#define macro ERC20__ALLOWANCE = takes(0) returns(0) { | ||
UTILS__NOT_PAYABLE<error_location>() | ||
0x04 calldataload ADDRESS_MASK() | ||
0x00 mstore | ||
ALLOWANCE_LOCATION() 0x20 mstore | ||
0x40 0x00 sha3 | ||
// stack: key(allowances[owner]) | ||
0x20 mstore | ||
0x24 calldataload ADDRESS_MASK() | ||
0x00 mstore | ||
0x40 0x00 sha3 | ||
// stack: key(allowances[owner][spender]) | ||
sload | ||
0x00 mstore | ||
0x20 0x00 return | ||
} | ||
|
||
template <error_location> | ||
#define macro ERC20__APPROVE = takes(0) returns(0) { | ||
UTILS__NOT_PAYABLE<error_location>() | ||
0x04 calldataload ADDRESS_MASK() | ||
caller | ||
APPROVAL_EVENT_SIGNATURE() | ||
0x20 | ||
0x00 | ||
// stack: 0x00 0x20 signature msg.sender spender | ||
0x24 calldataload // get value | ||
dup1 | ||
// stack: value value 0x00 0x20 signature msg.sender spender | ||
caller 0x00 mstore | ||
ALLOWANCE_LOCATION() 0x20 mstore | ||
0x40 0x00 sha3 | ||
0x20 mstore | ||
dup7 0x00 mstore | ||
0x40 0x00 sha3 | ||
// stack: key(allowances[msg.sender][spender]) value value 0x00 0x20 signature msg.sender spender | ||
sstore | ||
0x00 mstore | ||
// stack: 0x00 0x20 signature msg.sender spender | ||
log3 | ||
0x01 0x00 mstore | ||
0x20 0x00 return | ||
} | ||
|
||
template <error_location> | ||
#define macro ERC20__TOTAL_SUPPLY = takes(0) returns(0) { | ||
UTILS__NOT_PAYABLE<error_location>() | ||
TOTAL_SUPPLY_LOCATION() sload | ||
0x00 mstore | ||
0x20 0x00 return | ||
} | ||
|
||
template <error_location> | ||
#define macro ERC20__MINT = takes(0) returns(0) { | ||
UTILS__ONLY_OWNER() | ||
0x04 calldataload ADDRESS_MASK() | ||
0 TRANSFER_EVENT_SIGNATURE() 0x20 0x00 | ||
0x24 calldataload | ||
// stack: value 0x00 0x20 signature from to | ||
ERC20__TRANSFER_GIVE_TO() | ||
// stack: error1 value 0x00 0x20 signature from to | ||
dup2 dup1 | ||
// stack: value value 0x00 0x20 signature from to | ||
TOTAL_SUPPLY_LOCATION() sload add dup1 TOTAL_SUPPLY_LOCATION() sstore | ||
lt | ||
// stack: error2 error1 0x00 0x20 signature from to | ||
callvalue or or <error_location> jumpi | ||
log3 | ||
0x01 0x00 mstore | ||
0x20 0x00 return | ||
} | ||
|
||
#define macro ERC20__MAIN = takes(0) returns(0) { | ||
|
||
ERC20__FUNCTION_SIGNATURE< | ||
transfer, | ||
transfer_from, | ||
balance_of, | ||
allowance, | ||
approve, | ||
total_supply, | ||
mint, | ||
throw_error | ||
>() | ||
|
||
transfer: | ||
ERC20__TRANSFER<throw_error>() | ||
transfer_from: | ||
ERC20__TRANSFER_FROM<throw_error>() | ||
balance_of: | ||
ERC20__BALANCE_OF<throw_error>() | ||
allowance: | ||
ERC20__ALLOWANCE<throw_error>() | ||
approve: | ||
ERC20__APPROVE<throw_error>() | ||
total_supply: | ||
ERC20__TOTAL_SUPPLY<throw_error>() | ||
mint: | ||
ERC20__MINT<throw_error>() | ||
|
||
throw_error: | ||
0x00 0x00 revert | ||
|
||
} |
Oops, something went wrong.