90

In my blockchain application, I would like to have an event triggered at a later time, hours or perhaps even days after the application has most recently received a transaction from a user. How can I create an "event" that will trigger after a certain amount of time has passed?

84

Lazy vs Eager Execution

There are two fundamental ways of designing a contract to be called at a later time: lazy evaluation or eager evaluation.

Lazy evaluation means that the contract's state will be updated only when needed. This often makes sense for contracts that naturally incentivise users to call them at a future date.

An example of this might be a trust fund contract that will remain locked until someone's 18th birthday. This individual would be motivated to execute the dispersal of those funds at that time.

A more complex example is an interest-bearing contract. Say I deposit 1 ETH, and every month I get 1% interest, compounding.

There are two ways to go about this:

  1. The lazy way: When I want to withdraw my money, I call the contract and it calculates my balance, based on the interest rate, my last known balance, and the elapsed time.
  2. The eager way: I use the Ethereum Alarm Clock or some similar service to call the claimInterest() function of the contract, which calculates that month's interest and debits my balance.

In this case, lazy evaluation makes sense, because it is easy to calculate the current state based on the past state and elapsed time.

Eager evaluation is useful when state transitions are

  1. Computationally expensive
    • Working with large storage sets, sorting large lists, etc.
  2. Nondeterministic
    • Relies on outside input, such as calls to Oraclize.it
  3. Lacking incentives
    • Data reconciliation, various non-monetary contracts.
  4. Reliant on another contract
    • If the contract needs to accept input from or send transactions to another contract

Call Scheduling with Ethereum Alarm Clock

The Ethereum Alarm Clock service supports scheduling a contract to be called at a specified block in the future. The underlying mechanism is essentially an abstraction of incentive based solution above that allows arbitrary private key based accounts to have an incentive to execute calls on arbitrary contracts.

The protocol has been audited and deployed on mainnet. It's fully functioning right now.

Call scheduling can be done with the following code:

const { EAC, Util } = require('@ethereum-alarm-clock/lib');
const moment = require('moment');

const web3 = Util.getWeb3FromProviderUrl('ws://localhost:8545');

const eac = new EAC(web3);

async function scheduleTransaction() {
    const receipt = await eac.schedule({
        toAddress: '0xe87529A6123a74320e13A6Dabf3606630683C029',
        windowStart: moment().add('1', 'day').unix() // 1 day from now
    });

    console.log(receipt);
}

scheduleTransaction();

The example above uses @ethereum-alarm-clock/lib. which is minimal library to use Ethereum Alarm Clock protocol.

More explanatory instructions can be found here. There's also video tutorial.

Part of scheduling the call is providing sufficient ether to pay for the future gas costs for executing the call, as well as for the payments that go to the executor of the call and fee to protocol creators (if specified).

When this call is scheduled, a new contract is deployed that manages all of the details for call execution.

Execution

The Alarm service requires a private key based Ethereum account to execute the call at the specified time. This behavior is motivated by a payment value that is associated with each scheduled call. When the target block occurs, the executor of the call is fully reimbursed for their gas costs as well as paid from the specified payment amount for their service.

This process of monitoring the Alarm service for upcoming calls and executing them can be accomplished using TimeNode. Anyone can be a TimeNode, here's comprehensive tutorial and video how to become one: How to Run a TimeNode.

Configurable options for scheduled calls

  • toAddress - Recipient address
  • callData - Transaction data
  • callGas - Gas limit for transaction execution in the future
  • callValue - Future transaction value in Wei
  • windowSize - Size of the time window for execution, in blocks or seconds
  • windowStart - Block number / UNIX timestamp of when the window for execution should open
  • gasPrice - Future gas price for execution
  • fee - Fee (in Wei) paid to Ethereum Alarm Clock maintainers for using scheduling
  • bounty - Payment for transaction executor
  • requiredDeposit - Executor deposit, when it tries to execute scheduled transaction

Costs

The Alarm service attempts to create open market for call scheduling. The scheduler may specify any amount for both the Bounty and Fee values and those executing calls are free to choose which calls they are willing to execute.

At the time of scheduling, sufficient ether must be provided to pay for both the gas costs as well as the associated payments and fees. After execution, any remaining ether is automatically returned to the scheduler of the call.

Testing

The Alarm service is available for testing on the test networks such as Kovan and Ropsten. There are TimeNodes running which execute transactions on these networks.

Guarantees

The Alarm service is a marketplace for call scheduling and cannot provide any guarantees that a scheduled call will be executed. For the service to operate, it requires people to initiate the transactions that execute scheduled calls.

Protection

As the scheduler of a function call, you can count on the following:

  • Your contract will be called with the exact call data it was configured with.
  • Your contract will not be called before or after the window of blocks between the target block and the number of blocks after specified by the grace period.

Trustlessness

The Alarm service does not grant any special permissions to any party and is 100% open source.

Documentation and other links

  • See my comment on the other answer. First to combine the two gets the check mark! – Jeff Coleman Jan 21 '16 at 0:12
  • I added a section at the top which addresses (briefly) the concept of a contract incentivizing certain actions. – Piper Merriam Jan 21 '16 at 0:30
  • That's close, but it doesn't quite get to the heart of linagee's answer which is that you can often restructure a contract so that the "real" balances are just updated to the latest numbers the first time someone calls on them. I'd also like to see some description of how developers should decide between the "lazy evaluation" approach and the ethereum alarm clock approach, like I mentioned in my comment. – Jeff Coleman Jan 21 '16 at 0:42
  • 1
    Is this project still alive? Latest commit was [6 days ago][1] but the last release was in [October 2016][2]. [1]: github.com/pipermerriam/ethereum-alarm-clock/commit/… [2]: github.com/pipermerriam/ethereum-alarm-clock/releases/tag/… – atlantis Jul 7 '17 at 6:36
  • 1
    No news since then. Unfortunately it looks like this project is dead. – Kar.ma Aug 31 '17 at 10:44
20

You could use the Ethereum Alarm Clock as previously mentioned, but you could also change your programming style to a "must call to execute" paradigm.

For instance, if you want to lock up money for a month until it gets returned, instead of actually having the money be sent after a month, you could have the user call a function that then returns the money.

  • 2
    My ideal answer combines these top two by explaining when you should use one style vs the other. The answer, by the way, is that you should use a "must call to execute" paradigm for operations that affect only your own contract's state, and you should use the Ethereum Alarm clock for operations that need to update some state elsewhere in the blockchain (the state of someone who won't be calling your contract directly). – Jeff Coleman Jan 21 '16 at 0:11
15

As others have mentioned already, you can use the Alarm-clock or change the flow of your contract.

Another option is to use Oraclize with an empty query:

/*
   Simple Alarm code.

   This contract will be called back automatically 1 day after its birth
*/

import "dev.oraclize.it/api.sol";

contract Alarm is usingOraclize {
    function Alarm() {
       oraclize_query(1*day, "URL", "");
    }

    function __callback(bytes32 myid, string result) {
        if (msg.sender != oraclize_cbAddress()) throw;
        // do something, 1 day after contract creation
    }
} 
4

There is no formal way to schedule events via the protocol itself.

However somebody already wrote an Ethereum Alarm Clock-contract that supports scheduling events at a later moment in time. It's decentralized as well as far as I could tell, anybody can fire scheduled events and get paid for doing so.

1

Currently There are several options for this.

The top answer is old and Ethereum Alarm Clock was down for a long time until a few weeks ago and now is managed (looks like) by the Chronologic team.

I am copying an answer here as the community sends any other answer about scheduling to this one. I am including also a code example of how to do this with the AION system in mainnet and Ropsten.

Aion by ETH-Pantheon:

This a system that allows arbitrary bytecode transactions to be scheduled.This means you can call a particular function in a contract with particular data at any time or block in the future.
Pros: simple, allows arbitrary bytecode, unused gas is returned, low gas consumption, trustless, the transaction fee is defined apriori, live in mainnet and test networks, nice App, transactions can be canceled without incurring in payment of any class.
Cons: centralized.


Chronologic network:

This is basically a wrap on ethereum alarm clock (reboot).
Pros: decentralized (as it uses EAC), allows arbitrary bytecode, unused gas is returned, nice app, live in mainnet and test networks .
Cons: expensive in gas, fee per transaction is not defined apriori, scheduler nodes need to hold a chronologic token, also beside the payment to the executor a basefee to the developer of the EAC should be provided.


Oraclize:

This works calling a callback function after some period selected by the user, then you put the code you want to execute inside that function.
Pros: simple, live in mainnet and test networks
Cons: centralized, no arbitrary bytecode allowed, gas unused is not returned, the fee per transaction could be changed at any time, and to any value, which mean you must trust Oraclize.


Joule System: mywish.io.

This is a decentralized system to schedule ether transactions.
Pros: decentralized, app, live on mainnet and test networks
Cons: limited type of transactions.



Scheduling transactions using AION System.

In the case of AION (by ETH Pantheon) this is an example of scheduling recurrently a function

\You must use an external service for that application as smart contracts need to be triggered by an external account. The system AION allows you to do this, you can see examples of this here.

Assume you have a smart contract like this:

contract mycontract{
    uint256 public result;
    function add(uint256 x, uint256 y) public {
        result = x + y;
    } 

}

and you want to calculate this sum every 1 hour (for the sake of the example).

Aion allows you to schedule the execution of your function in a recursive way. Interfacing your contract with AION, the solution will be like this:

pragma solidity ^0.4.24; 

// this is the interface with AION
contract Aion {
    uint256 public serviceFee;
    function ScheduleCall(uint256 blocknumber, address to, uint256 value, uint256 gaslimit, uint256 gasprice, bytes data, bool schedType) public payable returns (uint,address);

}


contract MyContract{
    uint256 public result;
    Aion aion;

    // This function request to schedule the transaction
    function schedule_add(uint256 x, uint y) public {
        aion = Aion(0xFcFB45679539667f7ed55FA59A15c8Cad73d9a4E);
        bytes memory data = abi.encodeWithSelector(bytes4(keccak256('add(uint256,uint256)')),x,y); 
        uint callCost = 200000*1e9 + aion.serviceFee();
        aion.ScheduleCall.value(callCost)( block.timestamp + 1 hour, address(this), 0, 200000, 1e9, data, false);
    }


    // this is your original function
    function add(uint x, uint y) public {
        result = x + y;
    }


    function () public payable {}

}

This can be tested on Ropsten for free. (this example is for ropsten).

Disclaimer: I wrote the code for AION.

Hope this helps

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.