<!-- --- type: slide --- --> # Smart Contract Security --- # Assets in Smart Contract - [DeFi Market Cap](https://defillama.com/) ![](https://hackmd.io/_uploads/HkbzDAM02.png) - **Manta Pacific** |Project|Assets| |---|---| |zkHoldem|Game Token| |zkSBT|NFT| |perpetual|WETH/USD...| |...|...| --- # vulnerabilities - [Attacker : looking to profit by exploiting vulnerabilities](https://rekt.news/) <div style="text-align:center;"> <img src="https://hackmd.io/_uploads/Skez50MRn.png" alt="rekt leaderboard" width="300" height="500"> </div> --- <!-- # Pre-requisites - fundamentals of smart contract development - Adavaced Topics : - storage slot - evm execution context - call/delegate call - .... --- --> # Challenges : practice to learn security - [Openzepplin Ethernaut](https://ethernaut.openzeppelin.com/) - Web3/Solidity-based wargame where each level is a smart contract that needs to be 'hacked'. - help, player, contract <div style="text-align:center;"> <img src="https://hackmd.io/_uploads/Syn-MIA32.png" alt="ethernaut" width="500" height="300"> </div> - [BlockSec CTF](https://github.com/blockthreat/blocksec-ctfs) - Curated list of blockchain security wargames, challenges, and competitions and solution writeups - [manta-network/security](https://github.com/Manta-Network/security/tree/main/packages/contracts/contracts/security) --- # Common vulnerabilities - Integer Overflow and Underflow - No Private in Contract - Randomnes - Fallback Function - Proxy Pattern - Re-Entrancy --- ## Integer Overflow and Underflow |Problem|Analysis|Best Practice| |---|---|---| |[Ethernaut-05-Token](https://ethernaut.openzeppelin.com/level/0x478f3476358Eb166Cb7adE4666d04fbdDB56C407)|No built-in Compiler overflow Check for Solidity < 0.8|1.openzepplin.safeMath <br> 2. solidity 0.8 compiler check | ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.6.0; contract c { function add(uint8 x) public returns(uint8) { return x + 1; } } ``` ```typescript= // call add const res = await c.add(255) expect(res).eq(0) ``` --- ## No Privacy in Contract | Problem|Analysis|Best Practice| |---|---|---| |[Ethernaut-08-Vault](https://ethernaut.openzeppelin.com/level/0xB7257D8Ba61BD1b3Fb7249DCd9330a023a5F3670)|Everything you use in a smart contract is publicly visible, even local variables and state variables marked private.|1. do not use on-chain data as 'key' | ```solidity= // solidity contract contract c { bool public locked; bytes32 private password; function open(uint key) { if (key == password) { locked = false; } } } ``` ```typescript= // get locked const locked = await c.locked() // get password const slotIndex = 1 const password = await provider.getStorageAt(c.address, slotIndex) await c.open(password) ``` --- ## Randomnes |Problem|Analysis|Best Practice| |---|---|---| |[Ethernaut-03-CoinFlip](https://ethernaut.openzeppelin.com/level/0xA62fE5344FE62AdC1F356447B669E9E6D10abaaF)|Using random numbers in smart contracts is quite tricky if you do not want miners to be able to cheat.|1. do not use block nubmer/hash/timestamp as random entropy <br> 2. [Chainlink VRF : Verifiable source of randomness](https://chain.link/vrf) <br> 3. [Verifiable Delay Functions (VDFs)](https://blog.trailofbits.com/2018/10/12/introduction-to-verifiable-delay-functions-vdfs/) | ```solidity= // Contract function flip(bool _guess) public returns (bool) { uint256 blockValue = uint256(blockhash(block.number - 1)); uint256 coinFlip = blockValue / FACTOR; bool side = coinFlip == 1 ? true : false; if (side == _guess) { return true; } else { return false; } } ``` ```solidity= // Hacker contract HackCoinFlip { CoinFlip cf; constructor(address _cf) { cf = CoinFlip(_cf); } function getResult() public view returns (bool) { uint256 blockValue = uint256(blockhash(block.number - 1)); uint256 coinFlip = blockValue / FACTOR; return coinFlip == 1 ? true : false; } function flip() public returns (bool) { return cf.flip(getResult()); } } ``` --- ## [Fallback Function](https://docs.soliditylang.org/en/v0.8.15/contracts.html#fallback-function) |Problem|Analysis|Best Practice| |---|---|---| |[Ethernaut-10-Reentracy](https://ethernaut.openzeppelin.com/level/0x2a24869323C0B13Dff24E196Ba072dC790D52479)| 1. executed if none of the other functions match the given function name <br> 2. or .send()/.transfer() without a receive ether function.| recommended to define a receive Ether function as well, to distinguish Ether transfers from interface confusions | ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.2 <0.9.0; contract Test { uint x; // This function is called for all messages sent to // this contract (there is no other function). // Sending Ether to this contract will cause an exception, // because the fallback function does not have the `payable` // modifier. fallback() external { x = 1; } } ``` --- ## Fallback User Case : Re-Entrancy |Problem|Analysis|Best Practice| |---|---|---| |[Ethernaut-10-Reentracy](https://ethernaut.openzeppelin.com/level/0x2a24869323C0B13Dff24E196Ba072dC790D52479)| | [check-effects-interactions pattern](https://solidity.readthedocs.io/en/v0.5.8/security-considerations.html#use-the-checks-effects-interactions-pattern) : always first do checks and then state changes and only then external contracts calls or transfers | ```solidity= // SPDX-License-Identifier: MIT pragma solidity ^0.6.12; import 'openzeppelin-contracts-06/math/SafeMath.sol'; contract Reentrance { using SafeMath for uint256; mapping(address => uint) public balances; function donate(address _to) public payable { balances[_to] = balances[_to].add(msg.value); } function balanceOf(address _who) public view returns (uint balance) { return balances[_who]; } function withdraw(uint _amount) public { if(balances[msg.sender] >= _amount) { // check balances[msg.sender] -= _amount; // update (bool result,) = msg.sender.call{value:_amount}(""); // interaction if(result) { _amount; } } } receive() external payable {} } ``` --- # [Fallback User Case : Proxy Pattern]((https://blog.openzeppelin.com/proxy-patterns)) ![](https://hackmd.io/_uploads/HkNzT-NCh.png) <!-- [Puzzle-Ethernaut-PullzeWallet]([/O21qA4vuRdexEwGOQObtbA](https://ethernaut.openzeppelin.com/level/0x725595BA16E76ED1F6cC1e1b65A88365cC494824)) [Puzzle-Ethernaut-MotorBike](https://ethernaut.openzeppelin.com/level/0x3A78EE8462BD2e31133de2B8f1f9CBD973D6eDd6) --> --- # Contract Upgrades - [upgradeable zksbt on manta pacific](https://pacific-explorer.manta.network/address/0xFEe052821D8eFbE20a396695533Fb5B46765edA5) - more details in ["Upgradable contracts: UUPS and Multi-faucet proxy" Course](https://www.notion.so/mantanetwork/Upgradable-contracts-UUPS-and-Multi-faucet-proxy-27732239d91d495f90fd5bebefaca565) # Emergency stops ```solidity= contract EmergencyStop { bool isStopped = false; modifier stoppedInEmergency { require(!isStopped); _; } modifier onlyAuthorized { // Check for authorization of msg.sender here _; } function stopContract() public onlyAuthorized { isStopped = true; } function deposit() public payable stoppedInEmergency { // Deposit logic happening here } } ``` # Using Audit/Battle test library (Openzepplin) - [SafeMath](https://docs.openzeppelin.com/contracts/4.x/api/utils#SafeMath) - [access control](https://docs.openzeppelin.com/contracts/4.x/access-control) - Ownable pattern - role-based control - Using multi-signature wallets - [ReentrancyGuard](https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard) - ERC20, ERC721, Upgradable Proxy... # 3rd-party review : Audit & Bug bounties <!-- ## mind note ![](https://hackmd.io/_uploads/B1jdwZon2.png) --> --- ## Advanced Topic - Honey Pot - [Flashloan](https://docs.aave.com/developers/guides/flash-loans) - [Frontrun/Sandwich/Mev](https://eigenphi.io/mev/ethereum/sandwich) --- # Reference - [Solidity Security Considerations](https://docs.soliditylang.org/en/v0.8.15/security-considerations.html#security-considerations) - [Consensys GitHub repo](https://docs.soliditylang.org/en/v0.8.15/security-considerations.html#security-considerations:~:text=the%20Consensys%20GitHub%20repo) - [Ethereum Foundation EVM](https://ethereum.org/en/developers/docs/evm/) - [Ethereum Foundation Security Guide](https://ethereum.org/en/developers/docs/smart-contracts/security/) - [Master Ethereum : Gavin Wood](https://www.amazon.com/Mastering-Ethereum-Building-Smart-Contracts/dp/1491971940) - [calyptus_web3](https://twitter.com/calyptus_web3) <!-- ## Overview Goal/Why smart contracts hold Money curve, ... USD ? Dune Boards ? TVL ? open source, public execution. - safe project : * perpetual/zksbt/zkholdem - make money : bug bounty. * number of --> <!-- ___ ## Compiler Bugs - even if your smart contract code is bug-free, the compiler or the platform itself might have a bug. - curve - [list of known compiler bugs](https://docs.soliditylang.org/en/v0.8.15/bugs.html#known-bugs) --> <!-- --- ## EVM Context && Msg.sender [delegate call](https://docs.soliditylang.org/en/v0.8.15/introduction-to-smart-contracts.html?highlight=delegatecall#delegatecall-callcode-and-libraries) - message call apart from the fact that the code at the target address is executed in the context - dynamically load code from a different address at runtime (proxy paradigm) - [Puzzle-Ethernaut-06](https://ethernaut.openzeppelin.com/level/0x73379d8B82Fda494ee59555f333DF7D44483fD58) --- <!-- solidity special functions --> <!-- ## [Receive Ether Function](https://docs.soliditylang.org/en/v0.8.15/contracts.html#receive-ether-function) |Problem|Analysis|Best Practice| |---|---|---| |[1. Ethernaut-02-Fallback](https://ethernaut.openzeppelin.com/level/0x3c34A342b2aF5e885FcaA3800dB5B205fEfa3ffB)<br> [2. Ethernaut-09-King](https://ethernaut.openzeppelin.com/level/0x3049C00639E6dfC269ED1451764a046f7aE500c6)|executed on plain Ether transfers (e.g. via .send() or .transfer())| | --> <!-- ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.6.0 <0.9.0; // This contract keeps all Ether sent to it with no way // to get it back. contract Sink { event Received(address, uint); receive() external payable { emit Received(msg.sender, msg.value); } } ``` -->