OpenZeppelin 提供很多好用的工具使用
這章節說到**Cryptography(密碼)**相關:
檢查鏈上簽名(Checking Signatures On-Chain)
ECDSA
提供恢復和管理以太坊賬戶 ECDSA 簽名的功能。在前端 (網頁or其它) 使用web3.eth.sign產生,並且是一個65字節的數組(bytes
是Solidity 中的類型)
可以恢復數據簽名者ECDSA.recover
,並將其地址進行比較以驗證簽名。
大多數錢包會對數據進行哈希簽名並添加前綴**'\x19Ethereum Signed Message:\n'**,因此在嘗試恢復以太坊簽名消息哈希的簽名者時,您需要使用[toEthSignedMessageHash](<https://docs.openzeppelin.com/contracts/4.x/utilities#api:cryptography.adoc#ECDSA-toEthSignedMessageHash-bytes32->)。
用法大概如下:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "<https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/utils/cryptography/ECDSA.sol>";
contract ECDSAExample {
using ECDSA for bytes32;
constructor() {
}
function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) {
// data address的ECDSA加密 signature 簽名 address 地址
return data
.toEthSignedMessageHash()
.recover(signature) == account;
}
}
我們可以看_verify
確認的function一定是私有的也會是內部使用所以外部修飾詞一定是internal
搬磚進階:
在一些交易體系中,存在著只有單向交易,意思就是帳戶A向B發送付款,而B無法向A發送付款
(有心人就知道改怎麼做了 😈 ,所以我們最好是多了解一點。)
參考來源:https://learnblockchain.cn/article/3566 講得非常詳細例如為什麼這樣做省gas。
這裡有修正0.8.0 版本的執行
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "<https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/utils/cryptography/ECDSA.sol>";
import "<https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/security/ReentrancyGuard.sol>";
contract UniDirectionalPaymentChannel is ReentrancyGuard {
using ECDSA for bytes32;
address payable public sender;
address payable public receiver;
constructor(address payable _receiver) payable {
require(_receiver != address(0), "receiver = zero address");
sender = payable(msg.sender);
receiver = _receiver;
}
function _getHash(uint _amount) private view returns (bytes32) {
return keccak256(abi.encodePacked(address(this), _amount));
}
function getHash(uint _amount) external view returns (bytes32) {
return _getHash(_amount);
}
function _getEthSignedHash(uint _amount) private view returns (bytes32) {
return _getHash(_amount).toEthSignedMessageHash();
}
function getEthSignedHash(uint _amount) external view returns (bytes32) {
return _getEthSignedHash(_amount);
}
function _verify(uint _amount, bytes memory _sig) private view returns (bool) {
return _getEthSignedHash(_amount).recover(_sig) == sender;
}
// 驗證
function verify(uint _amount, bytes memory _sig) external view returns (bool) {
return _verify(_amount, _sig);
}
// 一旦我們聲明了這些函數,以便從一邊到另一邊簽署和恢復信息,我們就可以安全地進行交易了。
function send(uint _amount, bytes memory _sig) external nonReentrant {
// verifing signature and sender != receiver
require(msg.sender == receiver, "sender must be different than receiver");
require(_verify(_amount, _sig), "invalid signature");
(bool sent, ) = receiver.call{value: _amount}("");
require(sent, "Failed to send Ether");
selfdestruct(sender);
}
}
其實我們理解之後,會發現其實就是一個加密解密的過程(回到大學的時候 瑟瑟發抖 🙀 )
還可以看到這裡引用了 ReentrancyGuard 這個套件,主要是解決重入攻擊這個我們要開一個章節解釋,所以其實我們用好OpenZeppeline 套件,就算不懂用下去也就比較安全。
有任何問題可反饋: [email protected]