Making a time savings contract in Ethereum

Or a modern day Ulysses and the sirens.

Legend has it that Ulysses really wanted to hear some sirens sing, unfortunately they had a tendency to convince the captains and crews of passing ships to steer their vessels into some rocks… and collect their skulls. Ulysses solution to this problem was to command his crewmen to tie him to the mast so he could enjoy the concert, ( importantly he also instructed them to cover their ears) .

Savings accounts present you with a similar problem, let’s say you have some money left from your paycheck in your checking account, you might want to save it for a rainy day or an important future event, but there are sirens everywhere in the form of shinny things you want to spend your money on, so most savings accounts and instruments don’t allow you to withdraw your money after a certain date, they effectively tie you to the mast.

We don’t yet have a cryptocurrency bank that offers traditional savings since well, they don’t pay interests, and it’s a descentralized currency,so in the spirit of be “ your own bank™ ” you can make the best next thing, a contract that will tie you to the mast and lock your Ether for a period of time, I’ll go over the uses & logic later, for now let’s get down to it:

The Problem / challenge :

Create a contract that locks your funds ( Ether in this case ) and then releses them after a certain time period.

The contract :

pragma solidity ^ 0.4.0;
contract DateTime {
function getYear(uint timestamp) public constant returns (uint16);
function getMonth(uint timestamp) public constant returns (uint8);
function getDay(uint timestamp) public constant returns (uint8);
}
contract FuturePayable {
address private owner;
uint public bday;
uint public payday;
address public dateTimeAddr = 0x8Fc065565E3e44aef229F1D06aac009D6A524e82;
DateTime dateTime = DateTime(dateTimeAddr);
modifier onlyOwner {
require(msg.sender == owner);
_;
}
/*constructor*/
function FuturePayable() public {
owner = msg.sender;
bday = now;
payday = ( bday + 1 days );
}
/* Default function */
function() public payable {
}
function withdraw() public onlyOwner {
require (block.timestamp > payday);
msg.sender.transfer(this.balance);
}
function getBirthYear() view public returns (uint16){
return dateTime.getYear(bday);
}
function getBirthMonth() view public returns (uint8){
return dateTime.getMonth(bday);
}
function getBirthDay() view public returns (uint8){
return dateTime.getDay(bday);
}
function getPayYear() view public returns (uint16){
return dateTime.getYear(payday);
}
function getPayMonth() view public returns (uint8){
return dateTime.getMonth(payday);
}
function getPayDay() view public returns (uint8){
return dateTime.getDay(payday);
}
}

Deploying:

Contract Address:
0x192c0509fb52ea771bbfc6c99f4aa48b181be9e6
https://kovan.etherscan.io/address/0x192c0509fb52ea771bbfc6c99f4aa48b181be9e6

We will also send some Ether ( 1 ETH ) :

After adding the contract to Parity…

If we then try to immediately withdraw, Parity will warn you not to go ahead.

But if you do send the transaction, the contract will throw since it’s not ready yet, and you loose a bit of gas…

We need to wait for one whole day to retrieve our Ether, we will use that time to explain the contract:

function FuturePayable() public  {
owner = msg.sender;
bday = now;
payday = ( bday + 1 days );
}

The constructor upon creation sets the relevant dates, and here you can change the duration to something more relevant like 1 months 1 years it also defines an owner.

The other relevant bit is this one:

function withdraw() public onlyOwner {
require (block.timestamp > payday);
msg.sender.transfer(this.balance);
}

The first thing to note is that we are checking for ownership via the onlyOwner modifier, we then check that the date is correct with block.timestamp > payday and if so we then send the whole contracts balance upon being called, that’s it.

The rest of the contract just adds a payable function and some convenience date getters I covered previously here:

https://medium.com/@k3no/making-a-birthday-contract-858fd3f63618

A note about working with Timestamps:
Our contracts birthday is 1513212652 in Timestamp format.
It can also be consulted in human readable form straight from the contract thanks to the use of a Time Date library:
getBirthDay    14
getBirthMonth 12
getBirthYear 2017
The gotcha here is that the timestamp has a fixed time zone (UTC), so you would still need to convert it to your local time zone for it to make sense to you or your users.

So a day has passed and now is time to call the contract again…

This results in the owner account ( K3NOKOVAN ) receiveing (0.99 Ether, see note ) and the contracts balance going back to zero as intended, you can check the tx history for details:

https://kovan.etherscan.io/address/0x192c0509fb52ea771bbfc6c99f4aa48b181be9e6

Important Note: There are 2 transactions and thus 2 types of fees, the first one originated from the owner account calling the withdraw function:
https://kovan.etherscan.io/tx/0xfe63a3a5e22d3a0b505e1157de43dcd5c1912990fabd8fac13268a16336d9343
It consumed 30054 wei in Gas.
The second one is the one generated by this calls transfer, and it is called an Internal Transaction :
https://kovan.etherscan.io/tx/0xfe63a3a5e22d3a0b505e1157de43dcd5c1912990fabd8fac13268a16336d9343#internal
It consumed around 2300 wei in Gas (the limit or stipend for transfers). Both transaction fees were paid by the originating contract (the owner)
If you are transferring to the same account from where you are calling, your fees and deposit might be added in parity or other wallets,this is why you might get 0.99 ETH, and not 1 full ETH. 

Uses.

Well, the obvious one is to lock your Ether for a time period, you might want to buy and hodl some Ether for a few months expecting that the price rises, but don’t trust yourself you won’t spend it in some crypto kittens instead, or worse panic sell.

Other uses could be financial instruments, escrow services and future contracts.

Improving it.

While a working example, this is by no means the final word in time savings contracts, a number of improvements could be made, adding an automatic withdrawal, clearer finer date information, make it killable, provide a setter for the time period to name a few.

Thanks for reading !


Shameless plug:
If you are looking for an introduction to Ethereum, Solidity and Smart Contracts I just published an eBook ( and soon a print one ) on getting started:

https://www.amazon.com/dp/B078CQ8L7V

About the Author :

Born Eugenio Noyola Leon (Keno) I am a Designer,Web Developer/programmer, Artist and Inventor, currently living in Mexico City, you can find me at www.k3no.com