iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
Modern Web

web3 短篇集系列 第 29

Solidity 初學者避坑指南

  • 分享至 

  • xImage
  •  

本文摘要自 20 Common Solidity Beginner Mistakes

  • 2024/10/12 Solidity v0.8.26 (隨著科技進步,有些坑會被填起來,有新的坑會出現。)

slither

slither 可以簡單幫你分析合約的安全漏洞: https://github.com/crytic/slither
(公司產品建議找專業 Audit 團隊審核)

Install slither-analyzer:

python3 -m pip install slither-analyzer

Usage:

slither src/Counter.sol

坑坑相連到天邊

  1. 請「先乘後除」:solidity 沒有浮點數,除法會無條件捨去,除完小於 1 就是 0。
    • 錯誤:interest = principal / 3_333 * 10_000
    • 正確:interest = principal * 10_000 / 3_333
  2. check-effects-interaction: 參考 day7 - Reentrancy
  3. 轉帳時不要用 transfersend,用 call
    • transfer 會對接收者可能執行的邏輯進行 gas 限制,為了避免 reentrancy attack,但這可能也會導致某些正當邏輯無法被執行。
  4. 不要使用 tx.origin,用 msg.sender
    • wallet -> malicious intermediate contract -> final contract: tx.origin 會指向 wallet,導致惡意人士能夠使用中介合約來互動。
  5. 請使用 using SafeERC20 for IERC20 來避開不同 ERC20 代幣實作的錯誤回傳。
  6. Solidity v0.8.0 以上開始內建 overflow 檢查,不必使用 SafeMath。
  7. 記得設計權限管理 (access control)。
  8. 迴圈消耗 gas,請使用 "pull-over-push",參考 day6 - Pull over Push pattern
  9. Sanity checks: 檢查參數值範圍的合理性。
    • ex. 不能提領超過其 balance 的金額。
    • ex. 不能提領沒有存入的資產。
    • ex. setProtocolFee: 對於 owner 可設定的費用設置一個合理的上限。
  10. Missing code: ex. 有檢查某人能 mint 的數量,卻沒減去它已經 mint 的數量,導致可以反覆呼叫 mint。
  11. 請鎖定版號
    • pragma solidity ^0.8.0 是給 library 用的。
    • pragma solidity 0.8.26 application 請指定特定版本部署。
  12. 遵循官方 Style Guild
    • constructor 是第一個函式,接著是 external, public, internal, pure functions。
    • within each group:
      • payable functions go first
      • followed by the non-payable non-view functions
      • and the view function go last
  13. 記得觸發事件和 indexed
    • 只要有改變 storage 或轉入轉出 ether,都要記得觸發事件。
    • 事件的參數若是 address 記得加 indexed。
    • 延伸:Solidity Events
  14. 寫單元測試,延伸閱讀 Foundry Unit Tests
  15. 注意捨入(Rounding):Solidity 不支援浮點數,ex. 100/3 得 33 儘管正確答案是 33.3333。
    • 黃金法則:讓 protocol 賺讓 user 虧
    • 計算 protocol pays: 100/3 = 33。
    • 計算 the user pays: 100/3+1 = 34。
    • 延伸:fixed-point math
  16. 執行 formatter 讓別人好讀,forge fmtsolfmt
  17. Openzeppelin 的 _msgSender() 僅用於 Meta Transactions 的情境,不然的話用 msg.sender 就好
  18. API keys 和 private keys 記得放 .env,且 .env 要加入 .gitignore,才不會上傳到 Github。
  19. 注意簽署交易與執行交易之間的延遲,合約要使用者付錢時應設計最高願付價格作為參數。
    • ex. 買家簽署交易用代幣換 NFT,賣家 frontrun 更動價格。合約應設計買家最高願付價格作為交換函式的參數。
    • ex. NFT 購買函式,每次購買會加價 5%,此時若 10 個人看到某價格並同時送交易,會有九個人花比預期多的錢買下。用戶要限制交易最高可轉出的額度。
    • ex. 注意交易函式簽署後,owner 是否可能 frontrun 更換 token 地址。
  20. 注意使用者可能對同一函式呼叫多次
    • ex. deposit 內寫 balance[msg.sender] = msg.value; 會複寫每次投入合約的錢,要用 balance[msg.sender] += msg.value

上一篇
案例研究:Create2 Vickrey Auction
下一篇
完賽心得
系列文
web3 短篇集30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言