Solidity Real-Time Data – Updating Matic Price Inside a Smart Contract

go-ethereumsolidity

I'm working on a smart contract that allows users to pay for monthly subscriptions like Netflix, Amazon, etc…

Assuming that each subscription costs 20$ per month which is equivalent to 22 Matic at the time of writing this post.

During the time of the subscription, the user should pay 20$ per month with Matic, and its value will vary.

How can I update the monthly payment inside the smart contract so the subscriber will be able to pay each with the current value of MATIC not more not less? It's possible in solidity?

Or should I let the user pay his subscription manually each month based on the price of each subscription in dollars but with MATIC?

I tried to implement a solution with Tellor in my smart contract but I got stuck.

// smart contract subscription(part of it)
struct Subscription {
        address payable subscriber;
        uint start;
        uint nextPayment;
        bool activated;
    }

    
    /* nested mapping from address to id to Subscription */ 
    mapping(address => mapping(uint => Subscription)) private AllSubscriptions;


 function pay(address subscriber, uint planId) external {
    Subscription storage subscription = subscriptions[subscriber][planId];
    Plan storage plan = plans[planId];
    IERC20 token = IERC20(plan.token);
    require(
      subscription.subscriber != address(0), 
      'this subscription does not exist'
    );
    require(
      block.timestamp > subscription.nextPayment,
      'not due yet'
    );

    token.transferFrom(subscriber, plan.merchant, plan.amount);  
    emit PaymentSent(
      subscriber,
      plan.merchant, 
      plan.amount, 
      planId, 
      block.timestamp
    );
    subscription.nextPayment = subscription.nextPayment + plan.frequency;
  }

// UsingTellor functionnalities
// SPDX-License-Identifier: GPL-3.0
  pragma solidity ^0.8.0;

  import "usingtellor/contracts/UsingTellor.sol";

  contract PriceContract is UsingTellor {

  uint256 public btcPrice;

  //This Contract now has access to all functions in UsingTellor

  constructor(address payable _tellorAddress) UsingTellor(_tellorAddress) public {}

  function setBtcPrice() public {

    bytes memory _b = abi.encode("SpotPrice",abi.encode("MATIC","USD"));
    bytes32 _queryID = keccak256(_b);

    bool _didGet;
    uint256 _timestamp;
    bytes _value;

    (_didGet, _value, _timestamp) = getDataBefore(_queryID);

    uint256 maticPrice = abi.decode(_value,(uint256));

    require(token.transferFrom(subscriber,address(this),cost/maticPrice));
  }
}

Best Answer

following up on @thefett's code here's one way to do it in your project.

    // UsingTellor functionnalities
// SPDX-License-Identifier: GPL-3.0
  pragma solidity ^0.8.0;

  import "usingtellor/contracts/UsingTellor.sol";

  contract PriceContract is UsingTellor {

  uint256 public maticPrice;
  uint256 public cost = 20 ether;

  uint256 public monthlyPayment;

  //This Contract now has access to all functions in UsingTellor
  constructor(address payable _tellorAddress) UsingTellor(_tellorAddress) public {}

// smart contract subscription(part of it)
struct Subscription {
        address payable subscriber;
        uint start;
        uint nextPayment;
        bool activated;
    }

    
    /* nested mapping from address to id to Subscription */ 
    mapping(address => mapping(uint => Subscription)) private AllSubscriptions;

/* Pay subcription every Month*/
    function pay(uint256 planId) 
        external payable
        onlyUsers()
        {
        Subscription storage submitSubscription = AllSubscriptions[msg.sender][planId];

        require(block.timestamp > submitSubscription.nextPayment, " Payment not due yet");
        Plan storage plan = idToPlan[planId];

        // require(msg.value >= plan.monthlyPayment, " Monthly payment not correct");
        require(msg.value >= monthlyPayment, "Monthly payment not correct");

        emit PaymentSent(
            payable(msg.sender),
            payable(address(this)),
            plan.monthlyPayment,
            planId,
            block.timestamp);
        totalPaymentsPerWallet[msg.sender] += 1; 
        submitSubscription.nextPayment = submitSubscription.nextPayment + 4 weeks;

    }


 function setMaticPrice() public {

    bytes memory _b = abi.encode("SpotPrice",abi.encode("matic","usd"));
    bytes32 _queryID = keccak256(_b);

    bool _didGet;
    uint256 _timestamp;
    bytes memory _value;

    (_didGet, _value, _timestamp) = getDataBefore(_queryID, block.timestamp - 5 minutes);

    maticPrice = abi.decode(_value,(uint256));

    uint256 price = (cost/maticPrice);

    monthlyPayment = price * 10 **18;

  }


}
Related Topic