3

My goal is to schedule a call once every day.

[Q] Is it possible to use recursive function to schedule a call once every day using Ethereum Alarm Clock scheduler?

Example from following answer https://ethereum.stackexchange.com/a/87/4575 :

contract SchedulerAPI { 
    function scheduleCall(address contractAddress,
                          bytes4 abiSignature,
                          uint targetBlock) public returns (address); }

contract CallMeLater {
    // The address of the v0.6.0 Alarm Clock scheduler contract.
    address constant Scheduler = SchedulerAPI(0xe109ecb193841af9da3110c80fdd365d1c23be2a);

    function CallMeLater() {
        // Schedule a call to the `callback` function
        Scheduler.value(2 ether).scheduleCall(
            address(this),               // the address that should be called.
            bytes4(sha3("callback()")),  // 4-byte abi signature of callback fn
            block.number + 5082,          // the block number to execute the call 
        );               //As we know 1 day duration (1440 minutes): 5082 blocks.
    }

    function callback() public {
        // whatever code you want executed.
          CallMeLater(); //added: recursive call.
    } }

I added additional CallMeLater(); into end of callback() function, I assume, which will make new schedule (1 day ahead) in order to call callback().

2 Answers 2

2

Solution

The protocol changed since the question was posted. It is possible to do recursive calls by building a service that for example takes advantage of Proxy wallet (to fund following calls).

Ethereum Alarm Clock has RecurringPayment example in its repository. This is the contract:

pragma solidity 0.4.24;

import "contracts/Interface/SchedulerInterface.sol";

/// Example of using the Scheduler from a smart contract to delay a payment.
contract RecurringPayment {
    SchedulerInterface public scheduler;

    uint paymentInterval;
    uint paymentValue;
    uint lockedUntil;

    address recipient;
    address public currentScheduledTransaction;

    event PaymentScheduled(address indexed scheduledTransaction, address recipient, uint value);
    event PaymentExecuted(address indexed scheduledTransaction, address recipient, uint value);

    function RecurringPayment(
        address _scheduler,
        uint _paymentInterval,
        uint _paymentValue,
        address _recipient
    )  public payable {
        scheduler = SchedulerInterface(_scheduler);
        paymentInterval = _paymentInterval;
        recipient = _recipient;
        paymentValue = _paymentValue;

        schedule();
    }

    function ()
        public payable 
    {
        if (msg.value > 0) { //this handles recieving remaining funds sent while scheduling (0.1 ether)
            return;
        } 

        process();
    }

    function process() public returns (bool) {
        payout();
        schedule();
    }

    function payout()
        private returns (bool)
    {
        require(block.number >= lockedUntil);
        require(address(this).balance >= paymentValue);

        recipient.transfer(paymentValue);

        emit PaymentExecuted(currentScheduledTransaction, recipient, paymentValue);
        return true;
    }

    function schedule() 
        private returns (bool)
    {
        lockedUntil = block.number + paymentInterval;

        currentScheduledTransaction = scheduler.schedule.value(0.1 ether)( // 0.1 ether is to pay for gas, bounty and fee
            this,                   // send to self
            "",                     // and trigger fallback function
            [
                1000000,            // The amount of gas to be sent with the transaction. Accounts for payout + new contract deployment
                0,                  // The amount of wei to be sent.
                255,                // The size of the execution window.
                lockedUntil,        // The start of the execution window.
                20000000000 wei,    // The gasprice for the transaction (aka 20 gwei)
                20000000000 wei,    // The fee included in the transaction.
                20000000000 wei,         // The bounty that awards the executor of the transaction.
                30000000000 wei     // The required amount of wei the claimer must send as deposit.
            ]
        );

        emit PaymentScheduled(currentScheduledTransaction, recipient, paymentValue);
    }
}

Basically you can see that constructor function is payable, that means you have to fund the contract when creating it. This will fund future recursive calls.

Good example to look at is also Recurring Alarm Clock. The project is open-source and you can take a look at the code.

Misinformation in other answers/comments

Well, the other answer doesn't take into account how Ethereum Alarm Clock works - that call is scheduled, not instantly called. This means, there won't be infinite loop, it's more like setInterval in JavaScript.

Someone also misinforms in comment that there's gracePeriod, which would mean: "You'll find a parameter "gracePeriod" which says you cannot make the same call after 255 blocks." - but this is also wrong.

The linked documentation itself is outdated, but it says:

uint8 gracePeriod: The number of blocks after targetBlock that it is ok to still execute this call. Cannot be less than 64. (default: 255).

So gracePeriod in this example can be read as EXECUTION WINDOW.

1

Gas assumption issue might be there? I guesstimate as long as "this function capable accepting fund for Gas", this scheduled contract would run forever.

2
  • @alpher Were you able to verify this?
    – Gagan
    Oct 30, 2018 at 13:48
  • According to this document. You'll find a parameter "gracePeriod" which says you cannot make the same call after 255 blocks. So doesn't it mean that there is a limit in recursive?
    – Gagan
    Oct 30, 2018 at 14:18

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.