Complete Technical Manual for Security & Solutions Architects
This comprehensive manual provides deep technical knowledge on:
// Signature Verification
function verifySignature(
bytes32 messageHash,
uint8 v, bytes32 r, bytes32 s
) public pure returns (address) {
bytes32 ethSignedHash = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash)
);
return ecrecover(ethSignedHash, v, r, s);
}
Minimize state changes by packing structs, using events instead of storage, and implementing efficient data structures.
| Network | Consensus | TPS | Block Time | Finality |
|---|---|---|---|---|
| Ethereum | Proof of Stake | 15-30 | 12 seconds | 15 minutes |
| Solana | PoH + PoS | 3,000-5,000 | 400ms | 13 seconds |
| Avalanche | Snowman | 4,500 | <2 seconds | Sub-second |
| BNB Chain | PoSA | 100-300 | 3 seconds | 45 seconds |
Examples: Optimism, Arbitrum
// Fraud Proof Mechanism
contract OptimisticRollup {
uint256 constant CHALLENGE_PERIOD = 7 days;
function submitStateRoot(bytes32 newRoot) external {
pendingRoots[newRoot] = block.timestamp;
emit StateRootSubmitted(newRoot);
}
function challengeStateRoot(
bytes32 root,
bytes calldata fraudProof
) external {
require(block.timestamp <= pendingRoots[root] + CHALLENGE_PERIOD);
// Verify fraud proof
if (verifyFraudProof(fraudProof)) {
// Slash sequencer and revert state
slashSequencer(msg.sender);
revertToLastValid(root);
}
}
}
Examples: zkSync, StarkNet, Polygon zkEVM
// ZK Proof Verification
contract ZKRollup {
IVerifier public immutable verifier;
function submitBatch(
uint256[] calldata publicInputs,
bytes calldata proof
) external {
require(
verifier.verifyProof(publicInputs, proof),
"Invalid ZK proof"
);
// Update state root
stateRoot = bytes32(publicInputs[0]);
emit BatchVerified(stateRoot);
}
}
L3s are specialized chains built on top of L2s for specific use cases:
// Lending Pool Core Logic
contract LendingPool {
struct Reserve {
uint128 liquidityRate;
uint128 borrowRate;
uint128 liquidityIndex;
uint40 lastUpdateTimestamp;
address aTokenAddress;
}
mapping(address => Reserve) public reserves;
function deposit(address asset, uint256 amount) external {
Reserve storage reserve = reserves[asset];
// Update reserve state
updateState(reserve);
// Transfer tokens
IERC20(asset).transferFrom(msg.sender, aToken, amount);
// Mint aTokens
IAToken(reserve.aTokenAddress).mint(msg.sender, amount);
emit Deposit(asset, msg.sender, amount);
}
function borrow(
address asset,
uint256 amount,
address onBehalfOf
) external {
Reserve storage reserve = reserves[asset];
// Check collateral
require(
getUserCollateralValue(onBehalfOf) >=
amount * reserve.collateralFactor,
"Insufficient collateral"
);
// Execute borrow
IERC20(asset).transfer(msg.sender, amount);
updateDebt(onBehalfOf, amount);
}
}
| AMM Type | Formula | Best For | Example |
|---|---|---|---|
| Constant Product | x * y = k | General trading | Uniswap V2 |
| Concentrated Liquidity | L = √(x * y) | Capital efficiency | Uniswap V3 |
| StableSwap | χD^(n-1) = ∏x_i | Stablecoins | Curve |
| Weighted Pools | ∏(B_i^W_i) = k | Index funds | Balancer |
// Uniswap V3 Concentrated Liquidity
contract UniswapV3Pool {
struct Position {
uint128 liquidity;
uint256 feeGrowthInside0LastX128;
uint256 feeGrowthInside1LastX128;
uint128 tokensOwed0;
uint128 tokensOwed1;
}
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96
) external returns (int256 amount0, int256 amount1) {
// Lock for reentrancy
require(unlocked, "LOCKED");
unlocked = false;
SwapState memory state = SwapState({
amountSpecifiedRemaining: amountSpecified,
amountCalculated: 0,
sqrtPriceX96: slot0.sqrtPriceX96,
tick: slot0.tick,
liquidity: liquidity
});
// Execute swap through ticks
while (state.amountSpecifiedRemaining != 0) {
// Cross tick if necessary
// Calculate amounts
// Update state
}
unlocked = true;
return (amount0, amount1);
}
}
| Type | Mechanism | Gas Cost | Capital Efficiency | MEV Resistance |
|---|---|---|---|---|
| AMM | Liquidity Pools | ~100k gas | Low-Medium | Low |
| Order Book | Limit Orders | ~50k gas | High | Medium |
| Hybrid | RFQ + AMM | ~150k gas | Very High | High |
| Aggregator | Route Optimization | ~200k gas | Maximum | Medium |
// Universal DEX Router
contract UniversalRouter {
struct Route {
address[] pools;
uint24[] fees;
address[] tokens;
}
function universalSwap(
Route calldata route,
uint256 amountIn,
uint256 amountOutMin
) external returns (uint256 amountOut) {
// MEV Protection
require(tx.gasprice <= maxGasPrice, "Gas too high");
for (uint i = 0; i < route.pools.length; i++) {
if (isUniswapV2(route.pools[i])) {
amountOut = _v2Swap(route.pools[i], amountIn);
} else if (isUniswapV3(route.pools[i])) {
amountOut = _v3Swap(route.pools[i], amountIn, route.fees[i]);
} else if (isCurve(route.pools[i])) {
amountOut = _curveSwap(route.pools[i], amountIn);
}
amountIn = amountOut;
}
require(amountOut >= amountOutMin, "Slippage");
return amountOut;
}
}
// VULNERABLE CODE - DO NOT USE
function withdraw(uint amount) external {
require(balances[msg.sender] >= amount);
// External call BEFORE state update - VULNERABLE!
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount; // State update AFTER
}
// SECURE VERSION
function withdrawSecure(uint amount) external {
require(balances[msg.sender] >= amount);
// Check-Effects-Interactions pattern
balances[msg.sender] -= amount; // Update FIRST
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
// Pre Solidity 0.8.0 - VULNERABLE
uint8 balance = 255;
balance += 1; // Overflows to 0!
// SOLUTION 1: Use SafeMath
using SafeMath for uint256;
balance = balance.add(1);
// SOLUTION 2: Use Solidity >= 0.8.0
// Built-in overflow protection
// Or use unchecked{} when safe
// Commit-Reveal Pattern
mapping(address => bytes32) commits;
function commit(bytes32 hash) external {
commits[msg.sender] = hash;
}
function reveal(uint value, uint nonce) external {
bytes32 hash = keccak256(
abi.encode(value, nonce, msg.sender)
);
require(commits[msg.sender] == hash);
// Process revealed value
}
// Using OpenZeppelin
import "@openzeppelin/contracts/access/AccessControl.sol";
contract SecureContract is AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN");
constructor() {
_setupRole(ADMIN_ROLE, msg.sender);
}
function criticalFunction() external
onlyRole(ADMIN_ROLE) {
// Protected logic
}
}
import "@openzeppelin/contracts/
security/ReentrancyGuard.sol";
contract Safe is ReentrancyGuard {
function withdraw()
external nonReentrant {
// Protected from reentrancy
}
}
import "@openzeppelin/contracts/
security/Pausable.sol";
contract Emergency is Pausable {
function pause() external onlyOwner {
_pause();
}
function critical()
external whenNotPaused {
// Can be paused
}
}
import "@openzeppelin/contracts/
token/ERC20/utils/SafeERC20.sol";
using SafeERC20 for IERC20;
function transfer() external {
token.safeTransfer(to, amount);
// Handles return value checks
}
| Opcode | Gas Cost | Risk Level | Security Concern |
|---|---|---|---|
SELFDESTRUCT |
5000 | CRITICAL | Permanent destruction, lost funds |
DELEGATECALL |
700 | HIGH | Storage collision, proxy vulnerabilities |
CREATE2 |
32000 | MEDIUM | Metamorphic contracts |
ORIGIN |
2 | MEDIUM | Phishing attacks |
// Storage Packing
contract GasOptimized {
// Pack in single slot (32 bytes)
struct User {
uint128 balance; // 16 bytes
uint64 lastUpdate; // 8 bytes
uint32 id; // 4 bytes
bool active; // 1 byte
// Total: 29 bytes < 32 bytes (1 slot)
}
// Use calldata for read-only arrays
function process(uint[] calldata data) external {
// More efficient than memory
}
// Cache storage reads
function efficient() external {
uint256 cached = expensive; // 1 SLOAD
// Use cached multiple times
}
// Use custom errors (cheaper than strings)
error InsufficientBalance(uint256 required, uint256 available);
// Unchecked when overflow impossible
function increment(uint256 x) external pure returns (uint256) {
unchecked {
return x + 1; // Save gas when safe
}
}
}
calldata instead of memory for read-only arraysunchecked blocks when overflow is impossible++i over i++ in loopsSecurity: Multi-sig/Validators
Examples: Ronin, Multichain
Risk: Validator compromise
Security: On-chain verification
Examples: Rainbow, IBC
Risk: Implementation bugs
Security: Fraud proofs
Examples: Nomad, Hop
Risk: Challenge period
| Bridge | Date | Loss | Attack Vector |
|---|---|---|---|
| Ronin | March 2022 | $625M | Private key compromise (5/9) |
| Wormhole | Feb 2022 | $325M | Signature verification bypass |
| Nomad | Aug 2022 | $190M | Root update bug |
| Harmony | June 2022 | $100M | Private key compromise (2/5) |
contract SecureBridge {
mapping(bytes32 => bool) public processedMessages;
mapping(uint256 => bytes32) public chainRoots;
modifier nonReplayable(bytes32 messageHash) {
require(!processedMessages[messageHash], "Replayed");
processedMessages[messageHash] = true;
_;
}
function processBridgeMessage(
BridgeMessage calldata message,
bytes32[] calldata proof
) external nonReplayable(message.hash) {
// Verify message authenticity
require(
message.hash == keccak256(abi.encode(
message.nonce,
message.sender,
message.recipient,
message.amount,
message.srcChain,
message.dstChain
)),
"Invalid hash"
);
// Verify merkle proof
require(
MerkleProof.verify(
proof,
chainRoots[message.srcChain],
message.hash
),
"Invalid proof"
);
// Execute transfer
_mintOrUnlock(message.token, message.recipient, message.amount);
}
}
// EIP-1967 Standard
contract TransparentProxy {
bytes32 constant IMPL_SLOT =
0x360894...2bbc; // EIP-1967
function upgradeTo(address newImpl)
external onlyAdmin {
assembly {
sstore(IMPL_SLOT, newImpl)
}
}
fallback() external payable {
address impl;
assembly {
impl := sload(IMPL_SLOT)
}
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(
gas(), impl, 0,
calldatasize(), 0, 0
)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
}
contract UUPSUpgradeable {
address immutable self = address(this);
modifier onlyProxy() {
require(address(this) != self);
_;
}
function upgradeTo(address newImpl)
external onlyProxy onlyOwner {
_authorizeUpgrade(newImpl);
assembly {
sstore(IMPL_SLOT, newImpl)
}
}
}
contract SecureOracle {
uint256 constant STALENESS = 3600; // 1 hour
uint256 constant MAX_DEVIATION = 500; // 5%
function getSecurePrice(address token)
external view returns (uint256) {
uint256[] memory prices = new uint256[](3);
// Get from multiple oracles
prices[0] = chainlink.latestAnswer();
prices[1] = uniswapTWAP.consult(token);
prices[2] = band.getReferenceData(token);
// Calculate median
uint256 median = getMedian(prices);
// Check for manipulation
for (uint i = 0; i < prices.length; i++) {
uint256 deviation = abs(prices[i] - median) * 10000 / median;
require(deviation <= MAX_DEVIATION, "Price manipulation");
}
return median;
}
}
// Flash Loan Defense Mechanisms
contract FlashLoanProtected {
bool private locked;
uint256 private lastBlock;
modifier noFlashLoan() {
// Block same-block interactions
require(lastBlock != block.number, "Same block");
lastBlock = block.number;
_;
}
modifier nonReentrant() {
require(!locked, "Reentrant");
locked = true;
_;
locked = false;
}
// Use TWAP instead of spot price
function resistantPrice() view returns (uint256) {
uint256 spot = getSpotPrice();
uint256 twap = getTWAPPrice();
// Weight towards TWAP
return (spot * 3 + twap * 7) / 10;
}
}
# Install security tools npm install -g @ethereum/solidity-analyzer pip install slither-analyzer mythril # Run Slither analysis slither contracts/ --print human-summary # Run Mythril analysis myth analyze contracts/MyContract.sol # Foundry fuzzing forge test --fuzz-runs 10000 # Generate coverage report hardhat coverage # Deploy with verification hardhat deploy --network mainnet --verify