Solidity

智能合約不斷聽取價格資訊並在達到價格後立即執行的最佳方式是什麼?

  • May 28, 2021

我編寫了一個智能合約,該合約應該從 2 個地址,一個下注創建者和一個下注接受者那裡下注。賭注是 ETH/USD 的價格(通過 ChainLink)。

什麼是智能合約不斷聽取 ETH/USD 價格的最佳方式,以便每當價格達到賭注的一方或另一方時,合約就會generateBetOutcome()自動?

pragma solidity ^0.8.4;

import "https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";

contract Bet {

   //bet status
   uint constant STATUS_WIN = 1;
   uint constant STATUS_LOSE = 2;
   uint constant STATUS_TIE = 3;
   uint constant STATUS_PENDING = 4;

   //game status
   uint constant STATUS_NOT_STARTED = 1;
   uint constant STATUS_STARTED = 2;
   uint constant STATUS_COMPLETE = 3;

   //general status
   uint constant STATUS_ERROR = 4;

   //the betting structure
   struct DoubleBet {
       uint guess;
       address addr;
       uint status;
   }

   //the 'game' structure
   struct Game {
       uint256 betAmount;
       uint outcome;
       uint status;
       DoubleBet creator;
       DoubleBet taker;
   }
   
   Game game;
   
   receive() external payable {
   }
   
   address payable owner;
   
       AggregatorV3Interface internal priceFeed;

   /**
    * Network: Kovan
    * Aggregator: ETH/USD
    * Address: 0x9326BFA02ADD2366b30bacB125260Af641031331
    */
   constructor() public {
       priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
   }
   
   function createBet(uint _guess) public payable {
     game = Game(msg.value, 0, STATUS_STARTED, DoubleBet(_guess, msg.sender, STATUS_PENDING), DoubleBet(0, msg.sender, STATUS_NOT_STARTED));
     game.creator = DoubleBet(_guess, msg.sender, STATUS_PENDING);
   }

   function takeBet(uint _guess) public payable { 
     //requires the taker to make the same bet amount     
     require(msg.value == game.betAmount);
     game.taker = DoubleBet(_guess, msg.sender, STATUS_PENDING);
     generateBetOutcome();
   }
   
   function generateBetOutcome() private {
       game.outcome = uint(getThePrice());
       game.status = STATUS_COMPLETE;
       
       if (game.creator.guess == game.taker.guess) {
         game.creator.status = STATUS_TIE;
         game.taker.status = STATUS_TIE;
       } else if (game.creator.guess > game.outcome && game.taker.guess > game.outcome) {
         game.creator.status = STATUS_TIE;
         game.taker.status = STATUS_TIE;
       } else {
          if ((game.outcome - game.creator.guess) < (game.outcome - game.taker.guess)) {
            game.creator.status = STATUS_WIN;
            game.taker.status = STATUS_LOSE;
          } else if ((game.outcome - game.taker.guess) < (game.outcome - game.creator.guess)) {
            game.creator.status = STATUS_LOSE;
            game.taker.status = STATUS_WIN;
          } else {
            game.creator.status = STATUS_ERROR;
            game.taker.status = STATUS_ERROR;
            game.status = STATUS_ERROR;
          }
       }
   }
//returns - [<description>, 'originator', <originator status>, 'taker', <taker status>]
    function getBetOutcome() public view returns
    (string memory description, string memory originatorKey, uint originatorStatus, string memory takerKey, uint takerStatus) 
    {
       if (game.creator.status == STATUS_TIE || game.taker.status == STATUS_TIE) {
         description = "Both bets were the same or were over the number, the pot will be split";
       } else {
           if (game.creator.status == STATUS_WIN) {
            description = "Bet originator guess was closer to the number and will receive the pot";
          } else if (game.taker.status == STATUS_WIN) {
            description = "Bet taker guess was closer to the number and will receive the pot";
          } else {
            description = "Unknown Bet Outcome";
          }
       }
       originatorKey = "creator";
       originatorStatus = game.creator.status;
       takerKey = "taker";
       takerStatus = game.taker.status;
    }

   /**
    * Returns the latest price
    */
   function getThePrice() public view returns (int) {
       (
           uint80 roundID, 
           int price,
           uint startedAt,
           uint timeStamp,
           uint80 answeredInRound
       ) = priceFeed.latestRoundData();
       return price;
   }
   
   
   modifier onlyOwner() {
       require(msg.sender == owner);
       _;
   }
   
   
   
   function getBalance() public view returns (uint balance) {
       return address(this).balance;
   }
   
   
}

智能合約不能自動觸發自己,它們需要區塊鏈外部的東西來創建交易。使用 Chainlink,您有 2 個選項:

  1. 在 Chainlink 節點上創建一個作業,該作業使用cron 啟動器定期呼叫智能合約中的函式來檢查 ETH/USD 的價格,並在需要時採取行動。您可以安排它每天/每小時等執行
  2. Chainlinks 即將推出的Keeper Network是完成此類任務的理想人選。請注意,這仍處於測試階段,尚未在主網上正式啟動

引用自:https://ethereum.stackexchange.com/questions/99792