I’m really excited to release our code for the Catallax Trust today. It has been a long time coming and it will be nice to get some new eyes on the code.

If this is your first time reading about the Catallax Trust you can read the white paper here. A Catallax Trust is a contract that will hold crypto and pay it out in the future in fiat-based chunks based on the exchange rate at the time of the withdrawal. I can be used for employment contracts, donating to a charity, securing ICO funds, or simply helping you HODL with a budget.

We have had one code review done and implemented a number of improvements identified in that code review. Of course, we hope that the contracts are production ready, but if you think otherwise, please let us know by sending the issue to bugs@catallax.com or filing an issue on the github repo: https://github.com/skilesare/catallaxtrust

The Catallax Trust is made up of the following main contracts:

FiatTrustCustodian.sol — This is the custodian contract that oversees the creation of new trusts and tracks the fiat to crypto conversion rates for supported crypto / fiat pairs.

FiatTrustFactory.sol — This is the factory contract that the custodian uses to create new trusts. We can swap this out if we create a better trust without having to republish the custodian.

FiatTrust.sol — This contract is the core trust. Users will deposit their ETH and / or ERC20 tokens in these contracts and be able to withdraw from them over time.

The following support contracts are included as well:

DateTime.sol — a date time library

SafeMath.sol — safe arithmetic functions

ERC20.sol — interacting with tokens

TrustStorage.sol — we have to store the historical history of crypto / fiat exchange rates. This is held in a storage contract so that we can easily move the history to upgraded custodians if necessary.

iLicensor.sol — a stub contract for future governance of the custodian

The general process for setting up the contracts follows the following process(this is the code from our test suite):

prepEnvironment = (custodianOwner)->

return new Promise (resolve, reject)->

custodian = null

factory = null

token = null

storage = null

#Create the custodian

FiatTrustCustodian.new(from: custodianOwner).then (instance)->

custodian = instance

#create the factory

FiatTrustFactory.new(custodian.address, from: custodianOwner)

.then (instance)->

console.log 'new factory'

factory = instance

#create a datetime library(this has been published previously on mainnet so you can use one of those)

DateTime.new(from: custodianOwner)

.then (instance)->

console.log 'new DateTime'

#set the date time library

custodian.SetDateTimeLibrary(instance.address, from: custodianOwner)

.then (result)->

console.log 'dt set'

#set the factory location

custodian.SetFactory(factory.address, from:custodianOwner)

.then (result)->

console.log 'factory set'

#Create an ERC20 token to test with

HumanStandardToken.new(tokenStartBalance,"token",0,'tkn', from: custodianOwner)

.then (instance)->

console.log 'new token'

token = instance

#create a new storage contract

TokenStorage.new(from: custodianOwner)

.then (instance)->

console.log 'new storage'

storage = instance

#set the storage contract

custodian.SetStorage(storage.address, from: custodianOwner)

.then (instance) ->

console.log 'storage set'

#update the owner of the storage to include the custodian contract

storage.UpdateOwner(custodian.address, true, from: custodianOwner)

.then (instance)->

console.log 'first conversion set'

#set an old conversion for ETH to USD

custodian.SetConversion(ethTokenAddress, usdCurrencybytes, 1989,1, 1, web3.toWei(0.01,"ether"),1, from: custodianOwner)

.then (instance)->

console.log 'conversion set'

#set an old conversion for ERC20 token to USD

custodian.SetConversion(token.address, usdCurrencybytes, 1989,1, 1, web3.toWei(0.01,"ether"),1, from: custodianOwner)

.then (instance)->

console.log 'max fee set'

#set the max fee

custodian.SetMaxFee(usdCurrencybytes, 50, from: custodianOwner)

.then (instance)->

console.log 'origination fee set set'

#set the origination fee

custodian.SetOriginationFee(usdCurrencybytes, 25, from: custodianOwner)

.then ->

resolve

custodian: custodian

token: token

Once your custodian is configured you need to create, fund, and start your trust. The following code will do that and then make time pass so you can do your first withdrawal:

custodian.CreateTrust(ethTokenAddress, usdCurrencybytes, 12, 1, {from: accounts[0]})

.then (txn)->

trustAddress = null

txn.logs.map (o)->

if o.event is 'TrustCreated'

console.log 'found new Trust at' + o.args.location

i = FiatTrust.at(o.args.location)

trustAddress = o.args.location

console.log 'have instance'

#fund the wallet

web3.eth.sendTransaction({ from: accounts[1], to: i.address, value: web3.toWei(0.44,"ether") })

.then (result)->

#Start the Trust

i.StartTrust(from:accounts[0])

.then (result)->

console.log result

console.log 'sending ether'

#this function advances time in our test client by 34 days

return new Promise (tResolve, tReject)->

web3.currentProvider.sendAsync

jsonrpc: "2.0",

method: "evm_increaseTime",

params: [86400 * 34], # 86400 seconds in a day

id: new Date().getTime()

, (err)->

tResolve true

.then (result)->

#calculate the next withdraw date

i.NextWithdraw()

.then (result)->

console.log 'next ' + result

nextPayout = result.toNumber()

aDate = nextPayout * 1000

aDate = moment.utc(new Date(aDate))

console.log aDate

console.log 'conversion set for ' + aDate.year() + (aDate.month() + 1) + aDate.date()

#set the conversion for that tdate

custodian.SetConversion(ethTokenAddress, usdCurrencybytes, aDate.year(), aDate.month() + 1, aDate.date(), web3.toWei(0.01,"ether"),1)

.then (result)->#call the withdraw fucntion. 0.1 eth shold move from the contract to account[0]

console.log 'conversion set'

aDate = nextPayout * 1000

aDate = moment.utc(new Date(aDate))

console.log aDate

#check the current balance

web3.eth.getBalance(custodian.address)

.then (result)->

console.log result

startCustodianBalance = result.toNumber()

assert.equal 250000000000000000, startCustodianBalance, 'custodian has ether it shouldnt'

startBalance = web3.eth.getBalance(accounts[0])

console.log 'Start Balance' + startBalance

#withdraw from the trust

i.Withdraw(from: accounts[0])

.then (result)->

console.log result

web3.eth.getBalance(i.address)

.then (result)->

console.log 'withdrawl:' + result

assert.equal result.toNumber(), parseInt(web3.toWei(0.18,"ether")) - parseInt(web3.toWei(0.01,"ether")) * 0.005, 'withdraw wasnt right'

web3.eth.getBalance(accounts[0])

.then (result)->

console.log result

#since payout is 0 eth per usd we multiply fiatpayout 1

#we only test .9 eth and 1.1 because gas costs weigh in

# so much gas cost

#96 413397700000000000

#96 502336500000000000

#

console.log 'eth increased' + (result.toNumber() - startBalance.toNumber())

assert.equal result.toNumber() > startBalance.toNumber(), true, 'eth didnt transfer'

assert.equal result.toNumber() < startBalance.toNumber() + parseInt(web3.toWei(0.01,"ether")), true, 'too much eth transfered'

web3.eth.getBalance(custodian.address)

.then (result)->

console.log 'fee paid' + result

assert.equal result.toNumber(), 250000000000000000 + parseInt(web3.toWei(0.01,"ether")) * 0.005, 'Fee wasnt paid'

Have fun exploring the contracts! Post questions and issues in our github or reddit here.

If this is interesting to you and you’d like to see where we are going with Catallax, please pick up my book Immortality (Purchase of a physical or kindle copy helps support this project).

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0

If you would like more code articles like this please consider becoming a patron on patreon.

You can discuss this article and more at our reddit page r/Catallax.