flashloan-rs 0.2.1

Minimal Multicall3 Flashloan Module
Documentation
/// @title HashMap
/// @notice SPDX-License-Identifier: MIT
/// @author asnared <https://github.com/abigger87>
/// @notice A Module Encapsulating HashMap Methods
/// @notice Adapted from <https://github.com/huff-language/huff-examples/blob/main/erc20/contracts/utils/HashMap.huff>

/// @notice Given a piece of data (ie an address), hash it, generating the storage slot for a hashmap.
#define macro GET_SLOT_FROM_KEY(mem_ptr) = takes(1) returns (1) {
    // Input stack: [key]
    // Load the data into memory and hash it, while preserving the memory location.
    <mem_ptr>   // [<mem_ptr>, key]
    mstore      // []

    // Hash the data, generating a key.
    0x20                // [32]
    <mem_ptr>           // [<mem_ptr>, 32]
    sha3                // [slot]
}

/// @notice Given two keys (ie an address and a number), hash them together, generating a slot for a secondary hashmap.
///         This should only be used if you have multiple maps in your contract.
#define macro GET_SLOT_FROM_KEYS(mem_ptr) = takes(2) returns (1) {
    // Input stack: [key1, key2]
    // Load the data into memory.
    <mem_ptr>           // [<mem_ptr>, key1, key2]
    mstore              // [key2]
    <mem_ptr> 0x20 add  // [<mem_ptr> + 32, key2]
    mstore              // []

    // Hash the data, generating a key.
    0x40        // [64]
    <mem_ptr>   // [<mem_ptr>, 64]
    sha3        // [key]
}

/// @notice Calculate the slot from two keys
#define macro GET_SLOT_FROM_KEYS_2D(mem_ptr) = takes(3) returns (1) {
    // Input stack: [slot, key1, key2]
    // Load the data into memory
    <mem_ptr>           // [<mem_ptr>, slot, key1, key2]
    mstore              // [key1, key2]

    // next byte
    <mem_ptr> 0x20 add  // [<mem_ptr> + 32, key1, key2]
    mstore              // [key2]

    0x40                // [0x40, key2]
    <mem_ptr>           // [<mem_ptr>, 0x40, key2]
    sha3                // [slot1, key2]

    // concat the two keys
    <mem_ptr> 0x20 add  // [<mem_ptr> + 0x20, key2] put slot1 in memory
    mstore              // [key2]

    // next byte
    <mem_ptr>           // [<mem_ptr>, key2]
    mstore              // []

    // Hash the data, generating a key.
    0x40                // [0x40]
    <mem_ptr>           // [<mem_ptr>, 0x40]
    sha3                // [key]
}

/// @notice Load an element onto the stack from a key
#define macro LOAD_ELEMENT(mem_ptr) = takes(1) returns(1) {
    // Input stack: [key]
    GET_SLOT_FROM_KEY(<mem_ptr>)    // [slot]
    sload                           // [value]
}

/// @notice Load an element onto the stack from two keys
#define macro LOAD_ELEMENT_FROM_KEYS(mem_ptr) = takes(2) returns(1) {
    // Input stack: [key1, key2]
    GET_SLOT_FROM_KEYS(<mem_ptr>)   // [slot]
    sload                           // [value]
}

/// @notice Load an element onto the stack from a slot and two keys
#define macro LOAD_ELEMENT_FROM_KEYS_2D(mem_ptr) = takes(3) returns(1) {
    // Input stack: [slot, key1, key2]
    GET_SLOT_FROM_KEYS_2D(<mem_ptr>) // [slot]
    sload                            // [value]
}

/// @notice Store an element from a key
#define macro STORE_ELEMENT(mem_ptr) = takes(2) returns(0) {
    // Input stack: [key, value]
    GET_SLOT_FROM_KEY(<mem_ptr>)    // [slot, value]
    sstore                          // []
}

/// @notice Store an element from two keys
#define macro STORE_ELEMENT_FROM_KEYS(mem_ptr) = takes(3) returns (0) {
    // Input stack: [key1, key2, value]
    GET_SLOT_FROM_KEYS(<mem_ptr>)   // [slot, value]
    sstore                          // []
}

/// @notice Store an element from a slot and two keys
#define macro STORE_ELEMENT_FROM_KEYS_2D(mem_ptr) = takes(4) returns (0) {
    // Input stack: [slot, key1, key2, value]
    GET_SLOT_FROM_KEYS_2D(<mem_ptr>)    // [slot, value]
    sstore                              // []
}