Solana Smart Contract Best Practices
This is a beta version of the Solana Toolkit, and is still a WIP. Please post all feedback as a GitHub issue here.
Optimize Compute Usage
To prevent abuse of computational resources, each transaction is allocated a "compute budget". This budget specifies details about compute units and includes:
- the compute costs associated with different types of operations the transaction may perform (compute units consumed per operation),
- the maximum number of compute units that a transaction can consume (compute unit limit),
- and the operational bounds the transaction must adhere to (like account data size limits)
When the transaction consumes its entire compute budget (compute budget exhaustion), or exceeds a bound such as attempting to exceed the max call stack depth or max loaded account data size limit, the runtime halts the transaction processing and returns an error. Resulting in a failed transaction and no state changes (aside from the transaction fee being collected).
Additional References
Saving Bumps
Program Derived Address (PDAs) are addresses that PDAs are addresses that are deterministically derived and look like standard public keys, but have no associated private keys. These PDAs are derived using a numerical value, called a "bump", to guarantee that the PDA is off-curve and cannot have an associated private key. It "bumps" the address off the cryptographic curve.
Saving the bump to your Solana smart contract account state ensures deterministic address generation, efficiency in address reconstruction, reduced transaction failure, and consistency across invocations.
Additional References
Payer-Authority Pattern
The Payer-Authority pattern is an elegant way to handle situations where the account’s funder (payer) differs from the account’s owner or manager (authority). By requiring separate signers and validating them in your onchain logic, you can maintain clear, robust, and flexible ownership semantics in your program.
Shank Example
Anchor Example
Additional References
Invariants
Implement invariants, which are functions that you can call at the end of your instruction to assert specific properties because they help ensure the correctness and reliability of programs.
Additional References
Optimize Indexing
You can make indexing easier by placing static size fields at the beginning and variable size fields at the end of your onchain structures.