在某些业务,市场或行业,存在不允许双向发送付款的场景,即只能从账户A向B发送付款,而不能从账户B向A发送付款。这称为单向支付通道。
在某些业务,市场或行业,存在不允许双向发送付款的场景,即只能从账户A向B发送付款,而不能从账户B向A发送付款。这称为单向支付通道。
在这一步中,我们将创建一个简单的智能合约,添加一些依赖项来安全地签署交易。这是为了防止重放攻击和重入攻击。
这些依赖项来自OpenZeppelin合约,这是一个用于安全智能合约开发的库。
pragma solidity >=0.7.0 <0.9.0;
import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol"; import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/utils/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 = msg.sender;
receiver = _receiver;
}
}
现在,我们将创建一些函数,用于从发送方签署付款。
我们已经创建了4个不同的函数用于哈希并将哈希转换为EthSignedMessageHash。请注意,我们使用私有函数调用是为了重用代码,以这种方式减少gas使用量。
pragma solidity >=0.7.0 <0.9.0;
import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol"; import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/utils/ReentrancyGuard.sol";
contract UniDirectionalPaymentChannel is ReentrancyGuard {
// ...
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);
}
// ...
}
为了从接收方验证哈希,我们需要创建一个逆函数来“取消签名”交易。在这种情况下,当我们恢复签名时,我们应该获得发送方地址作为结果,这样我们就可以验证金额已经从发送方地址发出。
pragma solidity >=0.7.0 <0.9.0;
import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol"; import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/utils/ReentrancyGuard.sol";
contract UniDirectionalPaymentChannel is ReentrancyGuard {
// ...
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);
}
// ...
}
一旦我们声明了这些函数,以便从一边到另一边签署和恢复信息,我们就可以安全地进行交易了。
pragma solidity >=0.7.0 <0.9.0;
import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol"; import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/utils/ReentrancyGuard.sol";
contract UniDirectionalPaymentChannel is ReentrancyGuard {
// ...
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);
}
// ...
}
这是完整的合约。
pragma solidity >=0.7.0 <0.9.0;
import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/cryptography/ECDSA.sol"; import "github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/utils/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 = 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);
从开发人员的角度来看,区块链技术是非常有挑战性和有趣的。就我而言,因为它让我觉得我正在构建经济体系的一部分。
Source:https://medium.com/itnext/uni-directional-payment-channels-in-solidity-1aab8cc7eda9
ChinaDeFi - ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。
Layer 2道友 - 欢迎对Layer 2感兴趣的区块链技术爱好者、研究分析人与Gavin(微信: chinadefi)联系,共同探讨Layer 2带来的落地机遇。敬请关注我们的微信公众号 “去中心化金融社区”。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!