
介绍
在某些业务,市场或行业,存在不允许双向发送付款的场景,即只能从账户A向B发送付款,而不能从账户B向A发送付款。 这称为单向支付通道。
Solidity 实现
创建合约
在这一步中,我们将创建一个简单的智能合约,添加一些依赖项来安全地签署交易。这是为了防止重放攻击和重入攻击。
这些依赖项来自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带来的落地机遇。敬请关注我们的微信公众号 “去中心化金融社区”。
