EthSecurity – Telegram
I want to do more in web3Security space
If you have a proposal or partnerships ideas you can Dm @EthDev1
Hello mates i decided share daily Ethereum developer Q&A in interviews beside ordinary secuirty Knowledge sharing.from zero to hero

1-What is the difference between private, internal, public, and external functions?

Here are the main differences between private, internal, public and external functions in Solidity:

Private: Can only be called within the currently executing contract, not externally or inherited. Not part of the ABI.

Internal: Can be called internally from current contract or inherited contracts/libraries. Not part of the ABI.

Public: Part of the ABI and contract interface. Can be called externally or internally.

External: Part of the ABI but cannot access contract state. Can only be called externally from other contracts.

In summary:

Private: callable only within current contract
Internal: callable internally or by inheriting contracts
Public: callable internally or externally via ABI
External: callable externally via ABI but not state-changing

The visibility degrees follow this order:

private < internal < public < external

With private being the most restrictive and external the most accessible from outside the contract and inheriting contracts. 2-Approximately, how large can a smart contract be?

There is no hard limit on the size of smart contracts in Ethereum, but there are some practical constraints:

Code size: Contract bytecode (compiled code) is typically limited to around 24KB due to EVM limitations. Larger code requires optimization.

Deployment cost: Deploying large contracts can be prohibitively expensive due to high upfront gas costs of several million gas or more.

Complexity: Very large contracts with many operations slow down node verification times and can impact decentralization.

Updating: Updating logic in deployed contracts is complex/costly for large codebases, favoring smaller focused updates.

Testing: Thoroughly testing contracts with many operations and edge cases becomes intractable at larger sizes.

In general, contracts larger than around 5KB start facing significant constraints. Most real-world contracts are below 1KB.

As a rough guideline:

Up to 5KB: Typical size for production contracts
5-20KB: Possible but requiring careful optimization
20-24KB: Theoretical limit, extremely large
Over 24KB: Not viable, would require optimization techniques like splitting across multiple contracts.

So in summary, while theoretically unbounded - practical constraints of deployment costs, complexity and maintainability favor targeting smaller contract sizes below 5KB whenever possible. @EthSecurity1
👍5🎉1
Under what circumstances could abi.encodePacked create a vulnerability?

A few circumstances where abi.encodePacked could potentially create vulnerabilities:

Length padding attack: If an integer value is encoded that an attacker controls, they could append extra zeros to enforce type conversion to a larger type. This could allow reinterpreting the encoded data malevolently.

Overflow encoding: Encoding a series of values that together exceed the maximum type size (e.g. encoding multiple uint256 values that sum above 2**256) could cause unexpected behavior.(overflows transactions will revert in solidity 0.8.0)

Unexpected types: The packed format doesn't include type identifiers, so reinterpreting the encoded data unexpectedly as a different type than intended could lead to issues.

Semantic collisions: There is a small chance that semantically different contract types may encode to identical binary representations. Care needs to be taken to rely only on defined encoding properties.

Gas estimation: Since packed encoding delegates minimum gas amount based on input, very long or malicious inputs could potentially be crafted to exceed gas estimates.

Inheritance clashes: Ambiguous inheritance trees between encoded contract types could in theory lead to data interpretation conflicts on decoding. What is a storage collision in a proxy contract?
A storage collision in a proxy contract refers to a situation where the storage layout of the proxy contract and the logic contract conflicts, causing unexpected behavior.

To understand this, one must first understand how proxy contracts and logic contracts interact in an upgradeable contract system. An upgradeable contract system in Ethereum consists of two main parts:

Proxy Contract: This contract maintains a consistent address and holds the state variables (storage). It also contains a fallback function that delegates all calls to an address stored in the proxy, which points to the current logic contract.

Logic Contract(s): These contracts contain the business logic of the application. They can be replaced or upgraded, but they do not directly hold any state. They operate on the state stored in the proxy contract.

The way the EVM (Ethereum Virtual Machine) deals with storage layout is that each variable is assigned a slot in the storage space. If you have two contracts (the proxy and the logic contract) that are both using the same storage slots, then a storage collision can occur.

For example, if the logic contract has a variable x in slot 0, and the proxy contract also has a variable in slot 0, when the logic contract tries to access or modify x, it might be accessing or modifying the proxy's variable instead. This can lead to unexpected and potentially harmful behavior.

To avoid such collisions, developers need to be very careful about the storage layout when creating upgradeable contracts. Tools and libraries like OpenZeppelin's upgradeable contract tools can help manage this and prevent storage collisions. @EthSecurity1
👍1
Auditor life cycle @EthSecurity1
😁6
What is the difference between UUPS and the Transparent Upgradeable Proxy pattern?

• Proxy Implementation:
• UUPS uses the minimal proxy contract that delegates all calls to the implementation contract.
• Transparent Proxy has more complex proxy logic to forward calls based on function signatures.
• Upgrade Mechanism:
• UUPS upgrades by calling the upgradeTo() function directly on the proxy.
• Transparent Proxy upgrades by calling the upgradeTo() function on the proxy admin which owns the proxy.
• Storage Layout:
• UUPS uses the same storage layout for the proxy and implementation. No translation is needed.
• Transparent Proxy uses different storage for proxy and implementation which requires storage layout translation.
• External Calls:
• UUPS proxy cannot make external calls except for the delegatecall to the implementation.
• Transparent Proxy can make arbitrary external calls as it has its own logic.
In summary, UUPS has a minimal proxy and direct upgrade mechanism while Transparent Proxy has more complex proxy logic and admin-based upgrade flow. UUPS is simpler while Transparent Proxy is more flexible.
ERC777 tokens introduce some new potential attack vectors that developers should be aware of compared to the more established ERC20 standard:
• Reentrancy - ERC777 has hooks that allow contracts to react to token transfers. This enables reentrancy if the hooked contracts are poorly coded. Proper reentrancy guards need to be implemented.
• Malicious contracts - Since ERC777 tokens can interact with arbitrary contracts via hooks, a malicious contract could try to exploit the token or steal funds when it receives tokens. Extra precaution needs to be taken.
• Denial of service - If not rate limited, malicious contracts could trap tokens forever by refusing to return them in the hooks. This could block token transfers.
• Brute force burn attacks - The burn functionality could potentially be abused to force holders to burn tokens by repeatedly calling it.
• Hook logic complexity - Complex logic in the token transfer hooks increases potential vulnerabilities and gas costs. Hooks should be as simple as possible.
• Infinite hook loops - Chained token contracts could call each other's transfer hooks infinitely unless a counter is implemented.
So in summary, ERC777 provides more flexibility which brings both power and vulnerabilities that developers need to mitigate. Carefully auditing and testing ERC777 behavior is recommended before deployment.
@EthSecurity1
👍1
Why shouldn’t upgradeable contracts use the constructor?

There are a few key reasons why upgradeable contracts should not use the constructor:
1-Constructors can only be called once: If the constructor is used during initial deployment, it cannot be called again when upgrading the contract. This means any initialization logic would only run on the initial deployment and not on future upgrades.
2-State changes cannot be reverted: Any mutable state changes made in the constructor are permanent and cannot be reverted if a future upgrade needs to rollback changes.
3-Constructors are not upgrade-safe: Since the constructor runs only once at initial deployment, it does not support the upgrade workflow where the code is replaced but the contract state is maintained.
4-Initialization logic should be separated: It's considered a best practice to separate initialization logic from perpetual/state-changing logic. Initialization only needs to run once, while other logic may need to rerun on upgrades.
Instead of using the constructor, upgradeable proxies recommend using an "initialize" function that can be called again after upgrades to re-initialize any needed storage variables, mappings, etc. This keeps state changes reconfigurable and avoids issues with only running constructor code once.
So in summary - constructors are not compatible with how upgradeable proxy contracts work and any logic meant to rerun on upgrades should live outside the constructor for safety and manageability of upgrades.

What is the difference between memory and calldata in a function argument?

The main differences between memory and calldata in Solidity function arguments are:
• Memory: Data is stored in memory which exists only for the duration of the function call. Memory is EXPENSIVE to use since it gets cleared after the function finishes.
• Calldata: Points to argument data provided to the function call and is read-only. Calldata contains the actual call data coming from the message call and is onlymodifiable by the called contract. It is CHEAPER than memory.
In summary:
• Memory is mutable and stores a copy of data, while calldata is immutable and direct pointer to external input data.
• Memory gets cleared after function finishes, while calldata remains unchanged and points to original call data even after function finishes.
• Using memory is more expensive than calldata due to allocation and freeing on the stack.
• Calldata should be used for large immutable data inputs to save on gas costs compared to memory which must allocate space.
• Memory is suitable when the data needs to be modified by the function since calldata is read-only.
So in general, use calldata for large immutable input data and memory for any data that needs modification within the function scope.
@EthSecurity1
EthSecurity
Breaking down the Top 50 DeFi hacks 2016-2022 Reports of fake crypto job posting used to spread wallet stealer malware. Magnate Finance disappears with over $6 million in apparent 'rug pull'. Sort of professionals creating a web3sec community.Check out…
1. ZK Sync Audit reports : https://github.com/nullity00/zk-security-reviews/tree/main/ZKsync
2. Circuits : https://github.com/matter-labs/era-zkevm_circuits/tree/main/src
3. Boojum, the proving stack for circuits : https://github.com/matter-labs/era-boojum/tree/main
4. Verifier for circuits : https://github.com/matter-labs/era-boojum-validator-cli
5. Common ZK Bugs : https://github.com/0xPARC/zk-bug-tracker
6. Contracts : https://github.com/matter-labs/era-contracts

My 2 cents : Play on your strengths, try to breakdown the ZKEVM.

For any questions, reach out to
- Porter Adams, Security @ ZKSync (https://twitter.com/portport255)
- Vlad Bochok, Security @ ZKSync (https://twitter.com/vladbochok1)

Also, Brandon Ghomes has come forward to help https://twitter.com/brandonhgomes/status/1706837021702889603 (Brandon contributed to Plonky2 code, some of which is used by Boojum)

If you are unable to reach any of the above people, DM me.
Good luck bug hunting !

From DefiHackLabs’s Discord
@EthSecurity1
👍4
How large a uint can be packed with an address in one slot?

• Solidity reserves 256 bits (32 bytes) of storage for each storage slot.
• An address type takes up 160 bits (20 bytes).
• This leaves 96 bits (12 bytes) remaining in the slot.
• The largest integer type that can fit in 96 bits is uint96.
• Therefore, the largest uint that can be packed together with an address in one slot is uint96.

Which operations give a partial refund of gas?

• SSTORE - When a storage slot is set from non-zero to zero value, 15000 gas is refunded. This refunds about half the cost of an SSTORE operation.
• SELFDESTRUCT - When a contract self-destructs, 24000 gas is refunded to the caller. This is roughly one third of the cost of SELFDESTRUCT.
• CALL - If a CALL fails due to insufficient gas, all gas sent along with the call is refunded except the 2300 gas stipend.
• SUICIDE - Deprecated version of SELFDESTRUCT. Has the same 24000 gas refund when executed.
• CREATE - When CREATE fails due to insufficient gas, 32000 gas is refunded back to the creating contract.
• CREATE2 - Similarly returns 32000 gas when creation fails due to out-of-gas.
@EthSecurity1
👍41
What is an ERC20 approval frontrunning attack?

An ERC20 approval frontrunning attack exploits how the ERC20 token standard handles approvals for token transfers.

Here's how it works:

The ERC20 standard uses an "approve" function to allow third parties (like exchanges) to transfer tokens on a user's behalf, up to a set allowance amount.

A malicious actor monitors the blockchain for new approve transactions, before they are mined.

Once they see an approve transaction, they quickly submit a "transferFrom" transaction to move the approved tokens to their own wallet, before the original approve transaction is mined.

When the approve transaction is finally mined, it approves the exchange's transfer. But the tokens have already been stolen by the frontrunner via transferFrom.

The exchange's subsequent transfer then fails, as the allowance has been emptied by the malicious frontrunner.

So in summary, it's an attack that exploits the multistep nature of ERC20 approvals to frontrun legitimate transfers by stealing approved tokens before the approval transaction confirms. It undermines the trust in third-party token transfers on ERC20 networks.

Developers have proposed some mitigations like using meta transactions instead of approvals, to prevent this kind of frontrunning risk.
What is an inflation attack in ERC4626?

An inflation attack in the ERC4626 vault standard refers to a vulnerability that allows bad actors to arbitrarily inflate the total supply of a vault's deposits.

Here's how it works:

ERC4626 vaults hold deposited assets and issue vault shares representing claims on those assets.

When assets are deposited, the vault mints new shares proportional to the deposit amount.

Conversely, when shares are burned, the corresponding assets are withdrawn.

The inflation attack exploits a lack of validation on deposit amounts.

A malicious actor deposits a very large amount of an asset, much more than they actually provide.

This mints a huge number of new shares, inflating the total supply.

They then immediately redeem a small subset of the shares, withdrawing real assets while leaving inflated shares outstanding.

This effectively steals value from existing share holders by diluting the claims on underlying assets.

The key issue is it allows deposits and minting of shares without properly validating the deposited asset amounts. This has since been addressed by new versions requiring approvals.

But it demonstrated a major risk around arbitrary inflation in vault designs if validation is not implemented carefully. @EthSecurity1
4👍2
Why does the compiler insert the INVALID op code into Solidity contracts?

The Solidity compiler inserts INVALID opcodes into compiled contracts to act as placeholders for code that is not yet implemented or fully defined. Here are a few key reasons:

Futureproofing: It allows contracts to be compiled even if new EVM opcodes or Solidity features are proposed but not yet implemented.

Avoiding bugs: Executing undefined opcode behavior could result in subtle bugs. INVALID immediately reverts to a known state.

Clear errors: Instead of mysterious runtime failures, developers see a clear compilation error where the INVALID is located.

Standardization: The Ethereum foundation works to remove INVALIDs over time as features are finalized in hardforks.

Safety net: If an unimplemented feature is accidentally executed, it fails cleanly rather than producing unknown effects.

Placeholder: Assigns bytecode even for incomplete specifications, allowing proposed features to be included early in code.

So in summary, by inserting INVALID, the compiler produces deterministic, defined behavior for all code paths today while preparing contracts to seamlessly integrate standardized features in the future without code changes. It helps avoid unknown effects from undefined opcodes. What is the difference between how a custom error and a require with error string is encoded at the EVM level? The main differences in how a custom error and require with error string are encoded at the EVM level are:

Custom error:

Uses the 0xfe opcode to return a custom error with a specified error code and error message string.
Error code and string are concatenated together and pushed on the stack.
This error data remains attached to the transaction and visible on-chain.

Require with error string:

Uses the 0xf3 opcode for a require call that succeeds or reverts.
If it reverts, it will push the error string to return data, but not encode it on-chain with the transaction.
The return data and error string are discarded after the revert.

In summary:

Custom error attaches error code + message to transaction permanently
Require only includes error message in return data, not on-chain transaction data
Custom error allows encoding more semantic error information on-chain
Require only returns error locally on revert, without on-chain encoding

So a custom error allows more explicit error types and data to be encoded with a transaction even after it reverts, while require error string is only returned locally during the revert. @EthSecurity1
🔥4
One common vulnerability with the ecrecover function in Solidity is malleability of signatures.

ecrecover is used to recover the address that signed a message from an elliptic curve signature. However, signatures in crypto systems like Ethereum are malleable.

This means it is possible to modify a signature in a way that remains valid for the same message and public key, but produces a different signature value.

A common attack involves an attacker modifying a valid signature before it is verified via ecrecover. This could allow:

Impersonating the signer by recovering their address from a maliciously modified signature.

Hiding the real signer by modifying their valid signature into one that recovers to a different address.

Tricking contracts rely on ecrecover for authentication or permissions.

To prevent this, signatures should be verified correctly against the original message and public key, rather than relying on ecrecover alone. Additionally, signature metadata like timestamp/nonce can be included in the digest to make them non-malleable. @EthSecurity1