Last active
April 25, 2025 22:31
-
-
Save ndeto/e6154c9c522cc7477e69db60ee3d1757 to your computer and use it in GitHub Desktop.
Uniswap Assembly Contract (Huff)
This file contains hidden or 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
// I extracted this logic from a suite of contracts I wrote in Huff meant to perform swaps as part of an AMM system. | |
// This is just provide an example of how your can write smart contracts at assembly level by simply manipulating the stack and calling opcodes. | |
// This is for learning purposes only | |
// Swap function | |
#define function swap() nonpayable returns () | |
// These constants will be replaced by the actual values during deploy time | |
#define constant OWNER = 0x6dc63ab72c3b163f71ce602ea2727307cf9a40402cd20689e35f0aa0eb82b586 | |
#define constant AMOUNT_IN = 0x23864fb08284051ca4c4decf63586b6c3f4263de1c22f8c7e77a135196a69007 | |
#define constant EXPECTED_AMOUNT_OUT = 0x925b022ee8e701f539a353cbfd9a0852983f23bccf13eab86ec816d73003f94d | |
#define constant SWAP_FEE = 0x1caf8778049e0c13a1d5db49fd0aaf32a5573a00a294c90563550f0d4f404bfa | |
#define constant BASE_FEE = 0xe175b348864284ecdbf4c3c68afca185824661959253a859b48b92bd25b07331 | |
#define constant BUY_TAX = 0x1c9e613b095883a828b3f55c9d2330ef03fc27465fccbe0e9b1beb40af543371 | |
#define constant PAIR_ADDRESS = 0x4eab33021c15dc5f500948974f788b26434e076d83383a2437fc83a7614fc01b | |
#define constant ETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 | |
// Define storage slots. | |
#define constant TOKEN_IN = 0x500 | |
#define constant TOKEN_OUT = 0x520 | |
#define constant TOKEN0 = 0x540 | |
#define constant TOKEN1 = 0x560 | |
#define constant TOKEN_IN_BALANCE = 0x580 | |
#define macro BALANCE_OF_SENDER() = takes (1) returns (1) { | |
// Takes the token address on the stack and checks the balanceOf of the user | |
// [token address] | |
__RIGHTPAD(0x70a08231) callvalue mstore // FuncSig | |
[OWNER] 0x04 mstore // address for this contract | |
0x00 // [0x00, address] | |
0x24 // [0x24, 0x00, address] | |
callvalue // [callvalue, 0x24, 0x00, address] | |
0x00 // [0x00, callvalue, 0x24, 0x00, address] | |
swap4 // [address, callvalue, 0x24, 0x00, 0x00] | |
gas // [gas, address, callvalue, 0x24, 0x00, 0x00] | |
staticcall | |
returnBalance // move to store the balance if call was successful | |
jumpi | |
REVERT() // revert if call wasn't successful | |
returnBalance: | |
returndatasize 0x00 0x00 returndatacopy | |
0x00 mload | |
} | |
#define macro UNISWAP_V2_FLASHSWAP_CALLBACK() = takes (5) returns (0) { | |
// Starting stack | |
// [pair, senderAddress, tokenInAddress, pair, amountIn] | |
// Check call came from pair | |
caller // [msg.sender, pair, senderAddress, tokenInAddress, pair, amountIn] | |
eq // [0/1, senderAddress, tokenInAddress, pair, amountIn] | |
checkSender | |
jumpi // [senderAddress, tokenInAddress, pair, amountIn] | |
REVERT() | |
checkSender: // [senderAddress, tokenInAddress, pair, amountIn] | |
address // [ourContractAddress, senderAddress, tokenInAddress, pair, amountIn] | |
eq // [0/1, tokenInAddress, pair, amountIn] | |
makeTransfer | |
jumpi | |
makeTransfer: // [tokenInAddress, pair, amountIn] | |
[PAIR_ADDRESS] | |
SORT_TOKENS() | |
[TOKEN_IN] mload // [tokenInAddress, pair, amountIn] | |
BALANCE_OF_SENDER() // [tokenInAddress, pair, amountIn, senderBalance] | |
[TOKEN_IN_BALANCE] mstore // [pair, amountIn, senderBalance] | |
TRANSFER_FROM() | |
} | |
#define macro TRANSFER_FROM() = takes (4) returns (0) { | |
// Starting stack [owner tokenInAddress, pair, amountIn] | |
__RIGHTPAD(0x23b872dd) 0x100 mstore // [tokenInAddress, pair, amountIn] | |
[OWNER] 0x104 mstore // [senderAddress, tokenInAddress, pair, amountIn] | |
[PAIR_ADDRESS] 0x124 mstore // [pair, amountIn] Store tokenIn in a different location | |
[TOKEN_IN_BALANCE] mload 0x144 mstore // [amountIn, amountIn] Store amountIn in a different location | |
0x00 0x00 0x64 0x100 | |
0x00 | |
[TOKEN_IN] mload | |
gas | |
call | |
0x01 | |
doneStep | |
jumpi | |
REVERT() | |
doneStep: | |
} | |
// Given a pair address, returns [alternatecoin, ETH] | |
#define macro SORT_TOKENS() = takes (1) returns (0) { | |
// [pairAddress] | |
dup1 // [pairAddress, pairAddress] | |
GET_TOKEN_ZERO() // [token0Address, pairAddress] | |
[TOKEN0] mstore // [pairAddress] | |
pop pop | |
GET_TOKEN_ONE() // [token1Address] | |
[TOKEN1] mstore // [] | |
// Determine which token is ETH | |
[TOKEN0] mload // [token0Address] | |
[ETH_ADDRESS] // [ETH, token0Address] | |
eq | |
returnToken1AsShxtcoin | |
jumpi | |
returnToken0AsShxtcoin: | |
[TOKEN1] mload // [token1Address] | |
[TOKEN_IN] mstore // [] | |
[TOKEN0] mload // [token0Address] | |
[TOKEN_OUT] mstore // [token0Address, token1Address] | |
returnToken1AsShxtcoin: | |
[TOKEN0] mload // [token1Address] | |
[TOKEN_IN] mstore // [] | |
[TOKEN1] mload // [token0Address] | |
[TOKEN_OUT] mstore // [token0Address, token1Address] | |
done | |
jump | |
done: | |
} | |
#define macro GET_TOKEN_ONE() = takes (1) returns (1){ | |
// [pairAddress] | |
__FUNC_SIG("token1()") 0x00 mstore | |
0x00 // [0x00, pairAddress] | |
0x00 // [0x00, 0x00, pairAddress] | |
0x04 // [0x04, 0x00, 0x00, pairAddress] | |
0x1c // [0x1c, 0x04, 0x00, 0x00, pairAddress] | |
0x00 calldataload // [0x00, 0x1c, 0x04, 0x00, 0x00, pairAddress] | |
swap5 // [pairAddress, 0x1c, 0x04, 0x00, 0x00, 0x00] | |
gas // [gas, pairAddress, 0x1c, 0x04, 0x00, 0x00, 0x00] | |
staticcall | |
returndatasize 0x00 0x00 returndatacopy //copy token0() results to 0x00 in memory | |
0x00 mload // Return the token 0 address | |
} | |
#define macro GET_TOKEN_ZERO() = takes (1) returns (1){ | |
// [pairAddress] | |
__FUNC_SIG("token0()") 0x00 mstore | |
0x00 // [0x00, pairAddress] | |
0x00 // [0x00, 0x00, pairAddress] | |
0x04 // [0x04, 0x00, 0x00, pairAddress] | |
0x1c // [0x1c, 0x04, 0x00, 0x00, pairAddress] | |
0x00 calldataload // [0x00, 0x1c, 0x04, 0x00, 0x00, pairAddress] | |
swap5 // [pairAddress, 0x1c, 0x04, 0x00, 0x00, 0x00] | |
gas // [gas, pairAddress, 0x1c, 0x04, 0x00, 0x00, 0x00] | |
staticcall | |
returndatasize 0x00 0x00 returndatacopy //copy token0() results to 0x00 in memory | |
0x00 mload // Return the token 0 address | |
} | |
#define macro HANDLE_REVERT() = takes (0) returns (0) { | |
// store returndata in memory and reverts accordingly | |
returndatasize // [returndatasize, success] | |
0x11 | |
eq | |
returnRevert | |
jumpi | |
completeAction | |
jump | |
returnRevert: | |
REVERT() | |
completeAction: | |
} | |
#define macro SWAP() = { | |
caller // [msg.sender] | |
0xc4 calldataload // [tokenInAddress, msg.sender] | |
eq | |
doneStep | |
jumpi | |
// Start building uniV2Call params from call data | |
// [pair(0xe4), ReceiverAddress(0x04), tokenInAddress(0xc4), pair(0xe4), amountIn(0xa4)] | |
0xa4 calldataload // [amountIn] | |
0xe4 calldataload // [pair, amountIn] | |
0xc4 calldataload // [tokenInAddress, pair, amountIn] | |
0x04 calldataload // [senderAddress, tokenInAddress, pair, amountIn] | |
0xe4 calldataload // [pair, senderAddress, tokenInAddress, pair, amountIn] | |
UNI_V2_CALL() | |
doneStep | |
jump | |
return 0x00 0x20 | |
doneStep: | |
} | |
#define macro FALLBACK() = { | |
// revert for now | |
REVERT() | |
} | |
#define macro REVERT() = takes (0) returns (0) { | |
revert | |
} | |
#define macro RECEIVE() = takes (1) returns (1) {} | |
#define macro MAIN() = takes (0) returns (0) { | |
// This logic handles value deposits and if none, | |
// Calls the contract function | |
callvalue // [msg.value] | |
iszero // [is_msg_value_zero] | |
iszero // [is_msg_value_non_zero] | |
deposited // [deposited_jumpdest, is_msg_value_non_zero] | |
jumpi // [] | |
// Identifies which function to call | |
msize | |
msize calldataload // [msg.data[:32],0] | |
0xe0 shr // [msg.data[:4],0] | |
// dup1 | |
__FUNC_SIG(swap) eq swap jumpi | |
FALLBACK() | |
0x00 0x00 revert | |
deposited: | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I extracted this logic from a suite of contracts I wrote in Huff meant to perform swaps as part of an AMM system. This is just provide an example of how your can write smart contracts at assembly level by simply manipulating the stack and calling opcodes. This is for learning purposes only