In this article you will find 100 questions to prepare your Solidity job interview. Questions are grouped into easy, intermediate and difficult categories.
By the way, if you want to make sure you understand and remember all the questions / answers listed in this article, you need to spend some time writing many Solidity smart contracts. In my course Smart contract 30 we create 30 Solidity smart contracts ranging from easy to advanced. That’s the most in-depth course tutorial on Solidity that exist, and I am also releasing a sister course to test all these smart contracts with Truffle and Javascript.
Easy
1. What is an Ethereum smart contract?
An Ethereum smart contract is a small program that runs on the Ethereum blockchain.
2. What makes an Ethereum smart contract so special compared to other programs?
Once an Ethereum smart contract is deployed to the blockchain, it cannot:
- be stopped
- be hacked (as long as the code of the contract is correct)
- be modified (the code is immutable, however the data is)
3. Can a smart contract interact with other smart contracts?
Yes.
4. Can a Solidity smart contract call an API on the web?
No, it can only execute its own code and interact with other smart contracts on the blockchain
5. Can a Solidity smart contract store a lot of data?
No, storage is very limited on a smart contract. Storing data cost gas, and gas consumption is capped in each Ethereum block. So indirectly, storage is limited.
6. Can a smart contract be written in another language than Solidity?
Yes. There are other smart contract languages like Vyper or LLL. But Solidity is the most popular.
7. Is Solidity a dynamically or statically typed language? (i.e need to define variable types)
It’s a statically typed language, i.e variable types need to be defined, unlike in dynamic languages like Javascript.
8. Is Solidity compiled or interpreted?
It’s compiled, meaning it means to be first compiled before we can run the code.
9. What is the file extension of Solidity files?
.sol
10. Can a single Solidity file have several smart contracts?
Yes.
11. What is the typical layout of a Solidity smart contract?
//pragma statement (required)
pragma solidity ^0.5.9;
//contract declaration (required)
contract A {
//state variables
uint a;
//functions
function foo() {...}
}
12. What is the difference between state variables and local variables?
contract A {
//state variable
uint a;
//functions
function foo() {
uint b; //local variable
}
}
State variables are persisted on the blockchain after a smart contract finish to execute, whereas local variables live only during the execution of a function.
13. What is the problem with the following code (1/2)?
contract Storage {
uint data;
//Should update the `data` storage variable above
function set(uint _data) external {
address data = _data;
}
}
The set()
function redefine the data
variable inside its body. This will create a local variable that will shadow the state variable defined above. The assignment address data = _data
will assign to this local variable instead of the state variable. To fix the code, remove the address
keyword in front of data in the set()
function: data = _data
;
14. What is the problem with the following code (2/2)?
contract Storage {
uint data;
//Should update the `data` storage variable above
function set(uint data) external {
//data = data?
}
}
This is similar to the problem we have just before. The data
argument of the set()
function shadows the data
state variable. Because of this, we can’t access the data
state variable inside the set()
function. To solve this problem, we need to rename the argument from data
to _data
.
15. What are the 2 variable visibilities for state variables in Solidity?
- private
- public
16. Who can read private and public variables?
- private variables can be read only by functions inside the smart contract
- public variables can be read by anyone
17. What is the default visibility of state variables?
Private.
18. Are private variables really private?
No. Private is only for the EVM (Ethereum Virtual Machine, the part of Ethereum that execute smart contracts). But the data of smart contracts is put on the Ethereum blockchain, and all data on this blockchain is public. Using a special tool to analyse blockchain data, anyone to read private variables of smart contracts.
19. How to deal with private data then?
You either don’t put private data on the blockchain, or you put hashes.
20. Mention 3 data types that you use often, and explain why
- uint, for ether / token transfers, and identifying data
- address, for identifying humans and smart contracts
- strings, for naming things
21. What are the 2 container types in Solidity?
- mapping
- arrays
22. How to declare an array of integer in Solidity?
uint[] a;
23. How to declare a mapping of address to booleans in Solidity?
mapping(address => bool) a;
24. How to declare a mapping of address to mapping of address to booleans (nested mapping)?
mapping(address => mapping(address => bool)) a;
25. How to add data to an array declared as a state variable?
uint[] a;
function add(uint newEntry) external {
add.push(a);
}
26. How to add data to a mapping declared as a state variable?
mapping(address => bool) a;
function add(address addr) external {
a[addr] = true;
}
27. How to loop through an array?
uint[] a;
for(uint i = 0; i < arr.length; i++) {
//do something with arr[i]
//reading: uint a = arr[i]
//writing: arr[i] = a
}
28. What is the difference between a uint8 and a uint16?
uint8
can store number of up to 2^8 -1 (it has 8 bits), whereas uint16
can store numbers of up to 2^16 – 1.
29. What are the 4 function visibilities in Solidity, by increasing permissiveness?
- private
- internal
- external
- public
30. How to conditionally throw an error, with an error message?
Use require statement:
require(a !== b, 'My error message')
31. What are the 2 artifacts produced by the Solidity compiler when compiling a smart contract?
- The ABI (application binary interface)
- The bytecode
32. What is the ABI of a smart contract?
The ABI defines the interface of a smart contract, i.e the set of functions that can be called from outside the smart contract. The ABI only defines the function signatures (function names, argument types and return types) but not their implementation. The ABI also defines the events of the contract. The ABI is used outside the smart contract by Ethereum client libraries like web3 to interact with the smart contract.
33. In the following contract, which function will be part of the ABI?
contract A {
function foo() external {...}
function bar() public {...}
function baz() internal {...}
}
foo()
and bar()
will be part of the ABI.
34. Does the EVM understands Solidity?
No. The EVM only understand bytecode, which must first be produced by Solidity, outside of the blockchain.
35. What is the EVM bytecode?
The EVM bytecode is a series of EVM elementary instructions called opcodes. These opcodes define very simple simple operations like adding 2 numbers (ADD), loading data from memory (mload), etc… There are more than 100 of these opcodes defined in the Ethereum yellow paper. Coding directly with opcodes would be very tedious, so we need higher languages like Solidity to help us reason at a higher level of abstraction.
36. What are the 2 APIs used to interact with a smart contract?
eth_sendTransaction
(transaction) and eth_call
(call). Transactions cost money (gas) and can modify the blockchain. Calls do not cost money, cannot modify the blockchain, but can return a value contrary to transactions.
37. What is gas?
Gas is an abstract unit used to pay miners when sending a transaction on the Ethereum network.
38. How is gas paid?
Gas is paid in ether using the formula: ether cost = gasPrice * gas
, where gas represents the gas cost of the execution of a transaction. gasPrice
is in wei / gas, generally express is Gwei. A transaction also specifies a gasLimit
parameter, which specify a maximum number of gas that can be paid by a transaction. Without this, a transaction could potentially drain an account of all its Ether.
39. What happen if there is not enough gas in a transaction?
The transaction is stopped, and all state changes are reverted.
40. Who pays for gas in a transaction?
The sender of the transaction.
41. What is the most famous online IDE for Solidity?
Remix
42. List 2 famous smart contract framework for Solidity
- Truffle
- OpenZeppelin
43. Which Javascript Ethereum client can we use to develop Solidity on a local blockchain?
Ganache
44. What do you need to deploy a smart contract to the Ethereum network?
- bytecode of smart contract
- an Ethereum address with enough Ether
- A wallet to sign the transaction
- A tool to create the transaction and coordinate the signing process with the wallet
45. List 4 famous Ethereum wallets
- Metamask
- MyEtherWallet
- Ledger
- Trezor
46. List 3 networks where you can deploy a Solidity smart contract
- Mainnet
- Ropsten
- Kovan
Intermediate
47. How to manage dates in Solidity?
You need to use uint
variables.
48. How to have the current timestamp in seconds?
You need to use the now
keyword.
49. How to construct a timestamp of 1 day in the future?
A: now + 86400
50. What are the 2 ways to define custom data structure in Solidity?
- Struct
- Enum
51. When would you use a struct vs an enum?
Struct are for representing complex data structures with different fields. Enum are for creating variant for a single data. Ex: a color can be red, blue, yellow. You can combine both by defining an enum, and a struct that uses this enum in a field;
enum FavoriteColor }Blue, Red};
struct User {
address id;
string name;
Color favoriteColor;
}
52. What are the 2 ways to instantiate a struct?
struct User {
address id;
string name;
}
//Method 1 (argument order matters)
User("0xAio90....", "Mike");
//Method 2 (argument order does not matter)
User({name: "Mike", address: "0xAio90...."});
53. How to instantiate a struct that has an inner mapping?
struct User {
address id;
string name;
mapping(address => bool) friends;
}
//let assume the User struct is stored inside a mapping
mapping(address => User) users;
//Inside a function, you would instantiate your struct like this
users["0xAio90..."].id = "0xAio90...";
users["0xAio90..."].name = "Mike";
users["0xAio90..."].friends["0xIopop..."] = true;
users["0xAio90..."].friends["0xjk89I..."] = true;
54. When would you use an array vs a mapping?
I would use an array if I need to iterate through a collection of data. And I would use a mapping if I need to rapidly lookup a specific value
55. How to combine array and mapping to allow both iteration and rapid lookup of a struct?
//Let's consider this struct
struct User {
uint id;
string name;
}
//First, let's use an array to store all its ids
uint[] userIds;
//Then, let's use a mapping for rapid lookup
mapping(uint => User) users;
//If we need to rapidly lookup a user, we use the mapping
//And if we need to iterate through users, we iterate through the userIds array,
//and for each userIf we can
//lookup the correct user in the mapping
56. How to define an in-memory array of 3 integers?
uint[] memory arr = new uint[](3);
57. How to add a value to an in-memory array?
uint[] memory arr = new uint[](3);
uint[0] = 1;
uint[1] = 2;
uint[2] = 3;
uint[3] = 1; //out-of-bounds error
58. How to get the list of all keys in a mapping (like Object.keys() in Javascript)?
It’s not possible. Smart contracts don’t keep track of the list of entries in a mapping. You need to already know which key you want to access, or to store the list of keys yourself in a separate array.
59. How to create an in-memory mapping?
You can’t. Solidity has only storage mappings.
60. What happen if you try to access the key of a mapping that does not exist?
Contrary to arrays, there is no error, Solidity will give you a value, which is the default value of the type.
Ex:
mapping(uint => bool) myMap;
If you access myMap[10] but nothing exist there, Solidity will produce false
.
61. What are the 3 mechanisms for code re-use in Solidity?
- Group common codes in functions
- Contract inheritance
- Libraries
62. How to make a contract A inherit from a contract B in Solidity?
// First import the contract
import B from 'path/to/B.sol';
//Then make your contract inherit from it
contract A is B {
//Then call the constructor of the B contract
constructor() B() {}
}
63. If A inherit from B, and both define the same function foo, which one will be resolved?
//Case 1
contract B {
function foo() external {...}
}
contract A is B {
function foo() external {...}
}
If I call foo()
on A
, the function A.foo()
will be resolved
//Case 2
contract B {
function foo(uint data) external {...}
}
contract A is B {
function foo() external {...}
}
If I call foo(1)
on A
, the function B.foo()
will be resolved, because only B
defines foo(uint)
64. What are the 4 memory locations of Solidity?
Storage, Memory, Stack and Calldata
65. What is the default visibility of state variables?
Private
66. What is the difference between address
and address payable
?
Only address payable
can receive money
67. Is it necessary to make an address address payable
to transfer ERC20 tokens?
No. The payable
requirement is only required for native Ether. Ethereum has no knowledge of ERC20 tokens. For Ethereum, this is just a variable in a smart contract, like any other variables.
68. What are the main changes in Solidity 0.5.x vs 0.4.x?
- constructors are declared with the
constructor()
keyword instead offunction NameOfContract()
address
has been split into 2 subtypes:address
andaddress payable
. Only the second one can receive ether.- The
var
keyword has been removed - Events need to be emitted with the
emit
keyword - memory location needs to be explicit
- function visibility needs to be explicit
69. Give 3 ways to save gas
- Put less data on-chain
- Use events instead of storage
- Optimal order for variable declaration. See this link.
70. How would optimally order uint128, bytes32 and another uint128 to save gas?
uint128
uint128
bytes32
The EVM stores variable in 32-bytes slot. However Solidity is smart enough to pack into a single slot several variables if they can fit together. For this optimization to work, packed variables have to be defined next to each other. In the above example, the 2 uint128
will be placed in the same 256 bit slots (128 + 128 = 256).
71. How to concatenate 2 strings a, b?
Use the abi.encodePacked()
function:
string(abi.encodePacked(a, b));
72. How to get the length of a string in solidity?
bytes memory byteStr = bytes(a); //a is a string
bytesStr.length;
73. How to to create a smart contract from a smart contract?
contract A {
constructor(uint a) {...}
function foo() external {...}
}
contract B {
function createA(uint a) external {
A AInstance = new A(a); //pass constructor argument(s) if any
}
}
74. How to to call another smart contract from a smart contract?
contract A {
function foo() view external returns(uint) {...}
}
contract B {
function callFoo(address addrA) external {
uint result = A(addrA).foo();
}
}
75. How to get the address of a smart contract that was deployed from a smart contract?
Using the address()
operator to cast the contract type into an address:
address childAddress = address(new Child())
76. What will be the value of msg.sender
if a contract calls another one?
//This is the inner contract
contract A {
function bar() view external returns(address) {
//What will be the value of `msg.sender` here?
}
}
//This is the outer contract
contract B {
function foo() external {
A aInstance = new A();
aInstance.bar();
}
}
This is the address of the calling contract, i.e B in our example.
77. How to transfer ERC20 tokens?
contract ERC20Interface {
function totalSupply() public view returns (uint);
function balanceOf(address tokenOwner) public view returns (uint balance);
function allowance(address tokenOwner, address spender) public view returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
contract DecentralizedExchange {
function transferToken(address ERC20Address, address to, uint amount) {
ERC20Interface(ERC20Address).transfer(to, amount);
}
}
78. How to declare and emit an event?
contract A {
//declare event
Event TokenSent(uint amount, address to);
function sendToken(uint amount, address to) external {
...
//Emit event
emit TokenSent(amount, to); //careful, old Solidity 0.4 code didnt not require the emit keyword, dont be confused
}
}
79. What is the indexed
keyword in event definition?
If an event field is declared with the indexed
keyword, it means that external entities can filter only events whose field match a specific value. For example, in the below example, it means it’s possible to filter events with a to
field equal to a specific value.
Event TokenSent(uint amount, address indexed to);
80. How many event fields can be marked indexed
?
3 maximum.
81. Is it possible for a smart contract to read the events emitted before?
No. Only external entities can queries events.
82. Is it possible to delete or modify a past event?
No. Events are immutable.
83. In Solidity, how to do like a Javascript console.log for debugging?
There is no equivalent in Solidity, but you can use events, even if its not designed for this.
84. How would you implement access control without modifier?
contract A {
address admin;
constructor() {
admin = msg.sender;
}
function protectedFunction() external {
require(msg.sender == admin, 'only admin');
...
}
}
85. How would you implement access control WITH modifier?
contract A {
address admin;
constructor() {
admin = msg.sender;
}
function protectedFunction() external onlyAdmin() {
...
}
modifier onlyAdmin() {
require(msg.sender == admin, 'only admin');
_;
}
}
86. How to cancel a transaction?
Once a transaction has been sent, nobody can prevent it from being mined by a miner. But you can still send another transaction preventing the first one from working IF its mined before the first one. This second transaction will have the following properties:
- it will have the same nonce (i.e an incrementing integer that is sent in each transaction, specific to each Ethereum address)
- it will have a higher gasPrice than the first transaction
- it will send a tiny amount of Ether to another address
Let’s review why we need these. The same nonce means that the first transaction to be mined will prevent the other one from being mined: miners only mine transactions whose nonce is higher than the previous nonce for the address that has signed the transaction.
The higher gasPrice means a higher reward for miner, so if a miner has the choice to mine the second or the first transaction he will choose the second one.
And finally, sending a tiny amount of Ether is just because a transaction needs to do something on the blockchain, so we just do something that is useless but doesn’t cost us much. Actually, you could even call a read-only function in any smart contract, in a transaction, and you wouldn’t even need to send this tiny amount of Ether. You would still need to cover the gas fee in every case.
Difficult
87. What is the ABIEncoderV2 pragma statement?
This is an pragma statement is used to enable experimental features not yet enabled in standard Solidity. For example it enables to return a struct from a function called externally, which is not possible in standard Solidity yet (0.5.x).
88. Is it safe to use the ABIEncoderV2 pragma statement in production?
No. It should only be used in development, not in production.
89. Is it possible to send a transaction without requiring users to pay gas?
Yes. You would ask users to first sign a message on the frontend. Then the message and signature would be sent to a centralized backend (your app, off-chain) that would create a transaction and embed the payload (message + signature) into it. That means that gas fees will be covered by the wallet of the app, instead of the user wallet. On-chain, a smart contract will verify the validity of the signature and perform on operation on behalf of the user.
90. Which Solidity function would you use to verify a signature?
ecrecover()
.
91. What is a library in Solidity?
A library is a piece of code that be re-used by other smart contracts. There are 2 types of libraries:
- deployed
- embedded
Deployed libraries have their own address, and they can be used by several other smart contracts. Embedded libraries don’t have their own address and are deployed as part of the code of the smart contract that use them.
92. Give an example of how to use a library in a smart contract
library Lib {
function add(uint a, uint b) pure internal returns(uint) {
return a + b;
}
}
contract A {
using Lib for uint;
function add(uint a, uint b) pure external returns(uint) {
return a.add(b);
}
}
93. When is a library embedded vs deployed?
//Embedded (function is internal)
library Lib {
function add(uint a, uint b) pure internal returns(uint) {
return a + b;
}
}
//Deployed (function is public)
library Lib {
function add(uint a, uint b) pure public returns(uint) {
return a + b;
}
}
94. What is a re-entrancy attack?
A re-entrancy attack happen when a contract A calls a contract B which call back the calling function on contract A to perform some malicious effect. Example with a DAO-like attack:
contract A {
//...
function pay(address payable to, uint amount) external {
if(amount <= balances[msg.sender]) {
B(to).badFunction().send(amount);
balances[msg.sender] -= amount;
}
}
contract B {
address
function badFunction(address payable to) external {
ContractA(msg.sender).pay();
}
}
95. How to prevent against a re-entrancy attack?
- Solution 1: Decrease balances / do other state variable update BEFORE calling the other contract.
- Solution 2: Put in place re-entrancy guard with a variable that knows when a call is the second in the stack
- Solution 3: Limit the gas available to the called contract. If using
transfer()
, this is done automatically:
96. How to produce a hash of multiple values in Solidity?
keccak256(abi.encodePacked(a, b, c))
97. How to generate a random integer in Solidity?
We can leverage the block.timestamp
and block.difficulty
as a source of randomness, and use the keccak256()
hashing function:
uint(keccak256(abi.encodePacked(block.timestamp, block.difficulty)))
Be aware that miners can manipulate block.difficulty
and block.timestamp
, so this is not 100% secure.
98. What are the 2 kind of assembly in Solidity?
Functional and instructional. Functional uses functions, whereas instructional is a raw series of opcodes. Most people use the functional style.
99. How to declare assembly code?
assembly {}
100. Create a function to determine if another address is a contract or a regular address
function isHuman(address addr) external {
uint256 codeLength;
assembly {codeLength := extcodesize(addr)}
return codeLength == 0 ? true : false;
}
}
By the way, if you want to make sure you understand and remember all the questions / answers listed in this article, you need to spend some time writing many Solidity smart contracts. In my course Smart contract 30 we create 30 Solidity smart contracts ranging from easy to advanced. That’s the most in-depth course tutorial on Solidity that exist, and I am also releasing a sister course to test all these smart contracts with Truffle and Javascript.
Solidity
Leave a Reply