1. 程式人生 > 其它 >solidity編寫簡單支付通道智慧合約程式碼

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