- Fixed length array uint [5] arr; length cannot be increase.
- Array variable can be limited like address[] memory pools = new address; .
- Variable 2 types i.e., value and reference. https://www.geeksforgeeks.org/solidity-types/
- Encoding is done using keccak256 which expect single arg in bytes. https://cryptozombies.io/en/lesson/1/chapter/11
- Hash of specific length can be attained using modulo i.e.; hash % (10 ** length).
- Modulo only works for uint/int data type.
- Key can be incremented for mapping like mapping[key]++; .
- An account can be used by using it with interface i.e.;
ContractInterface contractVar = KittyInterface(contractAddress);
. The function then can be called with methodcontractVar.func(args)
. - Renounce ownership is setting owner to address(0) which cannot be called anymore. https://cryptozombies.io/en/lesson/3/chapter/2
- Better to emit event just before changes takes place.
- If file is imported all contracts will be inherited, if a specific contract is called then it will be inherited then.
- Inheritance rule is followed from origin if a base contract inherits a contract it can be inherited to every other contract that inherits base contract.
- Inheritance depends on import..import is linking file name, inheritance is linking with contract name.
- Use smallest integers inside struct for minimum storage space.
- Storage pointer can be used as arg inside a internal or private function.
- Identical data types packing cost less gas as they are clustered together. https://cryptozombies.io/en/lesson/3/chapter/4
- Uint default return value is 256 bits.
- Tuple are structs which requires input value to be passed with same arguments numbers as in struct. https://remix-ide.readthedocs.io/en/latest/udapp.html#passing-in-a-tuple-or-a-struct-to-a-function
- Calldata is for external functions while memory is for internal. View functions are gas free for external function.
- Storage operations are most expensive mainly for writing.
- Memory arrays are created with fixed length as they cannot be resize by using push method.
- Memory array inside external function with view attribute built with for loop is overall cheap in terms of gas.
- Bytes(str).length method for knowing string length.
- Functions in interface should be of same name with return value to be placed in order according to the main contract(same applied to implementing contracts.
- keccak data type is bytes32...abi. datatype is bytes with storage as memory or calldata.
- The ‘unchecked’ keyword is used for particular operation without any checks. When ‘unchecked’ is used, Solidity skips these default checks and assumes that the operation will not result in any issues.
- Unchecked can cause arithmetic over and underflow and should be used cautiously.
- Require and if condition works in an opposite way (mainly for the relational operators).
- View functions don't cost any gas when they're called externally. View function when called by a non-view function internally within a contract cost gas.
- Overflows occur when the value to be represented exceeds the range of values representable by a given type. The integer overflow occurs when a number is greater than the maximum value the data type can hold. Uint8 = max[255] + 1 overflow leads to 0, Uint8 = min[0 ] - 1 overflow leads to 255 as it is a –ve overflow.
- Underflows occur when the precision a type offers isn't enough to fully represent the result of an operation. The integer underflow occurs when a number is smaller than the minimum value the data type can hold. Underflow example is when denom is smaller than numerator 3/2.
- new uint; means initiating an array with length 3. Values are assigned as values[0] = 1;
- An array can be build inside a view function with memory pointer which make it retrieving data without any spending any gas.
- Code ordering is important in making logic to be strong.
- The keyword block.timestamp is constant as storage variable in contract but updated when called within a function.
- To pass message in error function string keyword must be declared inside error thisError(string).
- Modifiers are of 4 types i.e., visibility, state, custom and payable. Visibility is pvt, public, internal and external; state are view and pure; and custom are defined inside contracts. Payable modifier provides function with ability to receive ether.
- Ether can only be transfer to a payable address.
- Send and transfer are carried out using ( ) while call is done through call{value: msg.value}(" "); for transferring ether.
- call{value: msg.value}(" "); msg.value is the amount transfer while (" "); is checking return value. https://consensys.io/diligence/blog/2019/09/stop-using-soliditys-transfer-now/
- .call( ) is prone to reentrancy and should be used with caution.
- In solidity 0.8 and above transfer to caller is like this payable(msg.sender).transfer(address( this) .balance).
- Random values can be created in solidity using this keccak256(abi.encode(block.timestamp, msg.sender, randNonce))), this is due to all params will be different.
- % _modulus will limit number of number generated like for 100 it will give number from 1-99.
- Always put condition first in require that have higher computation process i.e., if (ids[msg.sender] == id) as this save gas.
- Redundant condition can be used as modifier for better access control.
- Memory pointer does not write to state variables. Memory pointer has block scope. Always use storage pointer to write data on state variables.
- Implementing a contract is linked to creating its interface which includes all functions and events. Then it is inherited in the contract. Functions in interface have external visibility with name to remain same.
- Function and modifier cannot have similar name and will lead to error.
- Mapping[num] = address; is the method to change address of a mapping.
- Library is a contract that is attached to functions with specific data type i.e., using library for data type. Library must be linked with the contract either making it internal to file or import.
- An argument can be passed to an function through variable with accessing i.e.; uint test = 2; test = test.mul(3);.
- require refund the rest of gas when a function fails, whereas assert not.
- Safemath method can be instead of decrement or increment like instead maker++ use maker.add(1).
- Natspec are comments with different tags like author, dev, title, param, audit etc.
-
Code are executed in top to bottom and left to right order.
-
Bytes and bytes32 have different bytes values in solidity.
-
Strings are converted to bytes.
-
View function does not allow state change. They are gas less and will cost gas only when they are called by another function internally.
-
Struct are custom data type that can have different data types in its. Structs are declared with pointers according to need.
-
Values can be passed simply according to data location or json key pair value.
-
Datatype also need to be declared while passing values.
-
Array declared with data types are dynamic i.e., struct[] arr. Static array are defining number of values during declaration struct[5] arr.
-
10 ** 18 and 1e18 is same thing.
-
Struct[index].datatype is method to read value inside of struct at a given index.
-
keccak256(abi.encode(string ) is method to convert string into bytes.
-
6 areas evm store information i.e.; storage, memory, call data, code, stack and logs[events].
-
Calldata and memory are temporary storage executed during function.
-
Calldata cannot be modified. Storage and memory data types can be modified.
-
Data storage are defined for struct, arrays and string.
-
Same return type should be declared in returns in which data is stored i.e.; simpleContract myContract should return simpleContract;.
-
Chainlink price feed return 8 decimal which can be converted to 18 using the method...return uint256(price * 1e10).
-
Chainlink latestRoundData returns 5 parameter of which second is taken i.e. price (, int256 price,,,).
-
Msg.value can be converted to token price in usd by formula:
msg.value * latestrounddata / 1e18
. -
Token price in usd can be converted to msg.value using formula ```(amountInUSD * 1e18) / TokenPriceInUSD;
-
Amount difference can be calculated using above point formula.
-
Multiple input can be added to array variable using loops.
-
arrVar = new array; is the method to delete every index of array.
-
Value increment in mapping should be use with += i.e.; map[address] += uint;
-
Modifier should be used if same condition have to be applied to different function.
-
Custom error an also be used instead of require condition.
-
Multiplication should always be carried out before division with also ensuring denominator is lower than numerator.
-
Transferring amount are carried out using transfer, send and call method.
-
Transfer and send have 2300 gas limit. Transfer throws error if txn need more than 2300 gas, Call fwd all the gas
-
Send and call method are low level calls which return bool value used to check for revert.
-
.call method is used to call function of contract
.call("")
. -
Receive and fallback functions are used to receive ether on contract. Fallback is called when no function with specific name exist and some data is sent with ether.
-
Libraries cannot be inherited. Libraries are used inside contract for specific data type i.e., ‘using library for uint’.
-
When using a function of library inside a contract, its first parameter must be the data type for which it is used.
-
dynamic datatypes (bytes, string or array) are not use with calldata instead we use the memory keyword.
-
calldata is a read-only temporary memory location that holds the function arguments sent to the function by the caller (EOA or another smart contract). You cannot instantiate calldata in the contract.
-
Amount in wei * tokenPrice / 1e18 gets the token value in decimal[USD].
-
Amount in wei * 1e18 / tokenPrice gets the token value in ether.
-
Struct with mappings cannot have pointers in memory.
-
Updating time variables through function should be carried out in last to avoid collision with condition to check for time.
-
In require condition the value which is target(influence the state change) should come first i.e.; require(block.timestamp > timeLimit).
-
Script contract must have run(), and test must have setup() as the first function.
-
Test contract should inherit script as well as the main contract.
-
Struct does not allow mapping and array in it.... ethereum/solidity#12302
-
Constructor cannot have visibility but can be mark payable.
-
Indexed events are topics...normal events are data that are merged with abi.
-
If and require condition are backward compatible.
-
Enums are custom data types which act mainly in context of Boolean condition. They can be used similarly to struct by defining them and using them with pointer variables.
-
Default value of enum will be the 1st element.
-
Enums can be converted into uint by type casting them like uint256(enum.elementIndex);
-
Error can be revert with data by declaring data in them. “revert error_name(address, uint, bool)”.
-
Empty arguments can be passed for function if like
function check_UpKeep(bytes memory /* check*/)
and will be called in likecheck_UpKeep(“”)
. -
Values in struct can be passed simply as struct as well as using json key-pair value syntax.
-
Any type returns in a function must be returned in its type or casted to it type before returning, e.g. returns (datatype memory) {return datatype()}.
-
Stack too deep error can occur if many local variables are used in a function. The solution is to divide them into two or more parts.
-
Vm.prank makes call to only one state changing function in a single txn but vm.startPrank can makes multiple calls.
-
Event in foundry can be tested using
expectEmit
which takes upto 5 params after which event is emitted followed by actual txn that is emitting the event in the contract function. -
Events must be separately defined in the test contract with same name and parameters(datatypes).
-
ERC-677 are upgradeable version and erc-777 as they are backward compatible erc-20.
-
If a contract is inherited (and have a constructor), it constructor can be passed as a modifier with the parent contract constructor.
-
An account can receive ERC20 token even if it does not have
receive
orfallback
function. -
ERC20 contract
approve
function returns true even if an address does not have ERC20 tokens and call the approve function. -
transfer
andsend
method will revert if receive and fallback function have any logic in it. This is due to 2300 gas limitation on these functions. -
call
method is low-level function which is called only by functions and not contractTypes. It returns bool and data. -
Eth fund can be withdraw from contract through low level call even if there is no withdraw function in the contract.
-
Integers cannot be directly converted to strings it requires OZ’s string lib and
Strings.toString(tokenID)
syntax. -
If multiple strings are required to concatenate they must be encode and then casted to string before concatenation.
-
Abi.encode/encodePacked is used to convert a data type into bytes. Abi.decode is used to convert bytes into its original datatype.
-
Integers conversion to bytes required first casting to its type
uint16 or uint256
thenabi.encodePacked
method is used. -
Abi.decode is used to bytes into its original datatype, by explicitly defining datatype as 2nd argument.
-
Library should be declared for data types they are used for
using Strings for uint256
, Strings library of OZ is used for uint data type. -
Base64 data can be converted only when datatype is of
bytes
. -
Integer can be changed to enum value by casting
enum(integer)
. -
All elements in enum elements can be retrieved using
uint(type(enum).max)
. -
Abi.encode
generate whole length bytes result whileabi.encodePacked
generated data without padding. -
Abi.encode is actual encoding while abi.encodePacked is casting.
-
Hash of encodePacked can be converted simply to it original form by casting to its type while encode require decoding with type define.
-
Data encrypt from abi.encode can be decode using abi.decode(bytes, datatype). Multiple data can be encoded and decoded in same manner.
-
Function selector is 1st four bytes of a function having its name and types of param.
-
Function selector bytes code can be generated by using function signature.
-
Bytes is not required if function signature is converted inside a function while required if called from outside.
bytes4(keccak256(bytes(func))); // method to generate function selector from function signature
-
Function selector can also be generated by using foundry cast command e.g: cast sig "functionName(address,uint)".
-
Function selector can be generated using cmd
this.functionName.selector
this only works for function having external or public visibility. -
Function signature is function name along with its parameters types e.g: "transferFrom(address, address, uint)".
-
Low level call can be made using function signature with method
abi.encodeWithSignature(functionsignature, param)
. -
Function signature can be generated from function selector using foundry cast command e.g: cast 4byte functionselectorbyte.
-
Function selector can also be used to make low level calls with method
abi.encodeWithSelector(functionselector, param)
. -
Difference between calldata and memory is based on type of call made. Memory is call made from inside the contract and calldata is made from outside the contract.
-
Bytes.length
is method to get data size of bytes. -
Bytes
is dynamic data which is used to save or return data without any limit. -
Reverse loop have condition in reversed form with length starting from length of loop and run till condition is greater than 0 and decrement for i. The index taken is (i-1) inside loop code.
-
Delegatecall is used to make call to another contract(implement) by caller(proxy).
-
Storage slot should be same as that of implement to avoid collision that will overwrite storage value or panic if cannot be encoded(bool/uint into string/bytes).
-
new
syntax means deploying a new contract i.e.,new Implement
while using only contract name means castingImplement
. -
Creating a constructor in the implementation won’t work because it will set the storage variables in the implementation.
-
A simple initializable contract doesn’t support
initializer
when contracts use inheritance and parent contracts also have to be initialized. -
The initializer modifier, updates the initialized variable to true. This variable is used by all contracts in the inheritance chain and will result in revert when
child initialize
is called as it already sets for the ``parent initialize```.x -
OpenZeppelin’s
Initializable.sol
contract addresses initializer issue by allowing initialization for all contracts within an inheritance chain. -
The core of Initializable.sol consists of three modifiers:
initializer
,reinitializer
andonlyInitializing
. -
The
initializer
modifier should be used during the initial deployment of the upgradable implementation contract and exclusively in the childmost contract. -
The
reinitializer
modifier should be used to initialize new versions of the upgradable implementation contract, again only within childmost contracts. -
The
onlyInitializing
modifier is used with parent initializers to run during initialization and prevents those initializers from being called in a later transaction. -
If
initialize
is called viadelegatecall
from the proxy, the owner is stored in the proxy’s storage. Ifinitialize
is called directly on the implementation, the owner is stored in the implementation’s storage. -
upgradeable should be called only in parentmost contract to avoid double initialization.
-
Specific pattern upgradeable only are upgraded to its own pattern like
UUPS
upgrade can only be upgraded toUUPS
. -
Initializer
modifier can be used in constructor to prevent overtaking of implementation ownership but not recommended.__disableInitializers()
function is currently most efficient way to avoid implementation ownership overtaking. -
Initialization function frontrun can be prevented by using
ERC1967Proxy
constructor to call the implementation at deploy time. The initialization call must be made at this moment, encoded in the _data variable. -
Maximum limit for upgrade is
type(uint64).max
, setting upgrade version to type(uint64).max (_initialized in the implementation) ensures the implementation contract will never be initialized. -
Care must be taken to not initialize the same contract twice, which can occur in an inheritance chain where two contracts share the same parent.
-
_disableInitializers()
prevent front running of initializer for initialize function by restricting calling initialize function through implementation contract. -
UUPS have upgrade logic in implementation while Transparent have logic in proxy.
-
Transparent requires
AdminProxy
to call every function while UUPS only required admin call for upgrade. -
Transparent pattern can be upgrade to a non upgradeable contract while UUPS only can be upgraded to an upgradable contract.
-
UUPS make call to upgrade from function
upgradeToAndCall
for new implementation. -
Logic in UUPS contract can be added to
_authorizeUpgrade
for new implementation. -
If
Ownable
library is used in initialize of upgradeable then upgrade to new implementation cannot be carried out with script.
- Foundry install on windows using git...guide YT smart contract programmer...’foundryup’ inside git install foundry on windows.
- forge init is used to start a new project...forge build or compile for compiling contract.
- In foundry contract are deployed locally on anvil. Anvil is local blockchain like ganache.
- Forge create take contract name not contract file. Anvil needs to be run before contract deployment.
test
is the main prefix to run test on any function and cannot run without it.- forge create contractName –private-key is command-line
CL
to deploy contract in foundry. - Forge create contractName –interactive is used to insert pvt key without showing.
- forge create contractName --rpc-url $test_rpc_url --private-key $test_pvt_key --constructor-args constructor arguments is the method to deploy contract with constructor .
forge script deployRaffle --rpc-url $test_rpc_url --broadcast --private-key $test_pvt_key --etherscan-api-key $eth_api –verify
is cli for deploying and verifying contract through deployment.- Contract also can be deployed using script by writing script in script folder.
- The main function in script is
run
which have the code for deployment. The contract file is imported and then the contract is deployed and saved as contract type variable which is returned. - To deploy contract onchain
forge script script/contract --rpc-url –broadcast –private-key
is the CL using script. - Create method to deploy contract onchain is linked to forge Contractname --rpc-url –broadcast –private-key` `` option.
- Adding variables in .env file shouldn’t have gap b/w var name and values like
varName=0x512
source .env
is means to add .env into source file.- To call value from .env file they should be with
$
sign without any gap in between. - Broadcast is only used with script and not with create method. It requires pvtkey for wallet
- –rpc-url is means to deploy on chain..in script deployment does not need pvt key with rpc but with create it need –private-key as well.
- Forge clean remove the
out
folder. Cast to-base
is method to convert values.- Cast is also used to interact with a deployed contract using CL `cast send contractAddress ‘’functionName(uint param)’’ args123
- Cast call can be made to check on result for a write function as a static call.
cast call contractAddress "func(argumentuint256)" --rpc-url
is the syntax to use for making call on-chain.- ‘vm’ cheat code ignore the next line if also the ‘vm’ is present.
- Vm.prank(caller) method is used to initiate txn with specific addres instead of msg.sender or address (this).
- Vm.deal(caller, 1 ether) is used to fund the contract with required amount.
- hoax(caller, 1 ether) is combination of both prank and deal.
- If an amount is to be sent for a payable contract it is called like a low level call. i.e.; contract.function{value: amount}();
- –f is short form of –fork-url and doesn’t work with local host...only with testnet or mainnet.
- Calling elements of array in test are done by caching them in array and calling each element separately (address[] memory fuser = (funded.getFunders());assertEq(fuser[0], caller));) or through loop.
- Testing needs to be developed around 3 A’s i.e. Arrange, Act and Assert.
- Arrange is setting all parameters and initial state of all variables...Act is calling the contract or method in contract...assert is validating state changes taken place in Act.
- Branching tree Technique or BTT is method for organising unit testing based on state changing taken place at each step.
- BTT starts with default behaviour of contract and then modifier are created and added before each state changing.
- Vm.warp() is the cheat code to create a time difference between two txns. By default it is 1 i.e., vm.warp(block.timestamp) is 1.
- Receive and fallback is must for contract receiving native token...payable function does not provide contract with ability to receive ether.
- Contract abi can be generated through cmd “forge inspect ContractName abi”. Internal/pvt functions abi are not generated.
- Contract abi can be convert back to interface using cmd “cast interface src/contract.sol” .
- Foundry default time is 1 if using
block.timestamp
. can be changes usingvm.warp(129)
returns current time ==129. - Value in scientific notation can be returned in console by using
%e
syntax, e.g.;console.log(‘This is one ether %e:’, 1 ether )
. - Vm.startbroadcast is used to deploy a contract within a function.
- Vm.startbroadcast makes foundry default sender as owner which can be changed accordingly i.e.,
Vm.startbroadcast(user)
. - Passing values in variables from a function or struct from a inherited contract must have parenthese”()” else it allows only 1 parameter to be passed.
- assertEq() only checks for specific data types which requires casting to the needed type first.
- Vm.expectRevert(‘custom error string’) custom error message should be passed as same define in the code.
- Vm.expectRevert(contractType.customError.selector) is used when custom error is used for revert in contract having no parameters.
- Vm.expectRevert(abi.encodewithSelector(contractType.customError.selector, param1, param2, ...) is used when custom error have parameters in it .
- expectRevert with custom error and arguments only allows 3 params.
- Custom error shows message for the reason a txn fails, while empty
revert()
showsEvmError: Revert
. - Events are required to be separately defined in test contract.
vm.expectEmit(true, false, false, false, address(emitter))
takes max of 5 args...1st 4 are bool, last one is emitting contract address. 1st argument must be true to pass the test or pass empty parentheses for default check.- If no args are passed in
vm.expectEmit()
first topic is true by default. - If only address is passed in last parameter
vm.expectEmit(address(emitter))
it checks the emitter of the event which is the contract. - Events parameter if is an address it should be indexed, as only topics are checked.
- Events are stored using
vm.recordLogs()
syntax in foundry. After this all txn are made which emits event and are stored. Vm.Log[] memory event_Entries = vm.getRecordedLogs()
is expression which is used for accessing all events.- Events emitted are stored in 1st index of topic as 0th index stored the whole event expression.
- Events are stored in bytes32 type and all events must be casted to type bytes32 before validating any event emitted.
- Converting address into bytes32 require first them to be casted to 20 bytes which is done by uint160 then into uint256 to be casted into bytes32
bytes32(uint256(uint160(funder)))
. forge coverage --report debug
is syntax to get coverage report for each line in contract.- Continue skips the current iteration while
break
stop the loop at current iteration. - There are different method of making address in foundry.
- The true return of ERC20 contract approve can cause
expectRevert
call to fail as it expect return value to be false. - Address are passed with datatype pointer in deployment script and not with casting. ContractType pointer needs to be passed with pointer and not with casting into Address type.
- Address of pointer to a contract type for a contract can be retrieve using
.address
syntax, e.g;contract.ContractTypePointer.address
. - Caller can be checked of a function by returning
msg.sender
in contract function and caching in testing function. gasleft()
is method for getting gas price for txn. The formula isuint256 gasUsed = (Start_Gas - End_Gas) * tx.gasprice;
wheregasleft()
is placed at start and end of txn.- Gas price in eth can be calculated depend on price of Gwei, i.e., formula
(190000(gas consumed) * 10 Gwei(depends on network activity) *1e9) / 1e18 = 0.0019 ETH(gas price)
. - If low level call return value is not check reverting txn will pass.
- Foundry devops tool only get contracts that are deployed on chain and are in
broadcast
folder. - Contract should be deployed with
vm.startBroadcast()
to have them inbroadcast
folder. - Persmission should be given with
fs_permissions = [{ access = "read", path = "./broadcast" }]
for correct functioning of devops. vm.readFile(relative path)
is foundry cheatcode use to access data of other files.- vm.readFile("relative path") returns data in string form.
-
Smart contract bytescode can be generated in remix compile tab on ‘Compilations Details` tab under bytecode object.
-
Solidity/EVM version and optimization settings have direct impact on contract bytecode.
-
Activating debugger in remix gives details in instructions section.
-
Every instruction have an opcode to execute. EVM identifies specifics opcodes with particular action.
-
EVM opcode reference https://www.evm.codes/
-
Codes executes from top down order with changing location around with
JUMP
opcode. -
JUMP
opcode takes the most top value of stack and move to target location. -
The target location of
JUMP
opcode must containJUMPDEST
opcode. -
JUMPDEST
opcode mark the target location, valid jump target. -
JUMPI
opcode only work if 2nd position in stack does not have 0 value, else it fails. -
STOP
opcode completely halts contract executions with no return value whileRETURN
also halt but with return data from EVM memory. -
JUMP
opcode make a jump with value that is pushed on stack before it, from its location to the target locationJUMPDEST
. -
Contract creation in evm have
JUMPI
opcode with following aRevert
andJUMPDEST
. -
Following instruction will lead to
Revert
and if not, it will jump to targetJUMPDEST
location. -
The value taken to
JUMPDEST
location is value ofPUSH2
opcode before theJUMPI
opcode. -
The ``Return
and
STOP``` opcode points towards end of creation code from the very first instruction. -
Creation code is not part of contract as it is executed only once.
-
Creation code sets contract initial stage and returning copy of runtime code.
-
Contract constructor is part of creation code and not runtime code but return the runtime code copy as it is the actual code of the contract.
-
PUSH1
opcode push 1 byte data on top of stack. -
Mstore
opcode grabs last 2 bytes from stack and store one of them (usually first one into 2nd one) in memory. -
PUSH
instructions are composed of 2 or more bytes if aPUSH
opcode is given it will skip next number on instruction depend on its number in opcode. -
The free memory pointer is opcode that is present till
MStore
opcode. -
After
MSTORE
, ifPUSH1
opcode is present the constructor is marked payable. -
Payable constructor after
PUSH1
opcode directly proceed to return which is end of creation code. -
After
MSTORE
, ifCALLDATA
opcode is present the constructor is non payable. -
Non-payable constructor have check starting from
CALLDATA
opcode and ends atREVERT
opcode. -
CALLDATA
opcode in present only when constructor is non-payable which ensures if value sent != 0 it proceed to revert else it jumps. -
All instruction in between
CALLDATA
andREVERT
opcode are usuallyDUP1, ISZERO, PUSH2 and JUMPI
opcode. -
DUP1
duplicates 1st element on stack,ISZERO
pushes 1 byte to stack if is 0 at top most andPUSH2
can push 2 bytes to stack. -
JUMPI
Opcode only works if no value is involved and will jump to next instruction i.e.JUMPDEST
after the revert opcode. -
After jump is complete at
JUMPDEST
,POP
(which is removing of a value from stack) Opcode indicates constructor presence. -
If a value is passed in constructor it will be read and pushed to stack indicates through a
PUSH1
andMLOAD
opcode. -
DUP1
is a duplicating of value at above instruction afterPUSH1
. -
After
DUP1
if a value is passed to constructor, it will havepush1
andpush2
followed byDUP
opcode respectively. -
If no value is passed after
DUP1
it will havepush2
andpush1
respectively. -
Afterwards there will be
CODECOPY
opcode present in both case if value is passed or not to constructor. -
CODECOPY
opcode takes 3 arguments; memory position where result is copied to copy code from(in some case the immediate opcode before), instruction number of the code to copy from and bytes size of code [length] from the instruction. -
When deploying a contract whose constructor contains parameters, the arguments are appended to the end of the code as raw hex data.
-
After
CODECOPY
the next instruction tillMStore
the value is updated at current position from previous value to current offset value if there is a constructor.
https://www.rareskills.io/post/try-catch-solidity
-
Try/catch responds only to external function calls and contract creation error.
-
Response of Try/catch is based on return value and data of low-level calls, when it fails.
-
External call fails on 3 conditions i.e.; called contract (or contract function) reverts, called contract does an illegal operation (like dividing by zero or accessing an out-of-bounds array index) and called contract uses up all the gas.
-
If an empty revert() is present in the calling function it will return no data
0x
. -
If revert() have string message revert(‘revertMessage’) the return data will be abi encoding of the function
Error(string)
. -
Revert error can be empty or takes only string arguments in it.
-
The abi encoding of function error includes function selector of
Error(string)
, offset(location) of string, length of string in bytes and content of the string encoded in hexadecimal. -
If a function have custom error
'emptyError()'
without arguments the return data will be first four bytes of the error function selector i.e.0xa97a0bd2
. -
If a function have custom error
errorArgs(address)'
with arguments the return data will be first four bytes of the error function selector i.e.0xad682f1b
and next 32 bytes will be address of the caller. -
If a function have custom error with arguments
errorArgs(bool)'
return data will be first four bytes of function selector of custom error and next 32 bytes will be value of bool. -
If a function have custom error with arguments
errorArgs(string)'
the return data will same as therevert error with string
but 1st 4 bytes will be function selector of custom error. -
If function reverts with require statement without error message it will return
0x
data similar to empty revert. -
When function reverts with require statement the return data will be similar to revert with string message, i.e.; abi encoding of error function.
-
Custom error with require statement only work for solidity version 0.8.26 or above.
-
If a function have custom error without argument in require statement it will revert with first four bytes of the error function selector.
-
Require statement with custom error
errorArgs(address)
with arguments return data will be first four bytes of the error function selector i.e.0xad682f1b
and next 32 bytes will be address of the caller. -
If a function have custom error with arguments
errorArgs(string)'
i.e., abi.encoding of error, as the return data will be same as therevert error with string
but 1st 4 bytes will be function selector of custom error. -
Return data for assert failure is concatenation of the function selector i.e., first 4 bytes of ‘Panic(uint256)’ and the error code i.e., 1.
-
The return data due to failure of unbounded array access is similar assert failure to based on first 4 bytes of ‘Panic(uint256)’ and the error code i.e., 32. In catch panic revert will be in numeric.
-
The return data due to failure of divide by zero is similar assert failure to based on first 4 bytes of ‘Panic(uint256)’ and the error code i.e., 12.
-
Division by zero in Solidity reverts with an error code of 18 (0x12). Division by zero at the assembly level doesn’t revert, instead it returns 0. That’s because the compiler inserts checks at the Solidity level, which is not done at the assembly level.
-
OOG error in low level call does not returns any data and is similar to empty revert().
-
Similar to revert() in Solidity, revert(0,0) is the equivalent in Inline assembly. It doesn’t return any error data as the starting memory slot is defined to be 0, and it has a data size of 0, which indicates that no data should be returned.
-
revert in assembly takes two parameters: a memory slot and the size of the data in bytes:
revert(startingMemorySlot, totalMemorySize)
. -
We can control what error data gets returned from an assembly revert by storing selector at zero slot and returning it for revert.
-
Try/catch handles exception that occurs during external function calls without reverting back the whole txn. Revert occurs at the called contract.
-
Try/catch first execute code at try level if any error occurs it will be caught in catch block.
-
Catch block first catch Panic error, then string error and in the last bytes error.
-
Panic error block catch error for illegal operations, such as dividing by zero and assert errors as they return panic codes.
-
String error block handles all reverts with a reason string. Revert(string) and require(false, “string”) errors will be caught as those errors return the Error(string) error.
-
Error excluding Panic or Error will be caught in the generic catch block, including custom errors, require statement and revert without a message string.
-
There is no catch block for custom errors, handle it in the generic catch-all block with a manual process i.e., low-level error data corresponds to a specific custom error signature.
-
Empty revert() inside catch blocks are not caught, while are caught in custom error.
-
If error return is of other type than the catch block, it will not be caught.
-
If a function implements an interface or calls another function that returns value but the caller function does not return, this will cause catch block unable to caught the error.
-
Revert() inside try block cause reverting not catching of error.
-
Try/catch syntax will not catch the error of high level call to a function by a contract, if
extcodesize
of the target contract fail; if the address is not a contract. -
Try/catch will fail to catch error if function is expected to return data, it verifies if
returndatasize
is not empty. -
Try/catch syntax will fail to catch error, if revert occur due to malformed or non-existent data.
-
Sstore store value at given storage slot, while sload retrieve value stored at given slot.
- Any file can be uploaded/import using IPFS desktop application.
ipfs://
is used on supported browser for read-only purpose.
# 1st try this
forge i foundry-rs/forge-std --no-commit
# If above cmd fail install lib/forge-std
forge init --force --no-commit
# Install openzeppelin-contracts gitmodules// same for any other dependencies
# all installation will be on latest version if specific version is require use @v4.9.4
forge i OpenZeppelin/openzeppelin-contracts --no-commit
forge i OpenZeppelin/openzeppelin-contracts-upgradeable --no-commit
# Run test
forge t
https://github.com/ComposableSecurity/SCSVS/tree/master https://gist.github.com/Abbasjafri-syed/773bef4cd2d199dc083221127c43684e https://lab.guardianaudits.com/encyclopedia-of-solidity-attack-vectors/block.timestamp-manipulation https://github.com/0xNazgul/Blockchain-Security-Library Test tokens on Sepolia https://blog.sui.io/sui-bridge-live-on-testnet-with-incentives/