Medium Solidity-interview-questions (and answers).
Questions taken from - https://www.rareskills.io/post/solidity-interview-questions
Easy questions - https://typicalhuman.substack.com/p/easy-solidity-interview-questions-rareskills
Repository - https://github.com/typicalHuman/solidity-interview-questions
1. What is the difference between transfer and send? Why should they not be used?
transfer
throws an error on failure, send
returns false on failure. It's better to use call
because transfer
and send
have hardcoded 2300 gas and if some of the EVM opcodes start using more gas - all transfers and calls might not work anymore.
Reference: https://docs.soliditylang.org/en/v0.8.24/cheatsheet.html#members-of-address, https://consensys.io/diligence/blog/2019/09/stop-using-soliditys-transfer-now/
2. How do you write a gas-efficient for loop in Solidity?
uint256 length = array.length;
for(uint256 i; i < length;){
unchecked{++i}
}
Reference: Link
3. What is a storage collision in a proxy contract?
Storage collision is a mechanism of proxy contracts when storage states from the source contract collide with the new proxy contract and the memory states are passed on to the new contract. Small example: we have a contract with the first variable uint256 a = 3; if we are going to update the proxy and the first state variable of the proxy is also uint256 - then this variable will also store the number "3", and that's why it's important not to change the order of states when dealing with proxy updates.
Reference: https://ethereum-blockchain-developer.com/110-upgrade-smart-contracts/06-storage-collisions/
4. What is the difference between abi.encode and abi.encodePacked?
abi.encode
simply encodes the arguments to bytes32
format (if the value is not big enough for bytes32
it will be adjusted with zeros), abi.encodePacked
encodes all the values compactly without filling empty bytes with zeros, and allows to encode multiple values in one bytes32
slot.
Reference: https://docs.soliditylang.org/en/v0.8.24/abi-spec.html#non-standard-packed-mode
5. uint8, uint32, uint64, uint128, uint256 are all valid uint sizes. Are there others?
Yes, for example uint16, uint40, uint80, because uint type has a step of 8.
Reference: https://docs.soliditylang.org/en/v0.8.24/grammar.html#a4.SolidityLexer.UnsignedIntegerType
6. What changed with block.timestamp before and after proof of stake?
Before the merge, block.timestamp
could be manipulated by miners, but after the merge, the block is mined exactly every 12 seconds, so block.timestamp
is predictable.
7. What is frontrunning?
Frontrunning is a method of placing your transaction ahead of some targeted transaction, often the purpose of frontrunning is to make a profit. For example: Bot sees that some whale is buying a large amount of some token (and it will defintely drive the price up because there would be less liquidity of that token in some pool or market), so it sends its own buy transaction with higher gas because it wants to buy tokens for lower price. Then the bot can sell those tokens at a higher price after the whale's buy transaction, because the price has gone up. This is called a Sanwich attack.
Reference: https://support.uniswap.org/hc/en-us/articles/19387081481741-What-is-a-sandwich-attack
8. What is a commit-reveal scheme and when would you use it?
Commit-reveal scheme is a technique used to protect against frontrunning, where you upload some sensitive value to the smart contract in an encrypted format, and then reveal it using some kind of hash that verifies that you actually put that value in and not some other value. Also, commit-reveal schemes often have logic to close commits for some time, so that frontrunners cannot commit any useful data in the last few seconds. One of the use-cases might be an implementation of the rock-paper-scissors game.
Reference: https://medium.com/coinmonks/commit-reveal-scheme-in-solidity-c06eba4091bb
9. Under what circumstances could abi.encodePacked create a vulnerability?
If the values that you are trying to encode are dynamic arrays - this could affect the end result, for example abi.encodePacked([a,b], [c,d])
would have the same hash as a abi.encodePacked([a,b,c], [d])
. Reference: https://swcregistry.io/docs/SWC-133/
10. How does Ethereum determine the BASEFEE in EIP-1559?
It's based on network demand and the fullness of the block, if the block was full before - baseFee would go up (it can't go higher/lower than 12.5% compared to the previous one).
Reference: https://www.blocknative.com/blog/eip-1559-fees
11. What is the difference between a cold read and a warm read?
The first time you read a variable from memory - it's a cold read, all reads after the first are warm.
Reference: https://ethereum.stackexchange.com/a/149670/99105
12. How does an AMM price assets?
Based on the x*y=k
formula, the price is basically based on the reserves of the tokens, if you had a pool of 30k USDT and 10 ETH this means that the correlation is 30,000/10 = 3000 USDT per ETH, if the reserve of USDT or ETH would change and it won't be equal to the actual price - arbitrage bots will use this opportunity to regulate the price (because if your asset costs more or less than a market price - bots can abuse it in order to get profit).
Reference: https://academy.binance.com/en/articles/what-is-an-automated-market-maker-amm
13. What is a function selector clash in a proxy and how does it happen?
Function clashing is an exploit that allows some functions to be executed through the proxy that the user didn't intend to execute, by creating a function with the same signature. For example, we have a malicious contract owner (who can upgrade the proxy), if he creates a function on the proxy with the exact signature that the user will use later - it will be executed instead of the function that the user wanted to execute.
Reference: https://forum.openzeppelin.com/t/beware-of-the-proxy-learn-how-to-exploit-function-clashing/1070
14. What is the effect on gas of making a function payable?
Actually, all functions are payable by default in EVM, so not specifying the payable
keyword will add opcodes to reverse execution if the msg.value
is greater than zero. So the payable function is cheaper than the non-payable one.
Reference: https://coinsbench.com/solidity-payable-vs-regular-functions-a-gas-usage-comparison-b4a387fe860d
15. What is a signature replay attack?
The signature replay attack is an attack that allows some functionality to be performed multiple times using a signature, even if it was designed to be performed once, or allows someone else to perform functionality using the other person's signature. It can be solved by using the msg.sender
check and also adding nonce
logic to the code so that the signature can't be used more than once.
Reference: https://solidity-by-example.org/hacks/signature-replay/
16. What is gas griefing?
Gas griefing is an attack technique that allows a malicious user to prevent users from executing transactions when there's no external call success check. It can be done by providing just enough gas to execute a top-level transaction, and then censoring the data so that the original user can't execute it later.
Reference: https://swcregistry.io/docs/SWC-126/
17. How would you design a game of rock-paper-scissors in a smart contract such that players cannot cheat?
It can be done by using commit-reveal scheme.
Reference: https://github.com/ojroques/ethereum-rockpaperscissors
18. What is the free memory pointer and where is it stored?
The free memory pointer is the pointer that shows where the last occupied byte of memory is, it's used when you create a new variable for example - it shows where to store this new variable.
Reference: https://ethereum.stackexchange.com/questions/137729/opcode-free-memory-pointer-and-offset
19. What function modifiers are valid for interfaces?
All declared functions must be external
Reference: https://solidity-by-example.org/interface/
20. What is the difference between memory and calldata in a function argument?
memory
parameters are mutable and calldata
parameters are immutable.
21. Describe the three types of storage gas costs.
Store a new variable: 20,000 gas
Updating state: 5,000 gas
Reading state: 200 gas
Reference: https://hacken.io/discover/solidity-gas-optimization/
22. Why shouldn’t upgradeable contracts use the constructor?
Because the constructor is called only once, and this code is not part of the runtime bytecode of a deployed smart contract. So this context won't be passed to the proxy contract. So it's better to use an initializer
method instead.
Reference: https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#the-constructor-caveat
23. What is the difference between UUPS and the Transparent Upgradeable Proxy pattern?
UUPS and Transparent Upgradeable Proxy are both transparent proxy patterns (https://blog.openzeppelin.com/the-transparent-proxy-pattern), but UUPS is cheaper because proxy management functions for proxy are not being duplicated in the proxy implementations.
Reference: https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups
24. If a contract delegatecalls an empty address or an implementation that was previously self-destructed, what happens? What if it is a regular call instead of a delegatecall?
It will return true, because even though the storage is empty for that address, the EVM still recognizes the existence of this address and decides that the call
/delegatecall
was successful.
25. What danger do ERC777 tokens pose?
The killer feature of the ERC777 standard is the receive hook, which allows you to react to the incoming tokens, similar to onERC721Received for NFT. This can be handy, but it also opens up the possibility of reentrancy attacks by giving the attacker another way to re-enter the contract.
Reference: https://forum.openzeppelin.com/t/can-sombody-explain-why-erc777-was-removed/38105
26. According to the solidity style guide, how should functions be ordered?
constructor
receive function (if exists)
fallback function (if exists)
external
public
internal
private
Within a grouping, place the view
and pure
functions last.
Reference: https://docs.soliditylang.org/en/v0.8.24/style-guide.html#order-of-functions
27. According to the solidity style guide, how should function modifiers be ordered?
The modifier order for a function should be:
Visibility (public,private,external,internal)
Mutability (pure,view) + payable
virtual
/override
Custom modifiers
Reference: https://docs.soliditylang.org/en/v0.8.24/style-guide.html#function-declaration
28. What is a bonding curve?
AMM mechanism for checking correlation between token supplies and calculating relative price for them.
Reference: https://iq.wiki/wiki/bonding-curve
29. How does safeMint differ from mint in the OpenZeppelin ERC721 implementation?
safeMint
checks 2 things: 1. the existence of tokenId
(it won't mint the same token twice), 2. if to
is a contract - it should implement the onERC721Received
function. mint
function doesn't check these conditions.
Reference: https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#ERC721-_safeMint-address-uint256-
30. What keywords are provided in Solidity to measure time?
1 == 1 seconds
1 minutes == 60 seconds
1 hours == 60 minutes
1 days == 24 hours
1 weeks == 7 days
Reference: https://docs.soliditylang.org/en/v0.8.24/units-and-global-variables.html#time-units
31. What is a sandwich attack?
Inserting a transaction before and after a targeted transaction in order to make a profit. Example: Bot sees that some whale is buying a large amount of some token (and it will defintely drive the price up because there would be less liquidity of that token in some pool or market), so it sends its own buy transaction with higher gas because it wants to buy tokens for lower price. Then the bot can sell those tokens at a higher price after the whale's buy transaction, because the price has gone up. This is called a Sanwich attack.
Reference: https://support.uniswap.org/hc/en-us/articles/19387081481741-What-is-a-sandwich-attack
32. If a delegatecall is made to a function that reverts, what does the delegatecall do?
It will return false
and won't revert the calling function.
Reference: https://docs.soliditylang.org/en/v0.8.24/security-considerations.html#call-stack-depth
33. What is a gas efficient alternative to multiplying and dividing by a power of two?
You can shift right/left instead of division/multiplication. While the DIV opcode uses 5 gas, the SHR opcode only uses 3 gas.
Reference: https://betterprogramming.pub/solidity-gas-optimizations-and-tricks-2bcee0f9f1f2
34. How large a uint can be packed with an address in one slot?
1 slot size = 32 bytes, address - 20 bytes, we have 12 free bytes - 8 * 12 = 96, uint96.max = 79228162514264337593543950335
35. Which operations give a partial refund of gas?
1 slot size = 32 bytes, address - 20 bytes, we have 12 free bytes - 8 * 12 = 96, uint96.max = 79228162514264337593543950335
36. What is ERC165 used for?
You can use it to check if the smart contract implements the interface and certain functions or not. It can be useful if you need to check if the contract is an ERC20 token or not. ERc165 uses supportsInterface(bytes4 interfaceID)
for this purpose.
Reference: https://eips.ethereum.org/EIPS/eip-165
37. If a proxy makes a delegatecall to A, and A does address(this).balance, whose balance is returned, the proxy's or A?
address(this)
will return the address of the proxy, so it will return the proxy's balance.
38. What is a slippage parameter useful for?
Slippage is a limit that shows how much the price could change during the trade. It's used in cases where liquidity is very volatile and you don't want to buy tokens at a much higher price or sell them at a much lower price than you wanted.
39. What does ERC721A do to reduce mint costs? What is the tradeoff?
ERC721A is a new implementation of ERC721 pattern but with some upsides and downsides: Upsides:
mints are much cheaper
Downsides:
transfers are more expensive
Mint optimization technique: it doesn't update all default mappings with info about token owner on each mint, it does it once during batch mint. Because of this, you don't have information about the tokenId owner, so you have to iterate the array first to find the owner of the token.
Reference: https://www.alchemy.com/blog/erc721-vs-erc721a-batch-minting-nfts
40. Why doesn't Solidity support floating point arithmetic?
One of the main reasons is the fact that fixed-point arithmetic is not very predictable and can lead to forks on different nodes, which is why EVM itself doesn't want to deal with it, but Solidity has started to implement floating-point numbers using the same technique used in the ERC20 tokens - https://docs.soliditylang.org/en/develop/types.html#fixed-point-numbers.
41. What is TWAP?
TWAP (Time-Weighted Average Price) - is a pricing algorithm used to calculate the price of an asset for a period of time. It can be done by taking different prices at equally distant points in time and then dividing the sum of them by the length of the points:
For example, imagine we wanted to calculate the TWAP of an asset over one minute using 15-second price point intervals. If the prices were $100 at zero seconds, $102 at 15 seconds, $101 at 30 seconds, $98 at 45 seconds, and $103 at 60 seconds, then to calculate the TWAP we would sum all price points (100, 102, 101, 99, 103) and then divide them by the number of timepoints (five). In this example, the TWAP is $101.
41. How does Compound Finance calculate utilization?
Utilization - percentage of actually borrowed funds in the lending pool compared to the total funds available for borrowing.
Utilization = TotalBorrows / TotalSupply;
Reference: https://docs.compound.finance/interest-rates/#get-utilization
42. If a delegatecall is made to a function that reads from an immutable variable, what will the value be?
It will return the value of immutable variable.
POC:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
contract FirstContract {
function doDelegate(address contr) external returns(bytes memory){
(, bytes memory data) = address(contr).delegatecall(abi.encodeWithSignature("doCall()"));
return data; // 0x00..1e = 30
}
}
contract secondContract{
uint256 immutable VALUE = 30;
function doCall() external returns(uint256){
return VALUE;
}
}
44. What is a fee-on-transfer token?
Fee-on-transfer token is a type of ERC20 token that takes a small fee after tokens are transferred.
Reference: https://help.1inch.io/en/articles/5651059-what-is-a-fee-on-transfer-token
45. What is a rebasing token?
Rebase token is a type of ERC20 token that changes its total supply (by burning/minting tokens) to maintain a peg to a certain value, they are very similar to stablecoins in idea but not in implementation.