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 ...
使用 Web3.js 操作 zkSync Paymaster
在之前的文章 Solidity - zkSync Paymaster 程式範例說明了如何撰寫和部署 Paymaster 合約,也有使用 Paymaster 發起交易的方法。不過專案是用 zksync-cli 建立,使用的是 Ethers.js v5 的版本。這篇文章會說明如何在 Web3.js 的專案中使用,本篇文章使用 Web3.js 4.2.2 版本。 zksync 套件zkSync 提供了官方的套件 zksync2-js 可以用來處理 Paymaster 相關的交易。但是該套件使用 Ethers.js 做為底層來開發,使用這套件等於要同時使用 Ethers.js。我這裡依據官方原始碼改寫了一份 Web3.js 版本的,可直接加入專案使用,就不用和 Ethers.js 混合使用。例如儲存為 paymaster-utils.ts: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686 ...
使用 Ethers.js 操作 zkSync Paymaster
在前一篇文章 Solidity - zkSync Paymaster 程式範例說明了如何撰寫和部署 Paymaster 合約,也有使用 Paymaster 發起交易的方法。不過專案是用 zksync-cli 建立,使用的是 Ethers.js v5 的版本。這篇文章會以如何在 Dapp 中,使用現成 Paymaster 的角度來說明。包含 Ethers.js v5 和 v6 的用法。 使用 zksync 套件和連接錢包等說明,參考之前的文章使用 Ethers.js 操作 zkSync 帳戶抽象,這邊不重複說明。 產生 Paymaster 參數使用 Paymaster 發送交易要在交易中帶入 Paymaster 相關參數,可以使用套件中提供的方法: 1utils.getPaymasterParams(paymasterAddress: string, paymasterInput: PaymasterInput): PaymasterParams paymasterAddress: Paymaster 合約地址。 paymasterInput: Paymaster 使用的類型和參數,目 ...
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 ...
使用 Web3.js 操作 zkSync 帳戶抽象
在之前的文章 zkSync 帳戶抽象 (Account Abstraction) 程式範例說明了如何撰寫和部署帳戶抽象合約,也有使用抽象帳戶發起交易的方法。不過專案是用 zksync-cli 建立,使用的是 Ethers.js v5 的版本。這篇文章會說明如何在 Web3.js 的專案中使用,本篇文章使用 Web3.js 4.2.2 版本。 zksync 套件zkSync 提供了官方的套件 zksync2-js 可以用來處理帳戶抽象相關的交易。但是該套件使用 Ethers.js 做為底層來開發,使用這套件等於要同時使用 Ethers.js。我這裡依據官方原始碼改寫了一份 Web3.js 版本的,可直接加入專案使用,就不用和 Ethers.js 混合使用。例如儲存為 eip712-signer.ts: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 ...
使用 Ethers.js 操作 zkSync 帳戶抽象
在前一篇文章 zkSync 帳戶抽象 (Account Abstraction) 程式範例說明了如何撰寫和部署帳戶抽象合約,也有使用抽象帳戶發起交易的方法。不過專案是用 zksync-cli 建立,使用的是 Ethers.js v5 的版本。這篇文章會以如何在 Dapp 中,使用現成抽象帳戶的角度來說明。包含 Ethers.js v5 和 v6 的用法,以及實際使用 Metamask 連接使用效果。 zksync 套件zkSync 提供了官方的套件可以用來處理帳戶抽象相關的交易,原先的版本為 zksync-web3,新的版本更名為 zksync2-js。分別對應到 Ethers.js v5 和 v6。 Ethers.js v5:使用 zksync-web3。 Ethers.js v6:使用 zksync2-js。 連接錢包首先要連接錢包,即為後續程式中的 signer 和 provider 的取得方式。 v6私鑰錢包12345import { Provider, Wallet } from 'zksync2-js';const private ...