Subverting the Circular Reference Error in Solidity
Recently in my Solidity adventures I have been working on a simple messaging board contract (still in development) with a voting mechanism akin to reddit. I was coding away in tranquility until I tried implementing comment chains. If you are unaware of comment chain style message boards (welcome to the internet, you must be new here), here is an example from reddit.
As you can see, a comment can contain many sub-comments, and sub-comments can have sub-comments of their own.
Encountering the Circular Reference Error
In my haste I wrote the naïve implementation where the comment contract simply stores an array of other comments’ addresses. This way the front end of my application can query the contract for the comments’ sub-comments. This uncompilable implementation is shown below.
To a day job java developer such as myself, this type of referencing is normal, but in solidity you cannot make circular references such as this or will receive a compiler error.
The (Ugly) Solution
Unfortunately, I have found no clean workaround to this error, but where there is a will there is a way. We can subvert this compilation error by creating two new contracts. I have named these the Maker and Supplier contracts. The Maker contract contains the actual functionality to create whichever contract you wish to store, in my case, a VotethComment, and the Supplier contract serves as an abstraction to the maker contract, so when we use this, the compiler is none the wiser. To create this supplier contract, all you need is the method signature of the maker contract. The supplier will be the contract we use in our main contract.
Now this implementation comes with a caveat, we must now generate a Maker contract and pass in its address to our main contract. The new VotethComment contract now will look like this.
As you can see we must now pass a generated Maker contract into the constructor. The addComment function has been modified as well. Now we create a Supplier with the address of the Maker. This is commonly done when creating contracts that call existing contracts (AKA Abstract Contract). The supplier can now create a VotethComment and we add that comment to the array of VotethComments to use on the front end. Ta Da! Comment Chains! (at least on the back end…)
Cleaning it all up
Since I am creating a reddit-style message board application I was able to clean up the generation of the Maker contract by putting it in a parent contract to the VotethComment contract rather than generating this class manually. This allows me to ignore the existence of the Maker contract floating around on the blockchain somewhere by storing it in the VotethPost contract for continual usage.
As you can see here when I call “new VotethComment()” I am passing in the comment maker conveniently stored in my VotethPost contract on creation.
You can take a look at the full example solution here on my github! Please feel free to play around with it in Remix!
If you have any suggestions or alternative solutions for me please let me know in the comments below!
Thanks For Reading!
My ethereum address: 0x947dEe856A22E8598ADdfe4Ec3175248235EEF01
My LinkedIn: https://www.linkedin.com/in/kyle-c-bryant/
I will be in Buenos Aires for a hackathon going on this month, please let me know if you will be there so we can network!