Git Product home page Git Product logo

huffmate's Introduction

huffmate • ci version license Discord

A set of modern, opinionated, and secure Huff contracts.

Warning

These contracts are unaudited and are not recommended for use in production.

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

Recommended To install with Foundry:

forge install huff-language/huffmate

To install with Hardhat or Truffle:

npm install @pentagonxyz/huffmate

Contracts

auth
├─ Auth — "Flexible and updatable auth pattern"
├─ NonPayable — "Modifier Macro that reverts the tx when msg.value > 0"
├─ OnlyContract — "Basic Macro that reverts when the sender is an EOA"
├─ Owned — "Simple single owner authorization"
├─ RolesAuthority — "Role based Authority that supports up to 256 roles"
data-structures
├─ Arrays — "Memory translation handlers for arrays"
├─ Hashmap — "Simple mapping utilities for 32 byte words"
├─ Bytes — "Helpers for working with Bytes"
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"
|  |  ├─ ExampleCloneFactory — "Example clones-with-immutable-args factory contract"
|  |  ├─ HuffClone — "Clones-with-immutable-args Clone Instance"
|  |  └─ HuffCloneLib — "Library for creating a HuffClone"
|  └─ huff-vrgda — "Variable Rate Gradual Dutch Auctions written in Huff"
|      ├─ LinearVRGDA — "VRGDA with a linear issuance curve"
|      ├─ LogisticVRGDA — "VRGDA with a logistic issuance curve"
|      └─ VRGDA — "Sell tokens roughly according to an issuance schedule"
math
├─ FixedPointMath — "Arithmetic library with operations for fixed-point numbers"
├─ Math — "Refactored, common arithmetic macros"
├─ SafeMath — "Safe Wrappers over primitive arithmetic operations"
├─ Trigonometry — "Basic trigonometry functions where inputs and outputs are integers"
tokens
├─ ERC20 — "Modern and gas efficient ERC20 + EIP-2612 implementation"
├─ ERC721 — "Modern, minimalist, and gas efficient ERC721 implementation"
├─ ERC1155 — "Minimalist and gas efficient standard ERC1155 implementation"
├─ ERC4626 — "Minimal ERC4626 tokenized Vault implementation"
utils
├─ Address — "Simple Utils for working with addresses"
├─ BitPackLib — "Efficient bit packing library"
├─ Calls — "Minimal wrappers for constructing calls to other contracts"
├─ CommonErrors — "Wrappers for reverting with common error messages"
├─ CREATE3 — "Deploy to deterministic addresses without the initcode factor"
├─ ECDSA — "An optimised ECDSA wrapper"
├─ ERC1155Receiver — "A minimal interface for receiving ERC1155 tokens"
├─ ERC20Transfer — "Efficient ERC20 transfer wrappers"
├─ Errors — "Custom error utilities"
├─ Ethers — "Utilities for working with ether at a low level"
├─ JumpTableUtil — "Utility macros for retrieving jumpdest pcs from jump tables"
├─ LibBit — "A library ported from solady for bit twiddling operations"
├─ MerkleProofLib — "Gas optimized merkle proof verification library"
├─ Multicallable — "Enables a single call to call multiple methods within a contract"
├─ Pausable — "An implementation of the Pausable standard"
├─ ReentrancyGuard — "Gas optimized reentrancy protection for smart contracts"
├─ Refunded — "Efficient gas refunds distributed through a modifier"
├─ SafeTransferLib — "Safe ETH and ERC20 transfer library that gracefully handles missing return values"
├─ Shuffling — "Refactored algorithms for shuffling and other bitwise algorithms"
└─ SSTORE2 — "Faster & cheaper contract key-value storage for Ethereum Contracts"
└─ Ternary — "A collection of ternary operations with abstracted conditional logic"
└─ TSOwnable — "An Ownable Implementation using Two-Step Transfer Pattern"

Acknowledgements

These contracts were inspired by or directly modified from many sources, primarily:

huffmate's People

Contributors

0xdaizz avatar amadimichael avatar benleim avatar clabby avatar d1ll0n avatar devtooligan avatar eugenioclrc avatar exp-table avatar goncalomagalhaes avatar ifrostizz avatar jetjadeja avatar jtriley-eth avatar kadenzipfel avatar maddiaa0 avatar manasbir avatar mathisgd avatar merlinegalite avatar obatirou avatar omsify avatar praneshasp avatar rabib avatar refcell avatar sarhaang avatar tanim0la avatar zakrad avatar zarfsec avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

huffmate's Issues

feat(v2): Safe Operations with Low Level Integers

Description

Pending #103, implementations for safely operating on low level integer types in huff can be done.

As detailed by @AmadiMichael:

Example: an extra macro in the safeMath library called SAFE_ADD_TYPE(), the same as SAFE_ADD() but would take a third stack input which is the max value of the intended type to cast the result into

/// a rewrite of safe add with max type

/// @notice Adds two numbers and reverts on overflow
#define macro SAFE_ADD_TYPE() = takes (3) returns (1) {
    // input stack          // [num1, num2, typeMax]
    dup2                    // [num2, num1, num2, typeMax]
    add                     // [result, num2, typeMax]
    dup1                    // [result, result, num2, typeMax]
    swap2                 // [num2, result, result, typeMax]
    gt                         // [is_overflow, result, typeMax]
    iszero                  // [is_not_overflow, result, typeMax]

    is_not_overflow jumpi   // [result, typeMax]
        [ARITHMETIC_OVERFLOW] PANIC()

    is_not_overflow:        // [result, typeMax]
        swap1              // [typeMax, result]
        dup2                // [result, typeMax, result]
        gt                     // [is_type_overflow, result]
        iszero              // [is_not_type_overflow, result]

        is_not_type_overflow jumpi   // [result]
         [ARITHMETIC_OVERFLOW] PANIC()

    is_not_type_overflow:
}

This can help in safe calculation of values of lower types like uint128 etc. After the initial overflow check (which accounts for only 256 bits) there's a check to ensure it doesn't overflow from the type you intend to keep it within.

someone can call this with

#include "utils/Constants.huff"

...

#define macro ADD_UINT128() = takes(0) returns(1) {
       [__UINT128_MAX]           // [Uint128Max]
       0x01                                // [0x01, uint128Max]
       0x02                               // [0x02, 0x01, uint128Max]
       SAFE_ADD_TYPE()                  // [result]
}

Returns a result in uint128

This will revert if trying to add numbers where either of them is higher than the max of result's type.

fix: Rip out Mechanisms

Overview

huffmate's goal is hyper-optimized utility contracts that can be built ontop of.

mechanisms do not fit this goal and ought to be ripped out into separate repositories.

Opti: remove double iszero before jumpi

Overview

There are several contracts where there are two iszero in a row before a jumpi to conditionally jump if a value is different from 0. But those are not necessary.
From evm.codes:

b: the program counter will be altered with the new value only if this value is different from 0. Otherwise, the program counter is simply incremented and the next instruction will be executed.

For example, in case of a call (delegate, static, or classic), they return success:

success: return 0 if the sub context reverted, 1 otherwise.

So, if there is a jumpi just after a call, there is no need to do iszero iszero.
Using the success directly from the stack is sufficient.
Removing those double iszero could save 2 instructions each times those macros are called.

Todo

Contracts where there are possible improvements:

  • ERC4626 (see PR)
  • ERC1967Upgrade (see PR)
  • ERC20_TRANSFER (utils)
  • SSTORE2_WRITE (after a create but same principle applies)
  • ERC721 (check if an address is != address(0))

Shouldnt the ERC721 implementation revert on `ownerOf(address(0))`?

This is a quote from eip-721

/// @notice Find the owner of an NFT
/// @param _tokenId The identifier for an NFT
/// @dev NFTs assigned to zero addresses are considered invalid, and queries
/// about them do throw.
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId) external view returns (address);

I dig into other implementations and see that ownerOf(address(0)) reverts;

But in the Huffmate implementation is returning always 0, shoulndt revert instead?
Please view ERC721.t.sol#L821-L824

Buttplug

`testOnlyContract` is failing

https://github.com/pentagonxyz/huffmate/blob/6798bcc97026e69ff0c4bb3e0c914d2bbcb8ba7c/test/auth/OnlyContract.t.sol

    /// @notice Tests that ONLY_CONTRACT macro reverts when tx.origin == msg.sender
    function testOnlyContract(address caller) public {
        vm.assume(caller != address(this));

        // Should revert when tx.origin == msg.sender
        // vm.startPrank(address,address) sets msg.sender and tx.origin
        vm.startPrank(caller, caller);
        vm.expectRevert();
        only_contract.call("");
        vm.stopPrank();

        // Only setting the msg.sender and not tx.origin should succeed, so long as caller != address(this)
        vm.startPrank(caller);
        (bool success,) = only_contract.call("");
        assert(success);
        vm.stopPrank();
    }

The default tx.origin of forge is 0x00a329c0648769A73afAc7F9381E08FB43dBEA72 which is different from address(this). So when the fuzzing tries with caller = 0x00a329c0648769A73afAc7F9381E08FB43dBEA72, the test fails.

Adding custom errors

Currently there is the REQUIRE that lets you mimic solidity require(condition, "message")

I want to propose a REQUIRE_CUSTOM_ERROR:

#define macro REQUIRE_CUSTOM_ERROR() = takes(2) returns(0) {
    // [condition, customErrorSig]
    do_not_throwErr jumpi
    0x00 mstore
    0x04 0x00 revert

    do_not_throwErr:
    pop
}

fix: `SafeTransferLib` tests

Overview

In SafeTransferLib's tests, we don't currently exclude the hardhat console or vm addresses from the non-contract tests. As pointed out in #119, this can sometimes cause the fuzz tests to fail.

Solution

Exclude the hardhat console or vm addresses from the non-contract tests. Bonus points for replacing the parameter restrictions with vm.assume so we get full advantage of all fuzz runs.

failing tests

Please, what would be the path to fix the failing tests ?

getting: Test result: FAILED. 16 passed; 30 failed; 0 skipped; finished in 5.43s

huffc:  0.3.2
foundry: nightly-4a643801d0b3855934cdec778e33e79c79971783

Duplicated `APPROVE` macro in the ERC20 contract

This is a good find from sashik.eth, so reposting here for tracking purposes, and it's a "good first issue" for anyone who wanna take it.

"
Why in huffmate/ERC20 "approve" macro declared twice?
https://github.com/huff-language/huffmate/blob/main/src/tokens/ERC20.huff#L98
https://github.com/huff-language/huffmate/blob/main/src/tokens/ERC20.huff#L248
"

By the way, one message later, he mentioned that huff-rs should not allow this to compile. So the current huffmate ERC20 is broken

"
Previous versions of huff allowed to compile this? because with the current I receive:
Error: Duplicate MACRO name found: \"APPROVE\" \nMACRO names should be unique
"

feat: REVERT Macro

Overview

Currently, every function selector match requires a redundant revert (eg 0x00 0x00 revert) when the function selectors don't match in the main macro.

If huff-rs gets support for a syntactic sugar string literal -> hex conversion, we could create a new Revert.huff utility that contains a Revert macro to make this redundancy simpler by just calling the macro like: REVERT() after no function selectors match.

Demonstration

#define function getCaller() view returns (uint256)

#define macro MAIN() = takes (0) returns (0) {
    pc calldataload 0xE0 shr
    dup1 __FUNC_SIG(getCaller) eq getCaller jumpi

    // No function selector matches, use new REVERT macro
    REVERT()

    getCaller:
        caller 0x00 mstore
        0x20 0x00 return
}

feat: Bytes

Overview

Implement the Bytes.huff contract located in src/data-structures/Bytes.huff.

The Bytes.huff contract should contain helpers for working with Bytes in Huff, similar to Arrays.huff in src/data-structures/Arrays.huff.

Shouldnt the ERC721 implementation revert on `balanceOf(address(0))`?

This is a quote from eip-721

/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by _owner, possibly zero
function balanceOf(address _owner) external view returns (uint256);

I dig into other implementations and see that balanceOf(address(0)) reverts;

But in the Huffmate implementation is returning always 0, shoulndt revert instead?
Please view ERC721.t.sol#L461-L464

Buttplug

include ERC72.huff got duplicate macro name

I got the error of compiling that it told me I have duplicate macro function, when I am writing the huffs with using huffmate, I think the reason is ERC721 included two files that are CommonErros.huff and nonpayable.huff, they all imported the same file that is Errors.huff. My #include visions are following:

MyTest.Huff ---> #include ECR721.huff

or

MyTest.Huff ----> #include hashmap.huff & #include ECR721.huff

above situations can cause the errors that including of duplicate to happen.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.