iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
Modern Web

web3 短篇集系列 第 8

個案研究:wannabet

  • 分享至 

  • xImage
  •  

wannabet 是一個鏈上打賭的合約應用,它的想法很簡單,程式碼也不難,是一個值得初學者入門研究的專案。

"escrow" 是指「第三方托管」,智能合約很適合做這類型的應用,我們可以把錢丟進合約,根據程式邏輯與條件,從合約取回託管的代幣。合約的邏輯在鏈上是固定的,用戶若懂得辨別地址與合約程式碼是否匹配、看懂合約的規則,以及確認合約的升級條件等等,將有助於了解鏈上應用的可信任程度。

使用者情境

A 想要跟 B 打賭,A 使用工廠合約 BetFactory.sol 部署一個 Bet.sol 合約,寫上要賭的內容,寫上打賭對象 (B 的地址),決定一個裁判的地址,決定下注 1 USDC,合約部署後,合約初始狀態為 Pending。

  • 情境(1) B 看到合約內容,看到裁判,不想參與對賭,呼叫 declineBet,合約狀態變成 Declined。或者 B 連交易都不想送,直接放生 A 的合約。
  • 情境(2) B 看到合約內容,決定參與對賭,呼叫 acceptBet,把賭注 1 USDC 丟進合約,合約狀態變成 Accepted。

最後,裁判判定贏家出爐:

  • 情境(1) B 獲勝,裁判呼叫 settleBet,winner 填 B 的地址,合約將 2 USDC 轉給 B。
  • 情境(2) 雙方平手,裁判呼叫 settleBet,winner 填 0x0000000000000000000000000000000000000000,合約辨識為平手,合約把雙方的 1 USDC 退還給 A 和 B。

例子

這裡放一個內容較完整的賭注,打賭內容大概是:

如果在太平洋時間 2024 年 11 月 5 日午夜(即 2024 年選舉日)之前,wannabet.cc 上的結算賭注超過 250 筆,則該賭注結果為「是」(0x...f812 勝出);否則,該賭注結果為「否」(0x...EF14 勝出)。

收小費

這部分我覺得挺有趣,特別挑出來講。

上述提到,A 想要跟 B 打賭,A 使用工廠合約 BetFactory.sol 部署一個 Bet.sol 合約。

如果 A 懂一點智能合約,它可以稍微改一下 Bet.sol,然後直接部署該合約,也能在鏈上跟 B 對賭,不必透過工廠合約。

工廠合約是由 wannatbet 的設計者所部署,讓用戶呼叫工廠合約來部署打賭合約,這可能在整體程式設計上會一定的好處,但開發者藉機設計了收小費的功能。

當 A 使用 BetFactory 部署 Bet.sol 的時候,以及當 B 呼叫 acceptBet 的時候,送出的交易的 value 需要滿足小費的金額,交易才會成功。

也就是說,A 和 B 在把 1 USDC 投入合約託管時,要塞一點 ETH 小費給 wannatbet 的擁有者,才能成功執行交易。

以下程式片段請參考 https://github.com/wannabet-cc/wannabet/blob/e7eb0a6e4db28f8a80313048cdd9f303c81ca63e/contracts/v2/BetFactory.sol#L121-L130

function createBet(
        address _participant,
        uint256 _amount,
        address _token,
        string memory _message,
        address _judge,
        uint256 _validFor
    ) public payable nonReentrant {
    
    ...
    
    // Interactions: Token transfer
        IERC20(_token).safeTransferFrom(
            msg.sender,
            address(newBet),
            _amount
        );

        // Interactions: Send ETH fee
        (bool feeSuccess, ) = payable(owner()).call{value: msg.value}("");
        if (!feeSuccess) revert BET__FailedEthTransfer();
    } catch {
        revert("Deployment or token transfer failed");
    }

以下程式片段請參考 https://github.com/wannabet-cc/wannabet/blob/e7eb0a6e4db28f8a80313048cdd9f303c81ca63e/contracts/v2/Bet.sol#L90-L110

function acceptBet() public payable onlyParticipant nonReentrant {
    // Checks
    if (msg.value < _BET_FACTORY.fee()) revert BET__FeeNotEnough();
    if (_isExpired()) revert BET__Expired();
    if (_status != Status.Pending) revert BET__InvalidStatus();

    // Update state
    _status = Status.Accepted;

    // Emit event
    emit BetAccepted();

    // Interactions: Token transfer
    _TOKEN.safeTransferFrom(msg.sender, address(this), _AMOUNT);

    // Interactions: Send ETH fee
    (bool feeSuccess, ) = payable(_BET_FACTORY.owner()).call{
        value: msg.value
    }("");
    if (!feeSuccess) revert BET__FailedEthTransfer();
}

Reference


上一篇
Reentrancy!
下一篇
自主管理的錢包
系列文
web3 短篇集30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言