Skip to content

Commit

Permalink
Merge pull request #61 from pentagonxyz/md/factory
Browse files Browse the repository at this point in the history
feat: Proxy + Clones
  • Loading branch information
refcell authored Sep 23, 2022
2 parents 82b7e8e + 78ab96f commit 31e4d47
Show file tree
Hide file tree
Showing 17 changed files with 1,132 additions and 10 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ A set of **modern**, **opinionated**, and **secure** [Huff](https://github.com/h
> Although contracts have been rigorously reviewed, this is **experimental software** and is provided on an "as is" and "as available" basis.
> We **do not give any warranties** and **will not be liable for any loss** incurred through any use of this codebase.

### Usage

To install with [**Foundry**](https://github.com/foundry-rs/foundry):
**Recommended** To install with [**Foundry**](https://github.com/foundry-rs/foundry):

```sh
forge install pentagonxyz/huffmate
Expand All @@ -38,9 +37,9 @@ auth
data-structures
├─ Arrays — "Memory translation handlers for arrays"
├─ Hashmap — "Simple mapping utilities for 32 byte words"
factories
├─ FactoryTODO
├─ ProxyFactoryTODO
proxies
├─ Clones"Clones library for deploying minimal proxy contracts"
├─ Proxy"Minimal ERC1967-compliant + upgradeable proxy contract"
mechanisms
| ├─ huff-clones — "Library for creating clone contracts with immutable arguments"
| | ├─ ExampleClone — "Example clones-with-immutable-args clone contract"
Expand Down Expand Up @@ -84,9 +83,11 @@ These contracts were inspired by or directly modified from many sources, primari

- [solmate](https://github.com/transmissions11/solmate)
- [solady](https://github.com/Vectorized/solady)
- [zolidity](https://github.com/z0r0z/zolidity)
- [huff-examples](https://github.com/huff-language/huff-examples)
- [huff-rs](https://github.com/huff-language/huff-rs)
- [huff-clones](https://github.com/clabby/huff-clones)
- [huff-vrgda](https://github.com/cheethas/huff-vrgda)
- [huff-tests](https://github.com/abigger87/huff-tests)
- [erc721h](https://github.com/philogy/erc721h)
- [Gnosis](https://github.com/gnosis/gp-v2-contracts)
Expand Down
4 changes: 4 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ fs_permissions = [
{ access = "read", path = "./test/mechanisms/huff-vrgda/mocks/LinearVRGDAWrappers.huff" },
{ access = "read", path = "./test/mechanisms/huff-vrgda/mocks/LogisticVRGDAWrappers.huff" },

{ access = "read", path = "./test/proxies/mocks/ClonesWrappers.huff" },
{ access = "read", path = "./test/proxies/mocks/ProxyWrappers.huff" },
{ access = "read", path = "./test/proxies/mocks/ProxyFactoryWrappers.huff" },

{ access = "read", path = "./test/tokens/mocks/ERC20MintableWrappers.huff" },
{ access = "read", path = "./test/tokens/mocks/ERC20Wrappers.huff" },
{ access = "read", path = "./test/tokens/mocks/ERC721Wrappers.huff" },
Expand Down
154 changes: 154 additions & 0 deletions src/proxies/Clones.huff
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/// @title Clones
/// @notice SPDX-License-Identifier: MIT
/// @author Maddiaa <https://github.com/cheethas>
/// @author asnared <https://github.com/abigger87>
/// @notice https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for deploying minimal proxy contracts, also known as "clones".
/// @notice To simply and cheaply clone contract functionality in an immutable way, this standard specifies
/// a minimal bytecode implementation that delegates all calls to a known, fixed address.
///
/// @notice The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
/// (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
/// deterministic method.
/// @notice Adapted from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Clones.sol)

#include "./ERC1967Upgrade.huff"
#include "../utils/CommonErrors.huff"

// BEFORE ADDRESS
//--------------------------------------------------------------------------------//
// Opcode | Opcode + Arguments | Description | Stack View //
//--------------------------------------------------------------------------------//
// 0x3d | 0x36 | RETURNDATASIZE | 0 //
// 0x60 | 0x602d | PUSH1 0x2d | 0x2d 0 //
// 0x80 | 0x36 | DUP1 | 0x2d 0x2d 0 //
// 0x60 | 0x600a | PUSH1 0x0a | 0x0a 0x2d 0x2d 0 //
// 0x3d | 0x3d | RETURNDATASIZE | 0 0x0a 0x2d 0x2d 0 //
// 0x39 | 0x39 | CODECOPY | 0x2d 0 //
// 0x81 | 0x81 | DUP2 | 0 0x2d 0 //
// 0xf3 | 0xf3 | RETURN | 0 //

// 0x36 | 0x36 | CALLDATASIZE | size //
// 0x3d | 0x3d | RETURNDATASIZE | 0 size //
// 0x3d | 0x3d | RETURNDATASIZE | 0 0 size //
// 0x37 | 0x37 | CALLDATACOPY | //
// 0x3d | 0x3d | RETURNDATASIZE | 0 //
// 0x3d | 0x3d | RETURNDATASIZE | 0 0 //
// 0x3d | 0x3d | RETURNDATASIZE | 0 0 0 //
// 0x36 | 0x36 | CALLDATASIZE | size 0 0 0 //
// 0x3d | 0x3d | RETURNDATASIZE | 0 size 0 0 0 //
// 0x73 | 0x73 | PUSH20 <addr> | addr 0 size 0 0 0 //

// AFTER ADDRESS
//--------------------------------------------------------------------------------//
// Opcode | Opcode + Arguments | Description | Stack View //
//--------------------------------------------------------------------------------//
// 0x5a | 0x5a | GAS | gas addr 0 size 0 0 0 //
// 0xf4 | 0xf4 | DELEGATECALL | success 0 //
// 0x3d | 0x3d | RETURNDATASIZE | rds success 0 //
// 0x82 | 0x82 | DUP3 | 0 rds success 0 //
// 0x80 | 0x80 | DUP1 | 0 0 rds success 0 //
// 0x3e | 0x3e | RETURNDATACOPY | success 0 //
// 0x90 | 0x90 | SWAP1 | 0 success //
// 0x3d | 0x3d | RETURNDATASIZE | rds 0 success //
// 0x91 | 0x91 | SWAP2 | success rds 0 //
// 0x60 | 0x602b | PUSH1 0x2b | 0x2b success rds 0 //
// 0x57 | 0x57 | JUMPI | Revert if success == 0 //
// 0xfd | 0xfd | REVERT | //
// 0x5b | 0x5b | JUMPDEST | //
// 0xf3 | 0xf3 | RETURN | //
//--------------------------------------------------------------------------------//

#define constant BYTECODE_BEFORE_ADDRESS = 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000
#define constant BYTECODE_AFTER_ADDRESS = 0x5af43d82803e903d91602b57fd5bf3

/// @notice Clone a contract using `create`.
/// @param {Stack} Implementation - address of the contract to clone.
#define macro CLONE() = takes (1) returns (1) {
CLONE_MACRO(create)
}

/// @notice Clone a contract to a deterministic address using `create2`.
/// @param {Stack} Implementation - address of the contract to clone.
/// @param {Stack} Salt - The salt to be added to create2.
#define macro CLONE_DETERMINISTIC() = takes (2) returns (1) {
CLONE_MACRO(create2)
}

/// @dev Can remain inside the scratch space therefore no memory pointer is required
#define macro CLONE_MACRO(deploy_opcode) = takes (2) returns (1) {
// Input Stack: [implementation, salt [optional]]

// Store the prefix
__RIGHTPAD(0x3d602d80600a3d3981f3363d3d373d3d3d363d73) // [prefix, implementation, salt]
0x00 mstore // [implementation, salt]

// Place the implementation at memory byte 20
0x60 shl // [rightpad(implementation), salt]
0x14 mstore // [salt]

// Add the suffix after the implementation at byte 40
__RIGHTPAD(0x5af43d82803e903d91602b57fd5bf3) // [suffix, salt]
0x28 mstore // [salt]

// Create the contract
0x37 // [0x37, salt]
0x00 // [0x00, 0x37, salt]
0x00 // [0x00, 0x00, 0x37, salt]
<deploy_opcode> // [address] * This will be create | create2

// Throw exception if deployment fails
dup1 iszero create_failed jumpi // [address]
continue jump

create_failed:
DEPLOYMENT_FAILED(0x00)

continue:
}


/// @dev Memory pointer required as this function nukes memory and this is part of a library
#define macro PREDICT_DETERMINISTIC_ADDRESS(ptr) = takes (3) returns (1) {
// Input Stack: [implementation, salt, deployer]
swap1 swap2 swap1 // [implementation, deployer, salt]

// Store the creation code prefix at memory byte 0
__RIGHTPAD(0x3d602d80600a3d3981f3363d3d373d3d3d363d73) // [prefix, implementation, deployer, salt]
<ptr> mstore // [implementation, deployer, salt]

// Store the implementation address at memory byte 20
0x60 shl // [rightpad(implementation), deployer, salt]
<ptr> 0x14 add // [ptr + 0x14, implementation, deployer, salt]
mstore // [deployer, salt]

// Store the creation code suffix at memory byte 40
__RIGHTPAD(0x5af43d82803e903d91602b57fd5bf3ff) // [bytecode_after, deployer, salt]
<ptr> 0x28 add // [ptr + 0x28, bytecode_after, deployer, salt]
mstore // [deployer, salt]

// mstore(add(ptr, 0x38), deployer)
0x60 shl // [rightpad(deployer), salt]
<ptr> 0x38 add // [ptr + 0x38, deployer, salt]
mstore // [salt]

// mstore(add(ptr, 0x58), salt)
<ptr> 0x4c add // [ptr + 0x58, salt]
mstore // []

// Hash and then store in memory
0x37 // [0x37]
<ptr> // [ptr, 0x37]
sha3 // [hash]

<ptr> 0x6c add // [ptr + 0x6c, hash]
mstore // []

// Hash the rest of the data
0x55 // [0x55]
<ptr> 0x37 add // [ptr + 0x37, 0x55]
sha3 // [hash]

// Clean the upper 96 bits (12 bytes) of the hash
// The remaining 160 bits (20 bytes) are the address
0x60 shl 0x60 shr // [clean(hash)]
}
22 changes: 22 additions & 0 deletions src/proxies/ERC1967Proxy.huff
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// @title ERC1967 Proxy
/// @notice SPDX-License-Identifier: MIT
/// @author asnared <https://github.com/abigger87>
/// @notice An upgradeable proxy that uses the ERC1967 storage layout.
/// @notice Adapted from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/ERC1967/ERC1967Proxy.sol)

#include "./Proxy.huff"
#include "./ERC1967Upgrade.huff"

/// @notice An internal constructor that upgrades the proxy to the implementation and calls the implementation
#define macro ERC1967_PROXY_CONSTRUCTOR() = takes (0) returns (0) {
0x00 // [forceCall]
0x24 calldataload // [data, forceCall]
0x04 calldataload // [address, data, forceCall]
UPGRADE_TO_AND_CALL() // []
}

/// @notice Returns the current implementation address
/// @notice Overrideable
#define macro IMPLEMENTATION() = takes (0) returns (1) {
GET_IMPLEMENTATION()
}
Loading

0 comments on commit 31e4d47

Please sign in to comment.