1

I have a function that allows users to pay for a monthly subscription. I run slither on my smart contract I got a warning that I have a potential re-entrance attack because State variables written after the call(s):

Should I move the transferFrom and sent require check to the end of the function?

// 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'
    );

    bool sent = token.transferFrom(subscriber, plan.merchant, plan.amount);
    require(sent, "token transfer failed");
    emit PaymentSent(
      subscriber,
      plan.merchant, 
      plan.amount, 
      planId, 
      block.timestamp
    );
    subscription.nextPayment = subscription.nextPayment + plan.frequency;
  }

1 Answer 1

0

To avoid re-entrency attack, you need to update your variables PRIOR to the transfer call. The code below should work. (If you still get re-entrency warning, please see if you might share entire contract code, so I can be sure I am not missing anything)

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'
    );
    
    // UPDATING Subcription prior to transferFrom
    subscription.nextPayment = subscription.nextPayment + plan.frequency;

    bool sent = token.transferFrom(subscriber, plan.merchant, plan.amount);
    require(sent, "token transfer failed");
    emit PaymentSent(
      subscriber,
      plan.merchant, 
      plan.amount, 
      planId, 
      block.timestamp
    );
    
  }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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