🟢1. Easy - Interview Questions
Last updated
Last updated
A private
function is only accessible inside the contract in which it is defined. An internal
function function is only accessible inside the contract in which it is defined AND inherited contracts. An external
function is intended to be called from outside the contract in which it is defined but can be called by using this.<FUNCTION_NAME>()
. It's used to reduce gas costs rather than to actually stop it from being called by the current contract. A public
function is callable by anyone, anywhere.
Ethereum enforces a maximum contract size of 24 KB (24,576 bytes) for the bytecode of deployed contracts. This limit is meant to prevent overly large contracts from consuming excessive blockchain resources and ensure efficient validation and execution. Deploying a smart contract must fit within the block gas limit, which varies but is typically around 30 million gas on Ethereum mainnet.
E.g. A contract could have a deployed bytecode size of less than 24 KB but still use more than the block gas limit if it had complex logic in its constructor which is executed during deployment.
The CREATE
opcode creates a contract at an address determined by the deployer nonce. So it is possible to know the address in advance but only if you know what the the deployer nonce will be at the time of deployment.
CREATE2
opcode allows contracts to be deployed at a specific address derived from:
The deployer’s address.
A salt value (a 32-byte arbitrary value provided by the deployer).
The keccak256 hash of the contract’s bytecode.
Over and underflow checks were added by default. The compiler now automatically reverts the transaction if an arithmetic operation results in an overflow or underflow. This enhancement makes contracts more secure by default and reduces the need for external libraries like SafeMath for these checks which were needed in previous versions.
delegatecall()
is used to preserve the context of a call, which is a requirement for proxy contracts.
Find the gas cost of the tx and multiply it by the price of Ethereum as the time of the tx.
A blockchain is inherently deterministic. To achieve consensus on the state of a blockchain, every node must be able to come to the same output for a given set of inputs. Therefore, true random number generation is not possible and external sources of randomness are required e.g. oracles.
A Dutch auction starts with a high price that decreases incrementally until a buyer accepts the current price, leading to a quicker sale at the first bid. In contrast, an English auction begins at a low starting price and increases with competitive bids until no higher offers are made, allowing bidders to actively compete for the highest price. The Dutch auction is faster and can prevent bidding wars, while the English auction encourages competition and transparency in price discovery.
In the ERC20 standard, transfer
allows a token holder to send tokens directly to another address, reducing the balance of the sender and increasing the balance of the recipient. transferFrom
facilitates token transfers on behalf of a third party, requiring prior approval via approve
for the spender to move a specified number of tokens from the owner’s account. This makes transferFrom
useful for use cases like escrow services or delegated transfers where a contract or user acts on behalf of another.
Mapping. A mapping allows constant-time (O(1)) lookups and is much more efficient for regular checks like allowlists. If a user is on the allowlist, simply set their address value in the mapping to be true
and it will be fast and gas efficient to check. To check if a user is in an array, the entire array may need to be processed, which means that the gas costs of interacting with the contract will grow exponentially with the size of the allow list array.
If a contract uses tx.origin
to authenticate an address then it is vulnerable to being manipulated by a malicious man-in-the-middle contract. If a malicious contract can pass through the tx.origin
then it could call a function e.g. an NFT transfer, without the explicit consent of the owner. This is why msg.sender
is more secure as the context is the address of the contract that directly called the function, unless delegatecall()
has been used.
keccak256. This is a variant of the SHA-3 family but differs slightly from the finalized NIST standard version of SHA-3. The keccak256 function is used in various core aspects of Ethereum, such as generating addresses, creating unique identifiers, and verifying data integrity within smart contracts.
1 Gwei = 0.000000001 ETH
1 Wei = 0.000000000000000001 ETH
require
is used to validate conditions that are expected to be true under normal circumstances, such as function input validation or checking contract state. It is typically used for user input, contract interaction conditions, and external calls. If the condition fails, require
will revert the transaction and return any remaining gas to the caller. require
can include a custom error message that is returned when the condition fails, making it easier to debug and understand why the transaction reverted.
assert
is used to test for internal errors and invariants within the code that should never fail. It checks conditions that, if broken, indicate a bug in the contract. Unlike require
, assert
is used to validate assumptions that should always hold true in contract logic. If an assert
statement fails, it consumes all the gas provided for the transaction. assert
does not provide an error message, so debugging is more difficult. It is meant for cases where a failure indicates a severe bug.
A flash loan is a function offered by lending platforms like Aave that allows anyone to borrow a huge amount of funds, at a fixed interest rate, for a single tx. The only condition is that the borrowed tokens + interest must be returned within the same tx it is borrowed, or the whole tx will revert. Flash loans are a powerful financial primitive not found in traditional financial markets and allow anyone to exploit financial opportunities, even when starting with almost no capital.
Anyone can be a whale for 12 seconds.
The check-effects-interaction pattern in Solidity enforces an order to prevent reentrancy vulnerabilities and unexpected outcomes. All checks and verifications should happen first, and then all effects that make changes to the state of the current smart contract should be actioned. Finally, only when those first two steps have been completed should the function interact with external contracts and/or users.
32 ETH.
When an external call in a function allows for another function to be called before expected state changes have been made. E.g. A send funds function that sends ETH before updating a user's balance. When the ETH is sent, the call to that user could be to a contract, which would allow for its receive or fallback function to reenter the calling contract and trigger the sending function again.
30 million gas block limit on Ethereum mainnet. Even on L2s with higher gas limits still would reach a limit that stops loops from running forever. A caller would also run out of ETH to pay for gas even before the gas limit is reached.
tx.origin
is the original source of the tx, the Externally Owned Account (EOA). msg.sender
is the address of the direct caller of the current function, so in a chain of contract calls, only the final contract that calls the function would show as msg.sender
.
selfdestruct()
no longer deletes the code of a contract once deployed, but currently during deployment, if selfdestruct()
is called it can be used to force sent ETH.
View functions can view the state of the blockchain. Pure functions cannot view any state and can only manipulate data passed to them.
transferFrom
transfers ownership of an NFT from one address to another without performing additional checks. It does not verify whether the recipient address is a contract or a regular address. If you use transferFrom to send an NFT to a smart contract that doesn’t handle ERC721 tokens, the token could be “stuck” since the contract might not have a way to process it.
safeTransferFrom
ensures a safe transfer by performing an additional check when sending an NFT to a contract address. It calls onERC721Received on the recipient contract if it’s a contract, ensuring that the contract is aware of the incoming NFT and can handle it properly. If the recipient contract does not implement the required onERC721Received function, the transaction will revert, preventing the NFT from being “stuck” in a contract that can’t process it.
In the ERC1155 standard, tokens are inherently semi-fungible, meaning they can be fungible or non-fungible based on how they’re defined. To create a non-fungible token (NFT) within an ERC1155 contract, you can treat specific token IDs as unique, which gives them non-fungible properties.
Modifers are useful for standardizing ownership and role-based checks on functions. Common access controls are onlyOwner
.
A modifier in Solidity is a keyword that defines reusable code to be run either before or after a function’s main logic, depending on the placement of the _;
statement within the modifier. Modifiers are flexible, allowing you to add functionality to functions in a modular, organized way.