Solidity 中的单向支付通道

在某些业务,市场或行业,存在不允许双向发送付款的场景,即只能从账户A向B发送付款,而不能从账户B向A发送付款。这称为单向支付通道。

介绍

在某些业务,市场或行业,存在不允许双向发送付款的场景,即只能从账户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带来的落地机遇。敬请关注我们的微信公众号 “去中心化金融社区”

点赞 2
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ChinaDeFi 去中心化金融社区
ChinaDeFi 去中心化金融社区
ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。