Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 50 additions & 34 deletions src/auth/RolesAuthority.huff
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,18 @@
#define constant IS_CAPABILITY_PUBLIC_LOCATION = FREE_STORAGE_POINTER()
#define constant GET_ROLES_WITH_CAPABILITY_LOCATION = FREE_STORAGE_POINTER()

/// @notice Helper to get the storage slot holding a user's roles
/// @dev Callers that both read and write the entry should use this and keep the slot on the
/// stack, rather than hashing it once per access
#define macro GET_ROLES_FOR_ACCOUNT_SLOT() = takes (1) returns (1) {
[USER_ROLES_LOCATION] // [location, account]
MAPPING_SLOT() // [slot]
}

/// @notice Helper to get the roles for a user
#define macro GET_ROLES_FOR_ACCOUNT() = takes (1) returns (1) {
[USER_ROLES_LOCATION] // [location, account]
LOAD_ELEMENT_FROM_KEYS(0x00) // [roles]
GET_ROLES_FOR_ACCOUNT_SLOT() // [slot]
sload // [roles]
}

/// @notice Returns if an account has a role
Expand All @@ -45,9 +53,18 @@
0x20 0x00 return // []
}

/// @notice Helper to get the storage slot holding the roles with a capability
/// @dev Callers that both read and write the entry should use this and keep the slot on the
/// stack, rather than hashing it once per access
#define macro GET_ROLE_FOR_CAPABILITY_SLOT() = takes (2) returns (1) {
// Input stack: [target, functionSig]
MAPPING_SLOT() // [slot]
}

/// @notice Helper to get the role for a capability
#define macro GET_ROLE_FOR_CAPABILITY() = takes (2) returns (1) {
LOAD_ELEMENT_FROM_KEYS(0x00) // [role]
GET_ROLE_FOR_CAPABILITY_SLOT() // [slot]
sload // [role]
}

/// @notice Checks if a Role has a Capability
Expand All @@ -67,7 +84,8 @@

/// @notice Helper to get if a capability is public
#define macro IS_CAPABILITY_PUBLIC() = takes (2) returns (1) {
LOAD_ELEMENT_FROM_KEYS(0x00) // [public]
MAPPING_SLOT() // [slot]
sload // [public]
}

/// @notice Checks if an account can call a function on a given address
Expand Down Expand Up @@ -145,39 +163,38 @@

// Disable the capability
disable:
// Get the current roles with the capability
// Get the current roles with the capability. The entry is read and written, so hash it
// once and keep the slot on the stack
0x44 calldataload // [sig]
0x24 calldataload // [target, sig]
GET_ROLE_FOR_CAPABILITY() // [roles]
GET_ROLE_FOR_CAPABILITY_SLOT() // [slot]
dup1 sload // [roles, slot]

// Shift 1 left the role
0x01 0x04 calldataload shl // [role, roles]
not // [others, roles]
and // [updated]
0x01 0x04 calldataload shl // [role, roles, slot]
not // [others, roles, slot]
and // [updated, slot]

// Store the new capability
0x44 calldataload // [sig, updated]
0x24 calldataload // [target, sig, updated]
STORE_ELEMENT_FROM_KEYS(0x00) // []
swap1 sstore // []

// Jump to the emit log label
emit_log jump

// Enable the capability
enable:
// Get the current roles with the capability
// Get the current roles with the capability, hashing the entry once
0x44 calldataload // [sig]
0x24 calldataload // [target, sig]
GET_ROLE_FOR_CAPABILITY() // [roles]
GET_ROLE_FOR_CAPABILITY_SLOT() // [slot]
dup1 sload // [roles, slot]

// Shift 1 left the role
0x01 0x04 calldataload shl // [role, roles]
or // [capabilies]
0x01 0x04 calldataload shl // [role, roles, slot]
or // [capabilies, slot]

// Store the new capability
0x44 calldataload // [sig, capabilies]
0x24 calldataload // [target, sig, capabilies]
STORE_ELEMENT_FROM_KEYS(0x00) // []
swap1 sstore // []

// Emit the capability updated event
emit_log:
Expand Down Expand Up @@ -208,37 +225,36 @@

// Disable the role
disable:
// Get the account roles
// Get the account roles. The entry is read and written, so hash it once and keep the
// slot on the stack
0x04 calldataload // [account]
GET_ROLES_FOR_ACCOUNT() // [roles]
GET_ROLES_FOR_ACCOUNT_SLOT() // [slot]
dup1 sload // [roles, slot]

// Shift 1 left the role
0x01 0x24 calldataload shl // [new_role, roles]
not // [others, roles]
and // [updated]
0x01 0x24 calldataload shl // [new_role, roles, slot]
not // [others, roles, slot]
and // [updated, slot]

// Store the new roles
0x04 calldataload // [account, updated]
[USER_ROLES_LOCATION] // [key, account, updated]
STORE_ELEMENT_FROM_KEYS(0x00) // []
swap1 sstore // []

// Jump to the emit log label
emit_log jump

// Enable the role
enable:
// Get the account roles
// Get the account roles, hashing the entry once
0x04 calldataload // [account]
GET_ROLES_FOR_ACCOUNT() // [roles]
GET_ROLES_FOR_ACCOUNT_SLOT() // [slot]
dup1 sload // [roles, slot]

// Shift 1 left the role
0x01 0x24 calldataload shl // [new_role, roles]
or // [updated]
0x01 0x24 calldataload shl // [new_role, roles, slot]
or // [updated, slot]

// Store the new roles
0x04 calldataload // [account, updated]
[USER_ROLES_LOCATION] // [key, account, updated]
STORE_ELEMENT_FROM_KEYS(0x00) // []
swap1 sstore // []


// Emit the user role updated event
Expand Down
33 changes: 33 additions & 0 deletions src/data-structures/Hashmap.huff
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,39 @@
sha3 // [slot3]
}

/// @notice Computes the storage slot of `mapping[key]`
#define macro MAPPING_SLOT() = takes(2) returns(1) {
// Input stack: [base_slot, key]
0x20 mstore // [key]
0x00 mstore // []
0x40 0x00 sha3 // [slot]
}

/// @notice Computes the storage slot of `mapping[key1][key2]`
#define macro MAPPING_SLOT_2D() = takes(3) returns(1) {
// Input stack: [base_slot, key1, key2]
0x20 mstore // [key1, key2]
0x00 mstore // [key2]
0x40 0x00 sha3 // [slot_1, key2]
0x20 mstore // [key2]
0x00 mstore // []
0x40 0x00 sha3 // [slot]
}

/// @notice Computes the storage slot of `mapping[key1][key2][key3]`
#define macro MAPPING_SLOT_3D() = takes(4) returns(1) {
// Input stack: [base_slot, key1, key2, key3]
0x20 mstore // [key1, key2, key3]
0x00 mstore // [key2, key3]
0x40 0x00 sha3 // [slot_1, key2, key3]
0x20 mstore // [key2, key3]
0x00 mstore // [key3]
0x40 0x00 sha3 // [slot_2, key3]
0x20 mstore // [key3]
0x00 mstore // []
0x40 0x00 sha3 // [slot]
}

/// @notice Load an element onto the stack from a key
#define macro LOAD_ELEMENT(mem_ptr) = takes(1) returns(1) {
// Input stack: [key]
Expand Down
4 changes: 2 additions & 2 deletions src/tokens/ERC1155.huff
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@
#define macro DECREASE_BALANCE() = takes (3) returns (0) {
// takes 3 [from, tokenId, amount]
[BALANCE_LOCATION] // [&balance, from, tokenId, amount]
GET_SLOT_FROM_KEYS_2D(0x00) // [slot, amount]
MAPPING_SLOT_2D() // [slot, amount]
dup1 // [slot, slot, amount]
sload // [bal, slot, amount]
swap1 // [slot, bal, amount]
Expand All @@ -700,7 +700,7 @@
// input stack: [to, tokenId, amount]

[BALANCE_LOCATION] // [&balance, to, tokenId, amount]
GET_SLOT_FROM_KEYS_2D(0x00) // [slot, amount]
MAPPING_SLOT_2D() // [slot, amount]
dup1 // [slot, slot,amount]
sload // [bal, slot, amount]
swap1 // [slot, bal, amount]
Expand Down
96 changes: 47 additions & 49 deletions src/tokens/ERC20.huff
Original file line number Diff line number Diff line change
Expand Up @@ -152,40 +152,36 @@
0x04 calldataload // [from, to]
caller // [msg.sender, from, to]
dup2 // [from, msg.sender, from, to]
[APPROVAL_SLOT] // [slot, from, msg.sender, from, to]

// Check for max approval
LOAD_ELEMENT_FROM_KEYS_2D(0x00) // [approved, from, to]
dup1 // [approved, approved, from, to]
0x44 calldataload // [value, approved, approved, from, to]
[APPROVAL_SLOT] MAPPING_SLOT_2D() // [slot, from, to]
dup1 sload // [approved, slot, from, to]
0x44 calldataload // [value, approved, slot, from, to]

// Check isOwner
dup4 // [from, value, approved, approved, from, to]
caller // [msg.sender, from, value, approved, approved, from, to]
eq // [msg.sender == from, value, approved, approved, from, to]
approved1 jumpi // [value, approved, approved, from, to]
dup4 // [from, value, approved, slot, from, to]
caller // [msg.sender, from, value, approved, slot, from, to]
eq // [msg.sender == from, value, approved, slot, from, to]
approved1 jumpi // [value, approved, slot, from, to]

// Check max approval
dup2 // [approved, value, approved, approved, from, to]
[UINT_256_MAX] // [type(uint).max, approved, value, approved, approved, from, to]
eq // [type(uint).max == approved, value, approved, approved, from, to]
approved1 jumpi // [value, approved, approved, from, to]
dup2 // [approved, value, approved, slot, from, to]
[UINT_256_MAX] // [type(uint).max, approved, value, approved, slot, from, to]
eq // [type(uint).max == approved, value, approved, slot, from, to]
approved1 jumpi // [value, approved, slot, from, to]

// Check has approval
gt // [value > approved, approved, from, to]
insufficientApproval jumpi // [approved, from, to]
dup2 dup2 // [value, approved, value, approved, slot, from, to]
gt // [value > approved, value, approved, slot, from, to]
insufficientApproval jumpi // [value, approved, slot, from, to]

// Adjust approval
0x44 calldataload // [value, approved, from, to]
swap1 // [approved, value, from, to]
sub // [approved - value => newApprovalValue, from, to]
caller // [msg.sender, newApprovalValue, from, to]
dup3 // [from, msg.sender, newApprovalValue, from, to]
[APPROVAL_SLOT] // [slot, from, msg.sender, newApprovalValue, from, to]
STORE_ELEMENT_FROM_KEYS_2D(0x00) // [from, to]
swap1 // [approved, value, slot, from, to]
sub // [approved - value => newApprovalValue, slot, from, to]
swap1 // [slot, newApprovalValue, from, to]
sstore // [from, to]
approved2 jump // [from, to]

approved1: // [value, approved, approved, from, to]
approved1: // [value, approved, slot, from, to]
pop pop pop // [from, to]

approved2: // [from, to]
Expand All @@ -212,34 +208,36 @@
/// @notice Transfers an amount of tokens from
#define macro _TRANSFER_TAKE_FROM() = takes (3) returns (3) {
// input stack: [value, from, to]
dup2 [BALANCE_SLOT] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance, value, from, to] // [from, value, from, to]
dup1 // [balance, balance, value, from, to]
dup3 // [value, balance, balance, value, from, to]
gt // [value > balance, balance, value, from, to]
iszero // [value <= balance, balance, value, from, to]
valid jumpi // [balance, value, from, to]
dup2 // [from, value, from, to]
[BALANCE_SLOT] MAPPING_SLOT() // [slot, value, from, to]
dup1 sload // [balance, slot, value, from, to]
dup1 // [balance, balance, slot, value, from, to]
dup4 // [value, balance, balance, slot, value, from, to]
gt // [value > balance, balance, slot, value, from, to]
iszero // [value <= balance, balance, slot, value, from, to]
valid jumpi // [balance, slot, value, from, to]

// Insufficient balance
0x00 0x00 revert // []

// Update the sender's balance.
valid:
dup2 // [value, balance, value, from, to]
swap1 // [balance, value, value, from, to]
sub // [balance - value, value, from, to]
dup3 // [from, balance - value, value, from, to]
[BALANCE_SLOT] STORE_ELEMENT_FROM_KEYS(0x00) // [value, from, to]
dup3 // [value, balance, slot, value, from, to]
swap1 // [balance, value, slot, value, from, to]
sub // [balance - value, slot, value, from, to]
swap1 // [slot, balance - value, value, from, to]
sstore // [value, from, to]
}

/// @notice Transfers an amount of tokens from one address to another.
#define macro _TRANSFER_GIVE_TO() = takes (3) returns (3) {
// input stack: [value, from, to]
dup1 // [value, value, from, to]
dup4 // [to, value, value, from, to]
[BALANCE_SLOT] LOAD_ELEMENT_FROM_KEYS(0x00) // [balance, value, value, from, to]
add // [balance + value, value, from, to]
dup4 // [to, balance + value, value, from, to]
[BALANCE_SLOT] STORE_ELEMENT_FROM_KEYS(0x00) // [value, from, to]
dup3 // [to, value, from, to]
[BALANCE_SLOT] MAPPING_SLOT() // [slot, value, from, to]
dup1 sload // [balance, slot, value, from, to]
dup3 add // [balance + value, slot, value, from, to]
swap1 // [slot, balance + value, value, from, to]
sstore // [value, from, to]
}

/// @notice Domain Separator
Expand Down Expand Up @@ -425,15 +423,15 @@
/// @notice Increments the nonce for next time,
#define macro _NONCE_PLUS_PLUS() = takes (1) returns (1) {
// input stack // [account]
dup1 // [account, account]
[NONCE_SLOT] LOAD_ELEMENT_FROM_KEYS(0x00) // [currentNonce, account]
dup1 // [currentNonce, currentNonce, account]
0x01 // [1, currentNonce, currentNonce, account]
add // [nextNonce, currentNonce, account]
dup3 // [account, nextNonce, currentNonce, account]
[NONCE_SLOT] STORE_ELEMENT_FROM_KEYS(0x00) // [currentNonce, account]
swap1 // clean up stack // [account, currentNonce]
pop // clean up stack // [currentNonce]
[NONCE_SLOT] MAPPING_SLOT() // [slot]
dup1 // [slot, slot]
sload // [currentNonce, slot]
dup1 // [currentNonce, currentNonce, slot]
0x01 // [1, currentNonce, currentNonce, slot]
add // [nextNonce, currentNonce, slot]
swap1 // [currentNonce, nextNonce, slot]
swap2 // [slot, nextNonce, currentNonce]
sstore // [currentNonce]
}

/// @notice Nonces
Expand Down
Loading
Loading