solidity编写简单支付通道智能合约代码

编写一个简单的支付通道

  Alice是发件人,Bob是收件人,若AliceBob之间含有多笔交易,每次都通过以太坊钱包转账,矿工不仅会扣取手续费,且以太坊的出块速度约为10-15s,因此存在交易延迟。

  在存在多笔交易时,构建一个简单但完整的支付通道使用椭圆曲线加密签名以实现安全、即时且无交易费用地重复传输以太币

  该支付通道需要实现发件人在调用合约初期把以太币质押在合约中,根据签名验证判断发件人总共欠收件人多少以太币,在合约有效期内由收件人结束合约并转账给收件人应得以太币,这样整个流程就只需要2次以太坊交易,节省了交易费和时间延迟。

什么是支付通道

  支付通道允许参与者在不发起以太坊交易的情况下重复转移以太币。这意味着可以节省与交易相关的延迟和费用。我们将探索两方(Alice Bob)之间的简单单向支付通道。它包括三个步骤:

1Alice用以太币智能合约提供资金。这“打开”了支付通道

2Alice签署消息,指定欠Bob多少以太币。每次付款都重复此步骤。

3Bob“关闭”支付通道,提取他的部分以太币并将剩余部分发还给Alice

  注意:只有第1步和第3步需要以太坊交易,第2步意味着Alice通过链下方法(如电子邮件)向Bob发送加密签名的消息。这意味着只需要两笔交易即可支持任意数量的转账。

  Bob可以保证收到应得资金,因为智能合约托管了Alice以太币并对消息签名加以验证。此外,为智能合约设计有效期限,即使Bob拒绝关闭支付通道,Alice也可以保证最终收回她的资金。由Alice设置或更改合约有效期

开通支付通道

  为打开支付通道,Alice部署智能合约,附加要托管的以太币并指定以太币接收者和合约有效期。这是下面合约代码函数SimplePaymentChannel的功能。

付款

  Alice通过向Bob发送签名消息来付款此步骤完全在以太坊网络之外执行。消息由发件人加密签名,然后直接传输给收件人。

每条消息都包含以下信息:

  智能合约的地址用于防止跨合约重放攻击),到目前为止欠收款人的以太币总量。

关闭支付通道:

  支付通道仅关闭一次每条消息都指定了累积的以太币欠款总额只有最新发送的消息被兑换。当Bob准备好接收以太币时,通过调用智能合约上的close函数来关闭支付通道只有Bob可以调用close函数,他们自然会传递最新的支付消息,因为该消息携带最高的总欠款该函数Bob支付应得以太币Alice返还剩余以太币,并销毁合约。

支付通道到期

  Bob可以随时关闭支付通道,但如果他们不这样做,Alice需要一种方法来收回她的托管资金。在合约部署时设置了合约有效期。一旦到达有效期,爱丽丝就可以调用函数claimTimeout()来收回资金。调用此函数后,Bob将无法再收到任何以太币,因此Bob需要在到期之前关闭通道。

solidity代码如下:

pragma solidity >=0.7.0 <0.9.0;

//用Remix编写,需手动调用function以实现相关功能
contract SimplePaymentChannel{
    address payable public sender;//发件人地址
    address payable public recipient;//收件人地址
    uint public expiration;//存储合约到期时间,防止收件人一直不关闭合约,占用发件人以太币资源

    //构造函数,部署合约时调用,仅调用一次
    //初始化发件人地址,收件人地址,合约有效时间
    constructor(address payable recipientAddress, uint256 duration) payable{
        sender = payable(msg.sender);//msg.sender是address类型,需强制类型转换为payable address类型
        recipient = recipientAddress;
        expiration = block.timestamp + duration;
    }

    //销毁合约,只有收件人能销毁合约
    function close(uint256 amount, bytes memory signature) external{
        //require()中判断条件为true则继续,为false则退出该function,回退该function内所有更改
        require(msg.sender == recipient);//判断调用该function地址是否为收件人
        require(isValidSignature(amount, signature));//判断收件人是否掌握有正确的的发件人消息签名

        recipient.transfer(amount);//把应得的以太币发送给收件人,谁调用transfer(),就给谁转账
        selfdestruct(sender);//销毁当前合约,将合约剩余资金发送到给定地址sender
        //由于合约内容已被记录在旧的区块上,仍可以被查询,但不能被再次调用,除非重新部署该合约
    } 

    //合约有效期续期,仅有发件人可以调用
    function extend(uint256 newExpiration) external{
        require(msg.sender == sender);//判断调用者是否为发件人
        require(newExpiration > expiration);//判断新的有效期是否大于当前有效期

        expiration = newExpiration;//重置合约有效期
    }

    //判断当前合约是否在有效期内
    function claimTimeout() external{
        require(block.timestamp >= expiration);//判断当前合约是否过期,若过期,则销毁合约
        selfdestruct(sender);//销毁合约
    }

    //函数isValidSignature(),splitSignature(),recoverSigner(),prefixed()涉及到 椭圆曲线加密 消息的验证过程,
    //详见我的另一篇博客https://www.cnblogs.com/forkroad/p/16121333.html,有详细介绍
    function isValidSignature(uint256 amount, bytes memory signature) internal view returns(bool){
        bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));//根据当前地址this和转账金额amount双重加密为消息message
        return recoverSigner(message, signature) == sender;//
    }

    function splitSignature(bytes memory sig) internal pure returns(uint8 v, bytes32 r, bytes32 s){
        require(sig.length == 65);
        assembly{
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            v := byte(0, mload(add(sig, 96)))
        }
        return (v, r, s);
    }

    function recoverSigner(bytes32 message, bytes memory sig) internal pure returns(address){
        (uint8 v, bytes32 r, bytes32 s) = splitSignature(sig);
        return ecrecover(message, v, r, s);
    }

    function prefixed(bytes32 hash) internal pure returns(bytes32){
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

}

 

 来源(solidity官方英文文档0.8.13):https://docs.soliditylang.org/en/v0.8.13/solidity-by-example.html#writing-a-simple-payment-channel

solidity官方中文文档0.8.0:https://learnblockchain.cn/docs/solidity/solidity-by-example.html#id15

椭圆曲线签名验证代码实现:https://www.cnblogs.com/forkroad/p/16121333.html

 

posted @ 2022-04-09 21:02  豆豆是只乖狗狗  阅读(655)  评论(0编辑  收藏  举报