iT邦幫忙

2024 iThome 鐵人賽

DAY 6
0
Modern Web

web3 短篇集系列 第 6

讓用戶主動提領 (Pull over Push pattern)

  • 分享至 

  • xImage
  •  

今天介紹一個寫合約的設計模式:Pull Payment Pattern (pull-over-push pattern)

智能合約常常被比喻為自動販賣機,使用者投錢,機器執行 function,吐出選擇的飲料。如果要找零,販賣機會在給飲料的同時即時找零。

然而,智能合約應該避免這樣的設計。好的合約傾向將退款的動作獨立寫成一個 function,當用戶主動領取退款時才轉錢。

以下是一個不良示範:

// bad
contract auction {
    address highestBidder;
    uint highestBid;

    function bid() payable {
        require(msg.value > highestBid);

        if (highestBidder != address(0)) {
            (bool success, ) = highestBidder.call{value: highestBid}("");
            require(success); // if this call consistently fails, no one else can bid
        }

       highestBidder = msg.sender;
       highestBid = msg.value;
    }
}

這是一個第一價格拍賣合約,可以看到 bid function 在使用者出價後,直接將上一個最高出價者的錢退還給他,接著更新合約的狀態。

這個 external call 可能失敗。如果上一個最高出價者使用合約來呼叫 bid,而他的合約 fallback 就是 revert,此時轉錢過程會導致交易失敗,合約狀態會 rollback,使得 bid 將永遠無法被執行。

遇到 external call 要預設有失敗的可能性。因此我們將退款邏輯移至另一個 function,使用 mapping(address => uint) refunds 紀錄退款者的地址和金額,讓用戶主動提出退款請求。

// good
contract auction {
    address highestBidder;
    uint highestBid;
    mapping(address => uint) refunds;

    function bid() payable external {
        require(msg.value > highestBid);

        if (highestBidder != address(0)) {
            refunds[highestBidder] += highestBid; // record the refund that this user can claim
        }

        highestBidder = msg.sender;
        highestBid = msg.value;
    }

    function withdrawRefund() external {
        uint refund = refunds[msg.sender];
        refunds[msg.sender] = 0;
        (bool success, ) = msg.sender.call{value: refund}("");
        require(success);
    }
}

不要直接將錢匯到用戶的地址,而是幫他們存起來,讓他們自己來提領。

本文參考: https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/external-calls/#favor-pull-over-push-for-external-calls


上一篇
敲開 EVM Opcodes 的入門磚
下一篇
Reentrancy!
系列文
web3 短篇集30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言