Skip to content

Commit

Permalink
Merge pull request #9 from charlie-g-cowan/cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
d1ll0n authored Feb 17, 2020
2 parents 319d9b5 + 10f8402 commit 3e3b0e0
Show file tree
Hide file tree
Showing 17 changed files with 717 additions and 89 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
.huff
51 changes: 51 additions & 0 deletions .eslintrc.js
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
}
]
}
};
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
.nyc_output
.nyc_output
yarn.lock
6 changes: 6 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
example
testData
*.spec.js
.eslintignore
.eslintrc.js
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,8 @@ console.log('macro return data = ', returnValue);
console.log('output stack state = ', stack);
console.log('output memory state = ', memory);
```

### **Testing**

Tests can be run with `yarn test`. Example contracts, such as the ERC20 implementation, can be tested with `yarn exampletest`.

17 changes: 17 additions & 0 deletions example/erc20/README.md
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)
270 changes: 270 additions & 0 deletions example/erc20/erc20.huff
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

}
Loading

0 comments on commit 3e3b0e0

Please sign in to comment.