1

I have compiled a smart contract that is supposed to take bets from 2 addresses, a bet creator and a bet taker. The bet is on the price of ETH/USD (via ChainLink).

What would be the best way to for the smart contract to listen to the price of ETH/USD constantly, so that whenever the price would reach one or the other side of the bet, the contract would generateBetOutcome() automatically?

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;
    }
    
    
}


1

Smart Contracts can't automatically trigger themselves, they require something external to the blockchain to create a transaction. With Chainlink you have 2 options:

  1. Create a job on a Chainlink node that uses a cron initiator to periodically call a function in your smart contract that checks the price of ETH/USD, and take action if required. You can schedule it to run daily/every hour etc
  2. Chainlinks upcoming Keeper Network is a perfect candidate to do these types of tasks. Take note this is still in beta and hasn't been officially launched on Mainnet yet
0

I would create a process in Python or Javascript.

  1. Then use Web3 to listen to events on the blockchain or query an AMM like Uniswap at a pre determined interval.
  2. Finally if inspect the price to determine if it meets your condition. If it does perform an action.

Here are some basics tutorials on using Python to connect to the blockchain:

https://cryptomarketpool.com/getting-started-with-python-and-web3-py/

https://cryptomarketpool.com/get-market-data-from-uniswap-using-web3-py-in-python/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.