Solidity 智能合約 - 工廠模式的搶先交易問題 (Front Running)
之前的文章 Solidity 智能合約 - 工廠模式的重組問題 (Reorg) 說明了重組問題和解決方案,但是並不能防止搶先交易 (Front Running)。本篇文章將說明這個安全問題,以及解決方式。 搶先交易 (Front Running)這是區塊鏈常見的一種獲利手法,也可以說是一種攻擊,監控未確認的交易來預知未來將發生的事情,讓自己的交易搶先執行而獲利。例如看到有人要用大單買入 ETH,就搶先買入後抬高價格賣給他。 問題延續上一篇文章的情境: 使用者 A 用 salt 0xabcd... 建立一個多簽錢包 0x9876...。 使用者 A 轉入 ETH 到 0x9876...。 假設使用者 A 先預測了生成的錢包為 0x9876...,並連續送出第二筆交易。這時候在鏈上,存在這兩筆未確認交易,攻擊者看到後搶先送出他的交易: 攻擊者 C 用 salt 0xabcd... 建立一個多簽錢包 0x9876...。 使用者 A 用 salt 0xabcd... 建立一個多簽錢包 0x9876...。已存在,交易失敗。 使用者 A 轉入 ETH 到 0x9876...。 結果 E ...
Solidity 智能合約 - 工廠模式的重組問題 (Reorg)
之前的文章 Solidity 智能合約 - 工廠模式 (Factory Pattern) 和 Solidity 智能合約 - 地址生成規則說明了工廠模式和地址生成的規則。在了解這些之後我們會發現某些情況可能存在重組的問題,本篇文章將說明這個安全問題,以及解決方式。 重組 (Reorg)我們這裡只簡略的說明這個現象,簡單說就是區塊打包的結果有可能發生變動,造成原本執行交易的結果發生變化 問題在工廠模式中採用 create 的地址生成規則的時候,會和執行順序有關。我們考慮以下的模擬情境: 使用者 A 建立一個多簽錢包 0x1234...。 使用者 A 轉入 ETH 到 0x1234...。 使用者 B 建立一個多簽錢包 0x5678...。 由於發生重組,順序改變了: 使用者 B 建立一個多簽錢包 0x1234...。 使用者 A 建立一個多簽錢包 0x5678...。 使用者 A 轉入 ETH 到 0x1234...。 結果使用者 A 的 ETH 跑到使用者 B 建立的 0x1234... 解決方案等待區塊確認如同中心化交易所入金一樣,等待足夠多的區塊確認後再進行下一步,使用者 ...
Solidity 智能合約 - 地址生成規則
之前的文章 Solidity 智能合約 - 工廠模式 (Factory Pattern) 說明了生成智能合約的方法,這篇文章進一步說明智能合約地址生成的規則,包含了 create 和 create2 的差異。 目前產生合約主要有兩種規則: create create2 create我們可以在智能合約中使用這個指令來建立合約,而上一篇文章提到的 new 寫法其實也是使用 create 指令。另外,EOA 錢包部署合約的時候也適用這個規則。這個規則中,影響地址主要是下面兩個參數: 發送者 (sender) nonce 生成的公式如下: 1keccak256(rlp([sender, nonce]))[12:] 後面的 [12:] 表示生成的 hash 取最後 20 bytes。如果是 EOA 錢包部署,sender 為錢包地址,nonce 為錢包發送交易時的 nonce。如果是智能合約中建立其他合約,sender 則為執行建立合約行為的主合約地址,nonce 則為此合約的第幾次執行生成合約,從 1 開始。 例如我在 hardhat 進行測試的時候,預設錢包是:0xf39Fd6e5 ...
Solidity 智能合約 - 工廠模式 (Factory Pattern)
簡介工廠模式 (Factory Pattern) 是一種程式設計的設計模式 (Design Pattern),用來生成物件的一種方式。在智能合約開發中,有些情況會使用到。例如:Uniswap 的交易對或是生成 Token。只需要輸入一些不同的參數,像是名稱、總發行量之類的設定,就可以就快速部署功能相同的合約。我們可以透過智能合約中撰寫一些程式碼來產生新合約,本篇文章會介紹一些方法。 在智能合約中用來建立合約實例的指令有三種寫法: new create create2 而根據實作的方法主要分為兩種: 部署整份合約 使用 Proxy 部署整份合約先假設我們有一個這樣的合約 12345import "@openzeppelin/contracts/token/ERC20/ERC20.sol";contract NormalToken is ERC20 { constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {}} ...
在 zkSync 驗證 TransparentUpgradeableProxy 合約
說明zkSync 可以使用 hardhat-zksync-verify 工具,來讓合約在瀏覽器上開源,通常可以使用下面指令進行驗證: 1npx hardhat verify --network zkSync 合約地址 例如使用合約地址 0xdD5AE451A75a654146747235FDB515F06A55D018,為一個 TransparentUpgradeableProxy 的合約,嘗試使用下面指令進行驗證: 1npx hardhat verify --network zkSync 0xdD5AE451A75a654146747235FDB515F06A55D018 結果會出現下面錯誤: 123Error in plugin @matterlabs/hardhat-zksync-verify: The number of constructor arguments you provided (0) does not match the number of constructor arguments the contract has been deployed with (3 ...
Solidity - zkSync Paymaster 程式範例
之前文章 zkSync 帳戶抽象 (Account Abstraction) 程式範例說明了 zkSync Era 帳戶抽象的用法,這篇繼續說明另一個 EIP-4337 的擴充功能 - Paymaster。這在 zkSync Era 中也有原生的支持。雖然是帳戶抽象中的擴充功能,實際上並不是只有抽象帳戶才能使用,EOA 帳戶也能使用,是一個獨立的模組。 說明Paymaster 主要的功能是能自訂交易發起人的 Gas 手續費支付方式。以往錢包需要 ETH 才能發送交易,透過 Paymaster 的機制可以解決這問題,可以用各種自訂的方式來代為支付 Gas。例如使用 USDC 等代幣來支付,甚至是免費代為支付。 運作機制是需要先使用智能合約實作 Paymaster,在合約中定義支付的方式,最後在發起的交易 Tx 中指定要使用的 Paymaster。 要實作一個 Paymaster,必須實作的介面如下: 123456789101112131415161718interface IPaymaster { // 主要驗證和支付的邏輯 function validateAndPayF ...
Solidity - zkSync 帳戶抽象 (Account Abstraction) 程式範例
簡介zkSync Era 原生支援帳戶抽象 (Account Abstraction) 的功能,這篇文章會簡單介紹一下帳戶抽象是什麼,主要會說明在 zkSync Era 如何實作相關的程式。 帳戶類型在介紹帳戶抽象之前,要先知道目前以太坊有兩種帳戶 外部擁有帳戶,英文為 EOA(Externally Owned Account),也就是一般有私鑰的錢包地址。 智能合約帳戶。 智能合約常會使用 msg.sender 來取得函式呼叫者,進一步作為在系統中的帳號,作為記帳之類的應用。EOA 的一般錢包可以直接發起交易來使用智能合約,而有時我們會使用另外的智能合約間接使用 dapp,例如多簽合約來管理,而這些智能合約帳戶本身無法自己發起交易,必須還是要有一般錢包來代為發送上鏈。 帳戶抽象 (Account Abstraction)現行的帳戶機制存在一些問題,例如 EOA 帳戶私鑰必須保管好不能遺失,智能合約帳戶本身無法自行發起交易等等。帳戶抽象被提出就是為了解決相關的問題的機制,可以參考完整的文件 EIP-4337 和 EIP-2938。網路上已經有很多關於帳戶抽象的介紹,這邊只簡單說明一 ...
Solidity 智能合約 - EIP-712 類型結構化資料雜湊和簽名
本篇文章說明 EIP-712 的標準,以及如何使用 Solidity 實作 EIP-712 的智能合約簽章驗證。 簡介在之前的文章介紹過一些簽章和檢驗的方式,而實際運用的時候可能會簽署許多資料來使用,例如這個例子: 123456789function permit(address owner, address spender, uint value, uint nonce, uint deadline, uint8 v, bytes32 r, bytes32 s) external { require(deadline >= block.timestamp, "signature expired"); require(!usedNonces[nonce], "used nonce"); bytes32 messageHash = abi.encodePacked(block.chainid, address(this), spender, value, nonce, deadline); bytes32 hash = ke ...
Solidity 智能合約 - 簽名延展性 (Signature Malleability)
之前的文章介紹了 ecrecover 的用法,不過內建的 ecrecover 存在簽名延展性 (Signature Malleability) 的問題。這篇文章將說明這個問題,以及如何解決。 問題拿之前文章的例子 1234567function test() external view returns(address) { bytes32 hash = 0xc1af4b94166cd32fc49b7b926cbb91ee421de2d04450e8ae57857b9b56ac7e53; uint8 v = 0x1b; bytes32 r = 0xe1077fb9321c187d8a43926896abac5455ce6add269e098f855ff059d6b846a3; bytes32 s = 0x56320be5f6d79c4d0e5583d6b9a2e50fae78f1fb5ff0553541e69c66dae2b2f8; return ecrecover(hash , v, r, s);} 上面的結果會得到簽署人為 0xDD980c315dFA ...
Solidity 智能合約 - ecrecover 簽章檢驗
簡介智能合約中的 ecrecover 函式,可以用來驗證錢包的的簽章。檢驗方可以在沒有簽章者私鑰的情況下,確認簽署者的身份。常用來作為鏈下授權,再由第三方上鏈使用或是單純的身份驗證。 函式1function ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address) hash: 是被簽章訊息的雜湊 v: 簽章的 v 值 r: 簽章的 r 值 s: 簽章的 s 值 回傳: 簽章者地址 範例例如下面的範例 123456789contract EcrecoverTest { function test() external view returns(address) { bytes32 hash = 0xc1af4b94166cd32fc49b7b926cbb91ee421de2d04450e8ae57857b9b56ac7e53; uint8 v = 0x1b; bytes32 r = 0xe1077fb9321c187d8a43926896abac5455ce ...