Quickstart¶
Introduction¶
This guide is inteded for smart contract developers that may want to use the EAC services from within their own applications. Since all the functionality of the Alarm Clock is built into the Ethereum chain via smart contracts, it can be accessed from other contracts. This makes it useful as a foundational tool to design and implement more complex utilities that depend on future transactions. For this guide we will be using the Solidity language. If you are unfamiliar with Solidity we recommend you familiarize yourself with its documentation first.
Scheduling your first transaction¶
The first step is to establish how we will interact with the EAC service’s
Scheduler
contract. We can use the Scheduler Interface to accomplish this.
The Scheduler interface contract contains some logic that is shared between both the
Block Scheduler and the Timestamp Scheduler. The function that we are interested in is the
schedule() function. See the signature of this function below:
function schedule(address _toAddress,
bytes _callData,
uint[7] _uintArgs)
doReset
public payable returns (address);
SchedulerInterface.sol
is an abstract contract that exposes the API for the Schedulers
including the schedule()
function that we will use in the contract we write.
function schedule
which will
return the address of the newly created TransactionRequest
contract. We will import this
contract into the contract we write so to ensure that our contract will be
compliant with the official API of the EAC.
Now lets write a simple contract that can use the scheduling service.
pragma solidity 0.4.19;
import 'contracts/Interface/SchedulerInterface.sol';
/// Example of using the Scheduler from a smart contract to delay a payment.
contract DelayedPayment {
SchedulerInterface public scheduler;
uint lockedUntil;
address recipient;
function DelayedPayment(
address _scheduler,
uint _numBlocks,
address _recipient
) {
scheduler = SchedulerInterface(_scheduler);
lockedUntil = block.number + _numBlocks;
recipient = _recipient;
scheduler.schedule.value(2 ether)(
recipient, // toAddress
"", // callData
[
2000000, // The amount of gas to be sent with the transaction.
0, // The amount of wei to be sent.
255, // The size of the execution window.
lockedUntil, // The start of the execution window.
30000000000 wei, // The gasprice for the transaction (aka 30 gwei)
12345 wei, // The fee included in the transaction.
224455 wei, // The bounty that awards the executor of the transaction.
20000 wei // The required amount of wei the claimer must send as deposit.
]
);
}
function () {
if (this.balance > 0) {
payout();
} else {
revert();
}
}
function payout()
public returns (bool)
{
require(getNow() >= lockedUntil);
recipient.transfer(this.balance);
return true;
}
function getNow()
internal view returns (uint)
{
return block.number;
}
}
The contract above is designed to lock away whatever ether it is given for
numBlocks
blocks. In its constructor, it makes a call to the
schedule
method on the scheduler
contract. We would pass in
the address of the scheduler we would want to interact with as the first
parameter of the constructor. For instance, if we wanted to use the Block
Scheduler that is deployed on the Ropsten test net we would use address
0x96363aea9265913afb8a833ba6185a62f089bcef
.
The function only takes 3 parameters at deployment, with the 7 parameters being into the schedule function being set by the developer of the smart contract. The schedule function takes 7 arguments, each of which we will go over in order.
address toAddress
: Theaddress
which the transaction will be sent to.bytes callData
: Thebytes
that will be used as the data for the transaction.uint callGas
: The amount of gas that will be sent with the transaction.uint callValue
: The amount of ether (in wei) that will be sent with the transaction.uint8 windowSize
: The number of blocks afterwindowSize
during which the transaction will still be executable.uint windowStart
: The first block number that the transaction will be executable.uint gasPrice
: The gas price which must be sent by the executing party to execute the transaction.uint fee
: The fee amount included in the transaction.uint payment
: The payment included in the transaction.
Let’s look at the other function on this contract. For those unfamiliar with solidity,
the function without a name is known as the fallback function. The fallback
function is what triggers if no method is found on the contract that matches
the sent data, or if data is not included. Usually, sending a simple value transfer function
will trigger the fallback function. In this case, we explicitly pass an empty string
as the callData
variable so that the scheduled transaction will trigger this
function when it is executed.
When the fallback function is executed, if the contract has a balance (which it does
since we sent it 2 ether on deployment) it will route the call into the payout()
function.
The payout()
function will check the current block number and check if it is not
below the lockedUntil
time or else it reverts the transaction. After it
checks that the current block number is greater than or equal to the lockedUntil
variable, the function will transfer the entrie balance of the contract to the
specified recipient.
As can be seen, this will make it so that a payment is scheduled for a future
date but won’t actually be sent until that date. This example uses a simple
payment, but the EAC will work with arbritrary logic. As the logic for a scheduled
transaction increases, be sure to increase the required callGas
in accordance.
Right now, the gas limit for a transaction is somewhere in the ballpark of 8,000,000
so there’s plenty of wiggle room for experimentation.