-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3c02a37
commit d239139
Showing
3 changed files
with
190 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,20 @@ | ||
GrimReaperHuffTest:testLiquidate() (gas: 390412) | ||
GrimReaperHuffTest:testLiquidate(uint256,address) (runs: 256, μ: 390235, ~: 390503) | ||
GrimReaperHuffTest:testOnlyOwner(address) (runs: 256, μ: 20247, ~: 20247) | ||
GrimReaperHuffTest:testLiquidate(uint256,address) (runs: 257, μ: 390236, ~: 390503) | ||
GrimReaperHuffTest:testOnlyOwner(address) (runs: 257, μ: 20247, ~: 20247) | ||
GrimReaperHuffTest:testRecoverERC20() (gas: 330912) | ||
GrimReaperHuffTest:testRevertIfLiquidationFail() (gas: 52407) | ||
GrimReaperHuffV0Test:testLiquidate() (gas: 390428) | ||
GrimReaperHuffV0Test:testLiquidate(uint256,address) (runs: 257, μ: 390004, ~: 390519) | ||
GrimReaperHuffV0Test:testOnlyOwner(address) (runs: 257, μ: 20257, ~: 20257) | ||
GrimReaperHuffV0Test:testRecoverERC20() (gas: 330803) | ||
GrimReaperHuffV0Test:testRevertIfLiquidationFail() (gas: 52429) | ||
GrimReaperSolTest:testLiquidate() (gas: 390820) | ||
GrimReaperSolTest:testLiquidate(uint256,address) (runs: 256, μ: 390395, ~: 390912) | ||
GrimReaperSolTest:testOnlyOwner(address) (runs: 256, μ: 18934, ~: 18934) | ||
GrimReaperSolTest:testLiquidate(uint256,address) (runs: 257, μ: 390397, ~: 390912) | ||
GrimReaperSolTest:testOnlyOwner(address) (runs: 257, μ: 18934, ~: 18934) | ||
GrimReaperSolTest:testRecoverERC20() (gas: 331740) | ||
GrimReaperSolTest:testRevertIfLiquidationFail() (gas: 51145) | ||
OptimizedGrimReaperSolTest:testLiquidate() (gas: 390477) | ||
OptimizedGrimReaperSolTest:testLiquidate(uint256,address) (runs: 256, μ: 390299, ~: 390562) | ||
OptimizedGrimReaperSolTest:testOnlyOwner(address) (runs: 256, μ: 20400, ~: 20400) | ||
OptimizedGrimReaperSolTest:testLiquidate(uint256,address) (runs: 257, μ: 390300, ~: 390561) | ||
OptimizedGrimReaperSolTest:testOnlyOwner(address) (runs: 257, μ: 20400, ~: 20400) | ||
OptimizedGrimReaperSolTest:testRecoverERC20() (gas: 330864) | ||
OptimizedGrimReaperSolTest:testRevertIfLiquidationFail() (gas: 52467) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
// Interface | ||
#define function approve(address spender, uint256 value) nonpayable returns (bool) | ||
#define function balanceOf(address) view returns (uint256) | ||
#define function transfer(address,uint256) nonpayable returns () | ||
|
||
#define function recoverERC20(address) nonpayable returns () | ||
#define function liquidationCall(address collateralAsset,address debtAsset,address user,uint256 debtToCover,bool receiveAToken) nonpayable returns () | ||
|
||
// Storage and constants | ||
#define constant OWNER = 0x0000000000000000000000000000000000000003 | ||
#define constant POOL = 0x794a61358D6845594F94dc1DB02A252b5b4814aD | ||
|
||
|
||
// ref: https://github.com/abigger87/subway-rs/blob/ee51bbca28503174acc6ae6d1f9723be262d884d/contracts/src/Sandwich.huff | ||
|
||
/// @notice Fetches the token balance of the caller for the provided token | ||
/// @notice Stack Input: [token] | ||
/// @notice Stack Output: [balance, token] | ||
#define macro STATIC_CALL_TOKEN_BALANCE_MINUS_ONE(err) = takes (1) returns (2) { | ||
// Static Call token.balanceOf(address(this)) | ||
__FUNC_SIG(balanceOf) 0x00 mstore // [token] | ||
address 0x20 mstore // [token] | ||
|
||
0x20 // [retSize, token] | ||
0x00 // [retOffset, retSize, token] | ||
0x24 // [argSize, retOffset, retSize, token] | ||
0x1c // [argOffset, argSize, retOffset, retSize, token] | ||
dup5 // [to, argOffset, argSize, retOffset, retSize, token] | ||
gas // [gas, to, argOffset, argSize, retOffset, retSize, token] | ||
staticcall // [success, token] | ||
|
||
// Validate successful call | ||
iszero <err> jumpi // [token] | ||
0x00 mload // [balance, token] | ||
dup1 iszero skip jumpi | ||
0x01 swap1 sub // [(balance - 1), token] | ||
skip: // [(balance - 1) | 0, token] | ||
} | ||
|
||
/// @notice Receive profits from contract | ||
#define macro RECOVER_ERC20() = takes (0) returns (0) { | ||
0x04 calldataload // [token] | ||
|
||
// Get the balance of this contract | ||
STATIC_CALL_TOKEN_BALANCE_MINUS_ONE(error) // [balance, token] | ||
|
||
// Call token.transfer(msg.sender, balance) | ||
__FUNC_SIG(transfer) 0x00 mstore // [balance, token] | ||
caller 0x20 mstore // [balance, token] | ||
0x40 mstore // [token] | ||
|
||
0x00 // [retSize, token] | ||
0x00 // [retOffset, retSize, token] | ||
0x44 // [argSize, retOffset, retSize, token] | ||
0x1c // [argOffset, argSize, retOffset, retSize, token] | ||
dup3 // [value, argOffset, argSize, retOffset, retSize, token] | ||
dup6 // [to, value, argOffset, argSize, retOffset, retSize, token] | ||
gas // [gas, to, value, argOffset, argSize, retOffset, retSize, token] | ||
call // [success, token] | ||
|
||
// Validate call success | ||
iszero error jumpi stop | ||
} | ||
|
||
/// @notice Entry point for liquidation call | ||
/// @dev calldata [address collateralAsset, address debtAsset, address user, uint128 debtToCover] | ||
/// calldata is encoded with abi.encodePacked(collateralAsset,debtAsset,user,debtToCover) | ||
///https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#non-standard-packed-mode | ||
#define macro EXECUTE_LIQUIDATION() = takes(0) returns(0) { | ||
// input stack: [] | ||
|
||
// Unpack the calldata | ||
// calldata is encoded with abi.encodePacked(address collateralAsset,address debtAsset,address user,uint128 debtToCover) | ||
0x00 calldataload 0x60 shr // [col] - bytes 20 | ||
0x14 calldataload 0x60 shr // [debt, col] - bytes 20 | ||
0x28 calldataload 0x60 shr // [user, debt, col] - bytes 20 | ||
0x3c calldataload 0x80 shr // [debtToCover, user, debt, col] - uint128 | ||
|
||
// Call debtAsset.approve(pool, debtToCover) | ||
// e.g. approve(address POOL,uint256 1000) | ||
// store func sig at 0x00 | ||
__FUNC_SIG(approve) 0xe0 shl // [func_sig, debtToCover, user, debt, col] | ||
0x00 mstore // [debtToCover, user, debt, col] | ||
// after the operation | ||
// Memory loc Data | ||
// 0x00: 095ea7b300000000000000000000000000000000000000000000000000000000 | ||
|
||
// store POOL address at 0x04 | ||
[POOL] 0x04 mstore // [debtToCover, user, debt, col] | ||
// after the operation | ||
// Memory loc Data | ||
// 0x00: 095ea7b3000000000000000000000000794a61358d6845594f94dc1db02a252b | ||
// 0x20: 5b4814ad00000000000000000000000000000000000000000000000000000000 | ||
|
||
// store debtToCover at 0x24 | ||
dup1 0x24 mstore // [debtToCover, user, debt, col] | ||
// after the operation | ||
// Memory loc Data | ||
// 0x00: 095ea7b3000000000000000000000000794a61358d6845594f94dc1db02a252b | ||
// 0x20: 5b4814ad00000000000000000000000000000000000000000000000000000000 | ||
// 0x40: 000003e800000000000000000000000000000000000000000000000000000000 | ||
|
||
0x00 // [retSize, debtToCover, user, debt, col] | ||
0x00 // [retOffset, retSize, debtToCover, user, debt, col] | ||
0x44 // [argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
0x00 // [argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
dup1 // [value, argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
dup8 // [to, value, argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
0x1388 gas sub // [(gas - 5000), to, value, argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
call // [success, debtToCover, user, debt, col] | ||
|
||
// Validate call success | ||
iszero error jumpi // [debtToCover, user, debt, col] | ||
|
||
// Call POOL.liquidationCall(collateralAsset, debtAsset, user, debtToCover, false) | ||
__FUNC_SIG(liquidationCall) 0xe0 shl 0x00 mstore // [debtToCover, user, debt, col] | ||
dup4 0x04 mstore // [debtToCover, user, debt, col] | ||
dup3 0x24 mstore // [debtToCover, user, debt, col] | ||
dup2 0x44 mstore // [debtToCover, user, debt, col] | ||
dup1 0x64 mstore // [debtToCover, user, debt, col] | ||
0x00 0x84 mstore // [debtToCover, user, debt, col] | ||
|
||
// Execute the call | ||
0x00 // [retSize, debtToCover, user, debt, col] | ||
0x00 // [retOffset, retSize, debtToCover, user, debt, col] | ||
0x104 // [argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
0x00 // [argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
dup1 // [value, argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
[POOL] // [to, value, argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
0x1388 gas sub // [(gas - 5000), to, value, argOffset, argSize, retOffset, retSize, debtToCover, user, debt, col] | ||
call // [success, debtToCover, user, debt, col] | ||
|
||
// Validate call success | ||
iszero error jumpi stop | ||
} | ||
|
||
/// @notice Revert, but still (3, 3) wgmi I guess | ||
#define macro WAGMI() = takes (0) returns (0) { | ||
0x03 dup1 revert | ||
} | ||
// Main | ||
#define macro MAIN() = takes(0) returns(0) { | ||
// here we dispatch based on the size of calldata instead of the function selector | ||
/* | ||
// pc = 0 there 100% of the time | ||
// so its just a way to save a very very small amount of gas (1 gas) | ||
// Get the function selector | ||
// load 32 bytes starting from position 0 onto the stack (if the calldata is less than 32 bytes then it will be right padded with zeros). | ||
// 0xE0 shr right shifts the calldata by 224 bits, | ||
// leaving 32 bits or 4 bytes remaining on the stack. | ||
pc calldataload 0xe0 shr // [func_sig] | ||
dup1 __FUNC_SIG(recoverERC20) eq recover_erc20 jumpi // [selector] | ||
*/ | ||
|
||
// Verify that the caller is the OWNER | ||
caller [OWNER] eq iszero error jumpi // [] | ||
|
||
// Dispatcher to determine which function to execute | ||
// 24 bytes call data `recoverERC20(address)` | ||
calldatasize 0x24 eq recover_erc20 jumpi // [] | ||
|
||
// If no matching selector was found, call the liquidation function | ||
EXECUTE_LIQUIDATION() | ||
|
||
recover_erc20: | ||
RECOVER_ERC20() | ||
error: | ||
WAGMI() | ||
|
||
0x00 0x00 revert | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters