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?
9 Answers
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:
- 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.
- 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
- Computationally expensive
- Working with large storage sets, sorting large lists, etc.
- Nondeterministic
- Relies on outside input, such as calls to Oraclize.it
- Lacking incentives
- Data reconciliation, various non-monetary contracts.
- 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 addresscallData
- Transaction datacallGas
- Gas limit for transaction execution in the futurecallValue
- Future transaction value in WeiwindowSize
- Size of the time window for execution, in blocks or secondswindowStart
- Block number / UNIX timestamp of when the window for execution should opengasPrice
- Future gas price for executionfee
- Fee (in Wei) paid to Ethereum Alarm Clock maintainers for using schedulingbounty
- Payment for transaction executorrequiredDeposit
- 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
- Full documentation on all aspects of the service is available here: http://docs.ethereum-alarm-clock.com/en/latest/
- Blog where any updates to the service are published: https://blog.chronologic.network/
- Primary web site with information on the currently deployed service and instructions on how to verify the source code: https://www.ethereum-alarm-clock.com/
- Instructions how to schedule using MyCrypto interface: https://blog.chronologic.network/how-to-schedule-transactions-on-mycrypto-com-f9c631dfa8dc
-
See my comment on the other answer. First to combine the two gets the check mark! Commented Jan 21, 2016 at 0:12
-
I added a section at the top which addresses (briefly) the concept of a contract incentivizing certain actions. Commented Jan 21, 2016 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. Commented Jan 21, 2016 at 0:42
-
2Is 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/…– atlantisCommented Jul 7, 2017 at 6:36
-
2No news since then. Unfortunately it looks like this project is dead.– Kar.maCommented Aug 31, 2017 at 10:44
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.
-
3My 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). Commented Jan 21, 2016 at 0:11
-
1💯 sublime answer, i think there's a lot of overcomplicatedness to web3 we should do away with– evenzeroCommented Aug 20, 2023 at 18:12
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
}
}
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.
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](https://app.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](https://contracts.mywish.io/create). 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 hours, address(this), 0, 200000, 1e9, data, true);
}
// 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
-
1I am using this code and whenever I try to schedule a function execution for the future by schedule_add(), my transaction gets rejected. I guess this should be related to the network congestion and high gas fees. Any recommendation to ensure my scheduling success? Commented Nov 25, 2021 at 16:13
You can use an external service to trigger a transaction on-chain, which triggers your contract.
You can use the Chainlink Alarm Clock to do this.
A full example, showing a delayed start of 5 minutes is shown below.
pragma solidity ^0.4.24;
import "chainlink/contracts/ChainlinkClient.sol";
contract ChainlinkAlarmClock is ChainlinkClient {
uint256 oraclePayment;
constructor(uint256 _oraclePayment) public {
setPublicChainlinkToken();
oraclePayment = _oraclePayment;
}
function delayStart(address _oracle, bytes32 _jobId) public onlyOwner {
Chainlink.Request memory req = buildChainlinkRequest(_jobId, this, this.fulfill.selector);
req.addUint("until", now + 5 minutes);
sendChainlinkRequestTo(_oracle, req, oraclePayment);
}
function fulfill(bytes32 _requestId) public recordChainlinkFulfillment(_requestId) {
/* additional computation here */
/* whatever you'd like to do with the delayed start*/
}
}
You cannot set up cron jobs in Ethereum. The protocol does not natively support this kind of operation.
You have to use an automation protocol that runs on top of Ethereum, e.g. Gelato Network.
There is a useful interface for this which lets you easily schedule these time-based cron jobs without having to write any smart contract code called "Gelato Ops". Disclaimer: I helped built the app :).
Check it out here:
On there, you can just enter the smart contract address and function you want to execute and then select the time interval which should determine when this function should be executed, like so:
You can also have any other arbitrary condition trigger your smart contracts however, not only time.
-
3It seems you are part of Gelato network. The site has a rule that if you use a link in the answer you should disclose your affiliation or it will be considered as spam and deleted. Also don't copy & paste the same answer, it will be marked as spam.– Ismael ♦Commented Feb 25, 2022 at 5:34
-
An alternative solution if you don't need to be really precise is to check for outstanding scheduled tasks in user-initiated transactions.
A simple solution could be for the first transaction in any block to process any outstanding tasks:
You could do this by keeping state of the current block number. At the start of a transaction, check if the current block number doesn't match that state variable, which implies we are on a new block. Update the state variable to be the current block number, and then process any outstanding tasks. You can store some form of list of outstanding tasks along with their earliest block number or timestamp. You can also only check for outstanding tasks every, for example, fifth block. If the target block/time is reached, the necessary code can be executed.
Pros:
- No centralized source of failure
- No requirement to pay gas fees ahead of time (although you have the option to require some upfront payment if you like)
- Not possible to accidentally pay too little gas fees and have your task aborted
Cons:
- Code may be executed later than the target time if no transactions are occurring on your smart contract
- The unlucky transactor that is first in the block has to pay for gas to process outstanding transactions. This can be compensated for by paying for some or all of the gas from any reserves that the smart contract owns, or by rewarding this unlucky transactor with a custom token.