Here are 45 common interview questions that focus on Solidity, the popular programming language used for writing smart contracts
on Ethereum:
A. Basic Concepts
1. What is Solidity, and how does it differ from other programming languages?
- Solidity is a high-level, statically-typed programming language specifically designed for implementing smart contracts on Ethereum and other blockchains. It’s influenced by JavaScript, Python, and C++.
2. What are the key components of a smart contract in Solidity?
- The key components include state variables, functions, modifiers, events, and structs.
3. What is the difference between public
, private
, internal
, and external
visibility in Solidity?
- Public: Accessible both inside and outside the contract.
- Private: Only accessible within the contract that defines it.
- Internal: Accessible within the contract and derived contracts.
-
External: Only callable from outside the contract; more gas-efficient than
public
when called externally.
4. How do you define a state variable in Solidity?
-
State variables store data permanently on the blockchain.
Example:
uint public balance;
5. What are events in Solidity, and why are they important?
- Events are logs on the Ethereum blockchain that notify external applications about contract activity. They are useful for triggering actions in off-chain applications like dApps.
6. What is the difference between view
and pure
functions in Solidity?
- View: Read-only functions that don’t modify the state.
- Pure: Functions that neither modify nor read the state; they only operate on input arguments.
7. What is a fallback function in Solidity, and when is it triggered?
-
The fallback function is executed when a contract receives Ether but no data (or an unknown function call). It is used to handle such cases gracefully.
fallback() external payable { }
8. How does inheritance work in Solidity?
- Solidity supports single and multiple inheritance, allowing contracts to inherit properties and functions from parent contracts. Derived contracts can override parent functions using the
override
keyword.
9. What is a constructor in Solidity, and how is it used?
- A constructor is a special function that initializes a contract when it is deployed. It is only executed once during the contract's creation.
10. What are the differences between storage
and memory
keywords in Solidity?
- Storage: Persistent, stored on-chain. Variables declared in storage are written permanently to the blockchain.
- Memory: Temporary, used during function execution. It is not stored on-chain and is cheaper in terms of gas.
B. Advanced Concepts
11. What is Gas in Solidity, and how does it impact smart contract execution?
- Gas is a unit that measures the amount of computational effort required to execute operations in Ethereum. It prevents infinite loops and incentivizes efficient coding.
12. What is the purpose of require
, assert
, and revert
statements in Solidity?
- require: Validates inputs and conditions. If the condition fails, the transaction is reverted.
- assert: Used to check for internal errors and conditions that should never happen. It’s more expensive in terms of gas.
- revert: Used to manually stop execution and revert the contract state.
13. What is the difference between delegatecall
and call
?
- call: Calls a function of another contract, changing the context to that of the called contract.
- delegatecall: Calls a function but keeps the context of the calling contract. It’s used in proxy patterns for contract upgrades.
14. What are modifiers in Solidity, and how do you use them?
- Modifiers are used to change the behavior of functions. They allow for preconditions before the execution of a function.
-
Example:
modifier onlyOwner() { require(msg.sender == owner); _; }
15. What is the purpose of the selfdestruct
function in Solidity?
-
selfdestruct
is used to delete a contract from the blockchain, sending any remaining Ether to a specified address. It’s typically used for contract upgrades or when a contract is no longer needed.
16. How does Solidity handle function overloading?
- Solidity allows multiple functions with the same name but different parameters. The compiler differentiates them based on the parameter types and count.
17. How would you implement a contract upgrade in Solidity?
- Contract upgrades can be implemented using proxy patterns, where the proxy contract delegates calls to the implementation contract. This allows changes to the logic without altering the contract's storage.
18. What are libraries in Solidity, and how do they differ from contracts?
Libraries are similar to contracts but they cannot store state and cannot receive Ether. They are reusable and their code can be called from contracts without redeploying.
19. What are interfaces in Solidity, and why are they used?
-
Interfaces define a contract’s external functions without including their implementation. They allow for interoperability between contracts. Example:
interface Token { function transfer(address _to, uint256 _value) external; }
20. What are structs in Solidity, and how are they used?
-
Structs are custom data types that group multiple variables together. Example:
struct Person { string name; uint age; }
C. Security Considerations
21. What is a re-entrancy attack, and how can it be mitigated in Solidity?
- A re-entrancy attack occurs when a malicious contract calls a vulnerable contract multiple times before the initial execution is completed, often draining funds. Mitigation techniques include:
- Using the Checks-Effects-Interactions pattern.
- Using the
reentrancyGuard
modifier from libraries like OpenZeppelin.
22. What is the Checks-Effects-Interactions
pattern, and why is it important?
- It is a Solidity best practice to first check conditions (
Checks
), then update the contract’s state (Effects
), and finally interact with other contracts (Interactions
). This minimizes vulnerabilities such as re-entrancy.
23. What is a front-running attack in Ethereum, and how can it be prevented in Solidity?
- Front-running occurs when someone exploits the visibility of pending transactions by submitting their own transaction with a higher gas fee to get processed first. Mitigation strategies include using commit-reveal schemes or adjusting transaction gas fees dynamically.
24. What are integer overflows/underflows, and how can you prevent them?
- Integer overflow happens when an arithmetic operation exceeds the storage limit of a variable. This can be prevented by using libraries like OpenZeppelin’s
SafeMath
, which checks for overflows and underflows (Solidity0.8.0
upwards natively supports this).
25. How can you protect smart contracts against Denial of Service (DoS) attacks?
- To prevent DoS attacks, avoid gas-heavy loops, use
pull
overpush
patterns for funds withdrawal, and limit external calls within functions.
26. What are some best practices for ensuring the security of Solidity smart contracts?
- Use known libraries (e.g., OpenZeppelin).
- Implement proper access control (e.g., owner checks).
- Avoid state changes before external calls.
- Limit the complexity of contracts.
- Conduct thorough audits and testing (including fuzzing).
D. Tokens, Standards, and Best Practices
27. What are ERC-20 tokens, and what are the key functions in an ERC-20 contract?
- ERC-20 is a standard for fungible tokens on Ethereum. Key functions include:
balanceOf
transfer
approve
transferFrom
allowance
28. What is the difference between ERC-20 and ERC-721?
- ERC-20: A standard for fungible tokens, where each token is identical.
- ERC-721: A standard for non-fungible tokens (NFTs), where each token is unique.
29. How do you test Solidity smart contracts?
- Testing can be done using frameworks like Truffle, Hardhat, or Brownie. Contracts can be tested locally on simulated blockchains (e.g., Ganache) or on testnets before mainnet deployment. Tools like Chai or Mocha are often used for writing unit tests.
30. What is OpenZeppelin
, and why is it important in Solidity development?
- OpenZeppelin is a popular framework that provides secure, reusable libraries and contracts for Solidity. It includes implementations of standard token contracts (ERC-20, ERC-721), access control patterns, and more.
E. Other advanced ones
31. What is the CREATE2
opcode, and how does it differ from CREATE
?
-
CREATE2
allows contracts to be deployed to a deterministic address based on the contract bytecode, deployer's address, and a salt value. -
Pros:
- Enables pre-calculation of contract addresses before deployment.
- Useful for factory contracts, ensuring the same contract address across networks.
-
Cons:
- Contracts cannot be deployed twice with the same bytecode and salt combination.
-
Example:
address contractAddress = address(uint160(uint256(keccak256(abi.encodePacked( bytes1(0xff), deployer, salt, keccak256(bytecode) )))));
32. How does abi.encode
, abi.encodePacked
, and abi.encodeWithSignature
differ in Solidity, and when would you use each?
-
abi.encode
: Encodes values into tightly packed binary form, used for general-purpose encoding. -
abi.encodePacked
: Encodes data in a packed format (no padding), useful for hash generation but can cause collisions with dynamic types. -
abi.encodeWithSignature
: Encodes data with a specific function signature, used for low-level call or delegatecall. -
Use cases:
-
abi.encode
for data storage or passing arguments. -
abi.encodePacked
for hash-based operations. -
abi.encodeWithSignature
for calling other contracts without ABI.
-
-
Example:
bytes memory encoded = abi.encodeWithSignature("transfer(address,uint256)", recipient, amount);
33. What is the difference between keccak256
and sha256
in Solidity, and when would you use each?
-
keccak256
: Ethereum’s primary hashing algorithm, based on SHA-3, used for signatures, address generation, and storing hashed data. -
sha256
: Standard SHA-2 hashing algorithm, often used for interoperability with external systems. -
Use cases:
- Use
keccak256
for Ethereum-specific functions like signature verification. - Use
sha256
for off-chain integrations or systems using SHA-2 standards.
- Use
34. How would you create a minimal proxy contract using the CREATE2
opcode in Solidity?
- A minimal proxy (also known as an EIP-1167 clone factory) is a contract that delegates all calls to a master implementation contract using
delegatecall
. You can combine this withCREATE2
to deploy proxies at predictable addresses. -
Steps:
- Compute the address using
keccak256
. - Deploy the proxy contract using
CREATE2
with a minimal bytecode proxy. - Example minimal proxy:
bytes memory bytecode = abi.encodePacked( hex"363d3d373d3d3d363d73", masterContractAddress, hex"5af43d82803e903d91602b57fd5bf3" ); address proxyAddress; assembly { proxyAddress := create2(0, add(bytecode, 0x20), mload(bytecode), salt) }
- Compute the address using
35. How does Solidity handle fixed-size and dynamic-size arrays differently in terms of gas usage and storage?
- Fixed-size arrays have predefined storage slots allocated for each element at compile time, making them cheaper and faster for storage and access.
- Dynamic-size arrays can grow or shrink, so additional storage and pointer management are required, resulting in higher gas costs for operations like adding or removing elements.
-
Trade-offs:
- Use fixed-size arrays when array size is known in advance and performance is critical.
- Use dynamic-size arrays when flexibility is needed.
36. What is extcodesize
, and how can it be used to check if a contract has been deployed?
-
extcodesize
is an EVM opcode that returns the size of the bytecode at a given address. It’s used to determine whether an address is a contract. - Example:
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
-
Use case:
- Helps to prevent sending Ether to externally owned accounts (EOAs) when a contract address is expected.
- Cons: Can’t differentiate between contracts in construction or destroyed contracts (selfdestructed contracts will return zero size).
37. What is the log
opcode, and how are Solidity events translated into EVM logs?
-
log
opcodes (log0
,log1
, up tolog4
) represent events in Solidity. They generate EVM logs that are stored on-chain but are not accessible within smart contracts themselves. -
Use cases:
- Used for emitting events, which are critical for off-chain dApps to monitor contract state changes.-
Example of event emission:
event Transfer(address indexed from, address indexed to, uint256 value); emit Transfer(msg.sender, recipient, amount);
-
Gas considerations: Storing data in logs is cheaper than in storage, but still requires gas.
38. What are low-level call
, delegatecall
, and staticcall
, and when should you use each?
-
call
: Executes code in another contract, allows Ether transfer, and changes context to the called contract. -
delegatecall
: Executes code in the context of the calling contract (proxy pattern). -
staticcall
: Similar tocall
, but ensures no state changes, useful for read-only external calls. -
Use cases:
-
call
for interacting with other contracts, transferring Ether, or fallback functions. -
delegatecall
for proxies and contract upgrades. -
staticcall
for ensuring no state modifications in read-only external calls.
-
39. How does the Solidity receive
function differ from the fallback
function, and when would you implement each?
-
receive
: A specific function triggered when the contract receives Ether without data. -
fallback
: Triggered when a function is called that does not exist in the contract or when the contract receives Ether with data (ifreceive
is not defined). -
Use cases:
- Implement
receive
for contracts that should accept Ether without any accompanying data. - Use
fallback
for advanced behavior like proxy contract routing or handling unexpected function calls. -
Example:
receive() external payable { } fallback() external payable { }
- Implement
40. What is assembly in Solidity, and when would you use inline assembly (Yul)?
- Assembly (Yul) allows for low-level manipulation of the EVM using opcodes directly. It's used for optimizations, gas savings, or accessing functionality not directly available in Solidity.
-
Use cases:
- Gas optimization for complex arithmetic or loops.
- Direct access to low-level EVM opcodes (e.g.,
mstore
,mload
).
-
Example:
function add(uint x, uint y) public pure returns (uint) { assembly { let result := add(x, y) return(result, 32) } }
-
Trade-offs:
- Can significantly reduce gas costs.
- Harder to read, maintain, and secure compared to high-level Solidity code.
41. What are the gas optimizations you would apply when writing Solidity code, and what trade-offs do they introduce?
- Gas optimizations include reducing storage writes, using
memory
instead ofstorage
, minimizing contract size, and packing variables.-
Pros:
- Reduces transaction costs, making your contract more efficient.
- Improves the performance of decentralized applications (dApps).
-
Cons:
- Over-optimizing can make code harder to read and maintain.
- Optimizations like variable packing might introduce bugs if improperly handled (e.g., overflow issues).
-
Pros:
42. What are the challenges of using the selfdestruct
function for contract upgrades or termination?
- The
selfdestruct
function deletes a contract from the blockchain and transfers any remaining Ether to a specified address.-
Pros:
- Removes the contract, freeing up storage space on the blockchain.
- Can be used to return funds in emergency situations.
-
Cons:
- Leaves orphaned contract calls, which may cause other contracts interacting with it to fail.
- There’s no way to undo a
selfdestruct
once executed.
-
Pros:
43. What are storage collision attacks, and how do you prevent them when using delegatecall
in Solidity?
-
Storage collisions occur when the storage layout between the proxy contract and the implementation contract differs, potentially causing state corruption.
-
Pros of preventing it:
- Ensures the integrity of contract storage and logic.
-
Cons:
- Requires careful design and auditing of storage layout across contract upgrades.
- Incorrect handling can still lead to subtle, hard-to-detect bugs.
-
Pros of preventing it:
44. How would you implement a time-lock mechanism in a smart contract, and what are its potential pitfalls?
- A time-lock restricts access to certain functions or assets for a predetermined time period, typically used for vesting or governance delays.
-
Pros:
- Improves security by allowing a delay between action and execution, giving time for review.
- Can prevent impulse or malicious actions.
-
Cons:
- May lead to unintended delays or freezing of assets if poorly implemented.
- Increases complexity, potentially making the system harder to interact with.
-
Pros:
45. What is Solidity’s immutable
keyword, and how does it compare with constant
?
- The
immutable
keyword defines a variable that is set during contract deployment and cannot be changed after that, but is not stored in storage.-
Pros:
- Reduces gas costs since
immutable
variables are stored in contract bytecode rather than storage. - Allows flexibility compared to
constant
, which must be known at compile-time.
- Reduces gas costs since
-
Cons:
- Once set, it cannot be changed, leading to potential limitations if the contract requires dynamic behavior later.
-
Pros:
45. How do you secure a multi-signature contract, and what are the potential vulnerabilities?
-
Multi-signature contracts require multiple parties to sign off on a transaction before it is executed, adding a layer of security.
-
Pros:
- Reduces the risk of a single point of failure or malicious control.
- Offers decentralized governance and enhanced security for high-value assets.
-
Cons:
- Introduces coordination challenges among signers, leading to delays.
- Vulnerable to denial-of-service (DoS) attacks if some signers become inactive or maliciously refuse to sign.
-
Pros:
These common and advanced questions delve deeper into Solidity's low-level mechanisms, optimization techniques, and EVM behavior, probing the candidate's understanding of performance, security, and the inner workings of smart contracts.
If you found this helpful, let me know by leaving a 👍 or a comment!, or if you think this post could help someone, feel free to share it! Thank you very much! 😃
Top comments (0)