An intuitive way of structuring your Solana program
When building Sure I have been so lucky to experiment with different styles of rust code and structure. I have been inspired by projects such as orca, jet, cykura and others that strive towards high degree of reusability and separation of concerns. It has become clear that a style has emerged.
before we jump into the weeds I just want to tell you that I have previously written about Solana development in these posts
- Transfer tokens between accounts on Solana
- Mint tokens on Solana using the Rust SDK
- Solana Anchor: “IdlError: Type is not find”
Please check them out if you want to quickly get started on Solana development. Also, please follow my twitter account https://twitter.com/0xksure for daily updates on blockchain development, web development and some nonesense.
Ok, awesome, lets do it!
The Solana Signature Style (tm?) is basically having three folders under src/, namely
- utils (or common)
This structure makes it very easy to concentrate on one problem at a time. Additionally, there is usually one paper thin lib.rs file under src/ that reference your instruction logic. Looks elegant, feels simple.
This is typically how src/ will look like
Let’s jump into the different folders and justify their existence.
One might be tempted to place the state together with instructions. Unfortunately, parts of the state might be needed in other or all of the instructions.
It’s a many-to-many relationship between state and instructions. An instruction would update different states and a state will be called by different instructions.
Now, state should be responsible for initializing, updating, deleting, returning data and do computation necessary to get to the next state.
While the instruction is responsible for receive and validating accounts. For then to structure the data and send it along to a state method.
Say you want to implement an automated market maker like uniswap. From the liquidity provider side you would interact with the program by using instructions like
- instructions/provide_liquidity.rs — responsible for updating the liquidity state and user state. But also move tokens from the LPs wallet into the pool.
- instructions/reduce_liquidity.rs — Similar to provide_liquidity but in reverse.
Each of these will call on state/pool.rs.
The pool state (state/pool.rs) would likely have the method provide/reduce_liquidity which would perform the necessary math and update the pool state.
Now you might also have a state/liquidity.rs file where you store logic for updating the user liquidity state. Naturally, an instruction will make calls for two state update, pool and liquidity.
Therefore it makes sense to separate state and instruction.
This is where you store your account handling and state update calls.
As mentioned above in the AMM example we might have the two files
- instructions/provide liquidity.rs
- instructions/reduce liquidity.rs
For which each of them will make calls to update the pool and liquidity state.
Before making any calls to update the state you must validate your accounts. This is especially important on Solana as invalidated accounts can contain data that exploits some vulnerability in your logic. If you want me to write more about please say so in the comment section.
Utils (or common)
Not every project has or needs a common folder. However, when your project grows in size it makes sense to extract shared logic from typically state to another place. This makes the code much easier to read and think about.
Actually, most of what you decide to move to the common folder is functions, methods or implementations that belongs in an external repo for others to use.
Some of the functionality that I have seen in common folders are
- bit math — when working with binary fixed point math rather than using floats (f32,f64).
- token transfer logic
- error handling — how do you handle errors inside your program and how do you notify your users
A case study
To wrap it up here is how a typical folder structure looks like
This is taken from the Oracle program of the Sure Protocol. Here you can see that a factory/ folder is also included. If you peek inside the folder you will see little logic. It could have been moved to utils.
The programs under Sure Protocol is a good reference for how to build on Solana using anchor. It’s a monorepo containing Solana programs, sdks and frontends. Please check it out if you are interested. And btw the oracle is live on http://oracle.sure.claims/ if you want to try it out.
It’s great to have a common way of structuring programs.
Please don’t get too caught up in how others do it as it usually makes the development experience more robotic and less creative.
Coding is meant to be fun and creative! But I would advice you from slinging 10,000 lines of rust code in a lib.rs. You know, for maintainability reasons.
Open source you code. Do it!
This is paramount to the developer experience on Solana. It helps new developers get up to speed on Solana development and hopefully shines light on new ways to compose programs. If you think your program is safe from breaches because you close source it you have to think again.
Hope you enjoyed this short but hopefully helpful post. I have been quite sloppy when it comes to putting out content on Solana or any development. I will try to expand some of my tweets into longer sized posts. So please follow me on https://twitter.com/0xksure for daily content.