Create an application
In this section we will go through how to create an application on EES using a simple example of a contract for automated ERC-20 transfers. Along the way we will explore best practises and design patterns. However, we will not focus on gas optimization.
First, a reminder of the interface we have to implement:
The application we wish to create in this example fulfils the following specification:
onExecute
: transfers a specified amount of an ERC-20 token from the job owner to a recipient. Specifications are stored within the contract.onCreateJob
: store state data for job index with given specification.onDeleteJob
: deletes stored state data for job index.The
IApplication
callback functions should only be callable by theJobRegistry
contract. This is important because the user gives our contract token permissions, so we want to make sure transfers only happen accordingly to the time restrictions defined in EES.
Storage layout and constructor
The data we need to store for each job are the recipient of the transfer, the amount and the ERC-20 token to be transferred. Note that the owner of the job is given in all the callback functions, removing the necessity to store it. We will also use solmate's SafeTransferLib
library for safe ERC-20 token transfers.
In our contract, we are going to store a couple of things:
The
JobRegistry
contract so we can verify the caller.A mapping from job index to a
TransferData
to keep track of the transfer specification for each job.
We will also create a modifier, restricting the caller of the implemented callback functions to the address of JobRegistry
.
In the constructor we set the jobRegistry
variable:
Job creation
Now we can start implementing the first callback function, onCreateJob
:
The first line checks if the given execution module is supported and reverts if not. Then, we unpack the encoded _applicationInput
bytes to the recipient
, amount
and token
values which are stored in a new TransferData
object. Finally, we add the transferData
object in the transferDataMapping
at _index
. Notice that we only use the _index
and _applicationInput
arguments for this example. Let's quickly go over a few examples where these might be relevant:
_owner
could be relevant if wanted to do something specific to the creator of the job or simply emit an event that a recurring payment has been created from _owner
to the recipient.
_ignoreAppRevert
could be checked if we want to make sure that the recurring payment is canceled if it doesn't go through, e.g. by lack of funds.
_executionWindow
could be relevant in this case if we want to make sure that payments fall within a certain time frame after they're due.
_executionModule
can be used to restrict which execution modules we allow for this application, for example regular time intervals.
_executionModuleInput
can be used to get information about the job's input to the execution module. For example if we only allow payments in a 30 day interval, we could enforce this by checking the cooldown
parameter of the decoded _executionModuleInput
in the case of RegularTimeInterval.
Job deletion
Now, let us implement the onDeleteJob
callback function:
This function doesn't do anything fancy, we simply delete the TransferData
object corresponding to the index of the deleted job from transferDataMapping
.
Job execution
Finally, let us implement the core logic that is executed upon the call to the onExecuteJob
callback function:
In here, we are simply doing an ERC-20 token transfer from the owner of the job to the recipient with the specified amount and token saved in transferData
. We are not using the _executionNumber
argument for anything in this example as we wish to perform the same ERC-20 transfer no matter how many times the job has been executed.
The full contract
Putting it all together, we get the contract:
Now we have successfully created an application for automated transfer of ERC-20 tokens checking all the specifications we wanted. By supporting any execution module and fee module, users can make both single scheduled and recurring jobs performing ERC-20 transfers using their own preferred fee structure. The EES protocol will take care of the rest and make sure the jobs get executed. Because we keep the set of supported execution modules modifiable, we can progressively support new execution modules with time.
Careful: This contract is not tested and should not be used in production. Always perform extensive testing and auditing on smart contracts containing critical logic.
Last updated