Contract-Deployment
ethers.js 通過 v,r,s 值從合約部署中恢復公鑰
我目前正在嘗試獲取部署契約的使用者的公鑰。不幸的是我不能讓它工作。
我試圖僅通過使用 ethers.js 來實現這一點,因為我不想讓我的 React 建構與其他包一起膨脹。我可以使用取自此問題的以下程式碼輕鬆地從給定簽名中獲取公鑰。
let msg = "This is a normal string."; let sig = await signer.signMessage(msg); const msgHash = ethers.utils.hashMessage(msg); const msgHashBytes = ethers.utils.arrayify(msgHash); const recoveredPubKey = ethers.utils.recoverPublicKey(msgHashBytes, sig); const recoveredAddress = ethers.utils.recoverAddress(msgHashBytes, sig);
在部署合約時,我應該能夠通過簡單地將
r
,s
和v
取自deployTransaction
. 文件中的範例類似。這是我的程式碼:const deployTx = contract.deployTransaction; const msgHash = ethers.utils.hashMessage(deployTx.raw); const dataBytes = ethers.utils.arrayify(msgHash); const expanded = { r: deployTx.r, s: deployTx.s, recoveryParam: 0, v: deployTx.v }; const signature = ethers.utils.joinSignature(expanded); // now the signature should be correctly formatted const recoveredPubKey = ethers.utils.recoverPublicKey(dataBytes, signature); const recoveredAddress = ethers.utils.recoverAddress(dataBytes, signature);
這種方法行不通。據我所知,部署期間簽署的數據位於
deployTransaction.raw
. 所以這應該有效。但我也對其進行了測試deployTransaction.data
。在我看來,簽名可能是錯誤的。
joinSignature
自動將值轉換v
為 27 或 28。根據EIP155,這沒有任何意義嗎?**編輯:**澄清一下,我認為我需要的只是真正的簽名雜湊。我怎樣才能生成它?這顯然不是原始部署事務的雜湊。
**編輯 2:**在對乙太坊書籍進行一些研究後,我發現了這一點:
In Ethereum’s implementation of ECDSA, the "message" being signed is the transaction, or more accurately, the Keccak-256 hash of the RLP-encoded data from the transaction. The signing key is the EOA’s private key.
因此,我將程式碼更改為以下內容:
const deployTx = contract.deployTransaction; const msg = ethers.utils.RLP.encode(deployTx.data); const msgHash = ethers.utils.keccak256(msg); const msgBytes = ethers.utils.arrayify(msgHash); const expanded = { r: deployTx.r, s: deployTx.s, recoveryParam: 0, v: deployTx.v }; const signature = ethers.utils.joinSignature(expanded); const recoveredPubKey = ethers.utils.recoverPublicKey( msgBytes, signature ); const recoveredAddress = ethers.utils.recoverAddress(msgBytes, signature);
不幸的是,這仍然不起作用。
現在解決了。程式碼和庫中存在一個小錯誤,
ethers
無法正確返回 chainId 併計算v
值。現在已經修好了,看這裡。非常感謝 ricmoo 的幫助。我寫了一個要點,可以正確恢復給定交易的公鑰。
簡而言之:
const tx = await provider.getTransaction(...) const expandedSig = { r: tx.r, s: tx.s, v: tx.v } const signature = ethers.utils.joinSignature(expandedSig) const txData = { gasPrice: tx.gasPrice, gasLimit: tx.gasLimit, value: tx.value, nonce: tx.nonce, data: tx.data, chainId: tx.chainId, to: tx.to // you might need to include this if it's a regular tx and not simply a contract deployment } const rsTx = await ethers.utils.resolveProperties(txData) const raw = ethers.utils.serializeTransaction(rsTx) // returns RLP encoded tx const msgHash = ethers.utils.keccak256(raw) // as specified by ECDSA const msgBytes = ethers.utils.arrayify(msgHash) // create binary hash const recoveredPubKey = ethers.utils.recoverPublicKey(msgBytes, signature) const recoveredAddress = ethers.utils.recoverAddress(msgBytes, signature)