flashloan-rs 0.2.0

Minimal Multicall3 Flashloan Module
Documentation
/// @title Create3
/// @notice SPDX-License-Identifier: MIT
/// @author Maddiaa <https://github.com/cheethas>
/// @author asnared <https://github.com/abigger87>
/// @notice Deploy to deterministic addresses without an initcode factor
/// @notice Adapted from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/CREATE3.sol)

#include "./CommonErrors.huff"


// Proxy Constants
#define constant PROXY_BYTECODE = 0x67363d3d37363d34f03d5260086018f3
#define constant PROXY_BYTECODE_HASH = 0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f

//--------------------------------------------------------------------------------//
// Opcode     | Opcode + Arguments    | Description      | Stack View             //
//--------------------------------------------------------------------------------//
// 0x36       |  0x36                 | CALLDATASIZE     | size                   //
// 0x3d       |  0x3d                 | RETURNDATASIZE   | 0 size                 //
// 0x3d       |  0x3d                 | RETURNDATASIZE   | 0 0 size               //
// 0x37       |  0x37                 | CALLDATACOPY     |                        //
// 0x36       |  0x36                 | CALLDATASIZE     | size                   //
// 0x3d       |  0x3d                 | RETURNDATASIZE   | 0 size                 //
// 0x34       |  0x34                 | CALLVALUE        | value 0 size           //
// 0xf0       |  0xf0                 | CREATE           | newContract            //
//--------------------------------------------------------------------------------//
// Opcode     | Opcode + Arguments    | Description      | Stack View             //
//--------------------------------------------------------------------------------//
// 0x67       |  0x67XXXXXXXXXXXXXXXX | PUSH8 bytecode   | bytecode               //
// 0x3d       |  0x3d                 | RETURNDATASIZE   | 0 bytecode             //
// 0x52       |  0x52                 | MSTORE           |                        //
// 0x60       |  0x6008               | PUSH1 08         | 8                      //
// 0x60       |  0x6018               | PUSH1 18         | 24 8                   //
// 0xf3       |  0xf3                 | RETURN           |                        //
//--------------------------------------------------------------------------------//

/// @notice Deploy a new contract with our pre-made bytecode via CREATE2
#define macro CREATE_3_DEPLOY() = takes (3) returns (1) {
    // Input Stack: [salt, &creationCode, value]
    // Output Stack: [deployed]

    // Create the proxy
    dup1 0x10                                   // [size, salt, salt, &creationCode, value]

    // Shift the proxy bytecode left
    [PROXY_BYTECODE]                            // [bytecode, size, salt, salt, &creationCode, value, bytecode]
    0x80 shl                                    // [RIGHTPAD(bytecode), size, salt, salt, &creationCode, value, bytecode]
    0x00 mstore                                 // [size, salt, salt, &creationCode, value]
    0x00                                        // [offset, size, salt, salt, &creationCode, value]
    0x00                                        // [value, offset, size, salt, salt, &creationCode, value]
    create2                                     // [address, salt, &creationCode, value]

    // Check the address of of the proxy is not null
    dup1 iszero                     // [address == 0, address, salt, &creationCode, value]
    deployment_failed jumpi         // [address, salt, &creationCode, value]

    // Load the length of the creation code
    dup3 0x04 add calldataload         // [creationCode.length, address, salt, &creationCode, value]

    // Copy the code from calldata to memory at memory position 0x20
    dup1 0x05 shl                           // [size, creationCode.length, address, salt, &creationCode, value]
    dup5 0x24 add                           // [calldataOffset, size, creationCode.length, address, salt, &creationCode, value]
    0x20                                    // [destOffset, calldataOffset, size, creationCode.length, address, salt, &creationCode, value]
    calldatacopy                            // [creationCode.length, address, salt, &creationCode, value]

    // Call the proxy with the creation code
    0x20                            // [retSize, creationCode.length, address, salt, &creationCode, value]
    0x00                            // [retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
    dup3                            // [argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
    0x20                            // [argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
    dup9                            // [value, argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
    dup7                            // [to, value, argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
    gas                             // [gas, to, value, argOffset, argSize, retOffset, retSize, creationCode.length, address, salt, &creationCode, value]
    call                            // [success, creationCode.length, address, salt, &creationCode, value]
    iszero                          // [success == 0, creationCode.length, address, salt, &creationCode, value]
    init_failed jumpi               // [creationCode.length, address, salt, &creationCode, value]

    // Get the deployed contract using the salt and make sure it has code at the address
    dup3 CREATE_3_GET_DEPLOYED()    // [deployed, creationCode.length, address, salt, &creationCode, value]
    dup1 extcodesize                // [deployed == 0, deployed, creationCode.length, address, salt, &creationCode, value]
    iszero init_failed jumpi        // [deployed, creationCode.length, address, salt, &creationCode, value]

    // Clean up stack and return
    swap5 pop pop pop pop pop       // [deployed]
    done jump

    deployment_failed:
        DEPLOYMENT_FAILED(0x00)
    init_failed:
        INITIALIZATION_FAILED(0x00)

    done:
}

#define macro CREATE_3_GET_DEPLOYED() = takes (1) returns (1) {
    // Input Stack : [salt]
    // Output Stack: [deployed_address]

    // Store 0xff | (right_padded_address >> 1) in memory
    __RIGHTPAD(0xff)        // [rightpad(0xff), salt]
    address 0x58 shl        // [rightpad(address), rightpad(0xff), salt]
    or                      // [[0xff][address], salt]
    0x00 mstore             // [salt]

    // Store the salt in memory at position 0x15
    0x15 mstore             // []

    // Store the hash in memory at 0x35
    [PROXY_BYTECODE_HASH]   // [hash]
    0x35 mstore             // []

    // Hash the memory from 0x00:0x55
    0x55 0x00 sha3          // [keccak]

    // ---------------------------------------- //
    //              Memory Layout               //
    // ---------------------------------------- //
    // prefix |    address   | nonce | empty    //
    // 0xd694 | <proxy_address> | 01 | 000..000 //
    // ---------------------------------------- //

    // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01)
    // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)

    // Clear the top 10 bytes of the hash
    0x60 shl 0x10 shr       // [proxy_address]

    // return rpl encoded
    __RIGHTPAD(0xd694)      // [0xd694, proxy_address]
    or                      // [ [0xd694][proxy_address] ]

    // Append a 0x01 to the end of the address

    0x01 0x48 shl           // [0x01 << 9, [0xd694][proxy_address]]
    or                      // [ [0xd694][proxy_address][01] ]

    // Hash the packed encoding in memory position 0x00
    0x00 mstore             // []
    0x17 0x00 sha3          // [hash]

    // Clear the top 12 bytes using shifts
    0x60 shl 0x60 shr       // [proxy_address]
}