Yesterday I successfully pushed the TreeFund contract up to the Ethereum Ropsten test network. It felt great to put something on-chain, even if it was just a test network.
I tested calls, transfers, and transactions against several contract methods. I’m happy to report back that I didn’t encounter any issues during these tests.
While this felt like progress, I was anxious to bring it all together and wire up leaf node withdrawals. As I began looking into leaf node withdrawals, I realized that my state tracking mechanism wasn’t going to play well with multi-coin support.
Before I dig into the challenges of multi-coin support, I want to step back and revisit the original premise for the TreeFund contract and discuss how I’ve implmented balance tracking. Then I will explore how the feature set has evolved and how I’m hoping to adapt and build those out.
The original idea for the TreeFund revolved around a simple concept. Akin to a trust fund, a grantor establishes a fund (via Ethereum contract), to which they can add coins to the fund by sending them into the TreeFund contract. The DApp would have a configurable number of benefactors (leaf nodes) that would be entitled to a percentage of the fund. Leaf nodes could withdraw coins from the fund after a certain amount of time had passed. For example, once a leaf node turned 18 years old, the DApp would make her share of the coins in the fund available for withdrawal.
Evolving Premise, State Tracking
As I worked through the initial development of the contract, I realized that I could expand on the premise in exciting ways. I also ran into a tricky development puzzle that needed to be solved before I could take on any new features.
The fund would need the ability to add new leaf nodes periodically, and it would also need to track the dynamic balances of leaf nodes. In off-chain application development, this would be a trivial task. Using a simple loop, we could iterate through each leaf node to calculate how many coins a given leaf would be entitled too. Leaf node balances could be calculated and recalculated as necessary.
In Solidity, however, it’s recommended to avoid unbounded loops. Because we want our DApp to support n number of leaf nodes, it’s essential to take this consideration seriously.
Enter Entitlement State
Initially, having not given it enough thought, I assumed that we could take the total amount of coins in the fund and divide it by the total number of leaf nodes to calculate the number of coins that a given leaf node was entitled too.
However, if we calculate leaf node entitlement in proportion to the amount of time a given node spent in the fund, leaf nodes can be added with custom dates, and we cant loop over unbounded arrays, simple division of balances probably won’t work.
After exploring several possibilities, I concluded that one concise way to track leaf node balances would be to keep a running total of how long all of the nodes had been active in the fund. In the contract, this is our
In a simple example, we can look at how this would work for a TreeFund contract with three leaf nodes:
- Leaf #1 - 6 years in fund
- Leaf #2 - 4 years in fund
- Leaf #3 - 1 year in fund
6 + 4 + 1 = 10 |
entitlmentState = 10
Then if total TreeFund holdings = 100 ETH
Leaf #1 entitlement can be calculated like this:
(6/10) * 100 = 60 ETH
Anytime that a leaf is added, we run a method that updates the entitlement state. We are amortizing work by updating the entitlmentState when the addLeaf method is called so this works nicely.
We now have a single state variable in the contract (and on-chain!) that allows us to calculate a given leaf node’s entitlement, without looping over unbounded arrays.
Ropsten Deployment, Multi-coin support
After deploying to Ropsten, it became clear pretty quickly that we had another issue. Tracking entitlement state in this way works well if you have a single asseset in the fund, but we want to support n number of coins, and things seem to get complicated quickly in that case.
For example, sticking with our example above, if the fund was holding 100 ETH and 8000 DAI, how would we adjust the entitlement state if a leaf node wanted to withdrawal a small amount of DAI? It’s not nearly as straight forward.
Fortunately, it would seem like one solution is to create and manage an entitlement state counter for each coin that the fund supports. It should be relatively simple to rework the contract to handle this. I also keep thinking there might be an excellent way to do this with native/wrapped ERC20 tokens. Either way, let’s talk about how the fund can now be used to invest coins into an interest earning DeFi position.
Investing TreeFund Coins into DeFi
It was too much fun, not to. I added connectors into the Compound.finance contracts enabling TreeFund to establish interest-earning DeFi positions with MCD (DAI). For now, the owner of the contract is the only one that can open DeFi positions with Compound, but of course, we can update the contract to add some clever muli-sig leaf node movements or something like that down the road. I’m hoping to write more about this integration after some further testing.
Moving Towards Mainnet
With those new features included, we can say the mission of the TreeFund contract is to allow grantors to collect, store, invest, and distribute coins to benefactors. The next steps are to implement multi-coin support and leaf withdrawals. Once that’s tested and working on Ropsten, we’ll be one step closer to mainnet :)