Omni and the optimization of Solana staking
💡Omni supports both native and liquid (via Lido) $SOL staking natively in app — download Omni now for iOS or Android and get a taste of those juicy yields today!
Solana has emerged as one of the most exciting layer one blockchains in recent years, and despite their growing pains (it is mainnet beta after all), they've solidified themselves as a serious contender in the Ethereum killer race.
The design decisions Solana has chosen to become a top L1 are opinionated and quite frankly a little at odds with other networks. For example, their full and validator nodes have extremely high system requirements, meaning you often can’t run nodes from home or cheaply on typical VPS software. However, the primary upside to these design decisions is a network that is simultaneously fast and cheap for end users to interact with. Sub second block times and transaction fees that can be measured in cents give Solana a chance at achieving mass adoption and delighting users who interact with it.
In this article, we’ll dig into how Solana works, some of the complexities associated with building on top of it, and how we rolled out our staking integration despite these to optimize the Solana staking experience.
For a bit of context, Omni is a self-custodial, multi chain mobile wallet. Supporting more than 20 distinct layer one networks and boasting over 30 native yield integrations, Omni is your entry point into DeFi and beyond.
The complexity that presents itself while trying to offer SOL staking as a self-custodial wallet comes down to Solana stake program specific intricacies that weren’t designed with end user friendliness in mind. Until now, existing wallets in the Solana ecosystem have directly exposed the stake program interface as it lives on chain to users, resulting in confusing flows and screens for users to manage their positions with. The Omni team looked at these flows and believed we could do better given the tools and SDKs available to us. What has resulted is the easiest Solana staking flow in the market (whether that be on desktop, browser extensions, or mobile) and a UX that is directly consistent with our other staking flows.
What is the typical Solana staking flow?
Omni prides itself on the three step staking process we’ve created for each yield integration we support, no matter the complexity. Now that we’re familiar with the Solana network, we can dig into how exactly delegation works (this will get a little fine grained and technical, but these details are necessary to fully understand the work done by our engineering team).
The first step is to create a new stake account on chain with the balance you wish to be delegated. This can be thought of as a kind of sub-account to your primary account that you send and receive funds from, logically separate but managed by your primary account. A small fee will be subtracted from your delegation amount to create this stake account, which is an implementation detail of the Solana network on chain accounts have a concept of rent exemption, ie. a balance they need to maintain to not be garbage collected by the network, a kind of DDOS prevention mechanism.
After creating this stake account and waiting for its creation to be confirmed by the network, a delegate call is able to be made that delegates the SOL loaded into the stake account initially to a validator.
For every subsequent stake operation a user wishes to make, steps 1 and 2 must be repeated, stake accounts cannot be topped up.
Now let’s quickly also cover unstaking, because this is where it gets tricky for users.
To unstake funds, we need to deactivate the previously created stake account. This is a simple transaction to submit, but it’s worth noting that it needs to be done for every stake account that exists. That means if a user has staked three times over the past year and wishes to withdraw their funds, they need to submit transactions for each of those accounts.
To further muddy the waters, stake accounts must be deactivated in their entirety. There’s unfortunately no way to unstake half your assets present in a stake account. After unstaking, a period of roughly four days needs to elapse before your stake account is deemed inactive. Once inactive, your stake (SOL tokens) can be withdrawn back to your primary account with another transaction.
So... how does Omni solve these complexities?
If you’ve made it this far, kudos, because it’s a hard flow to understand and an even harder flow to reverse engineer and come up with improvements for. As expected though, that's exactly what the Omni team did.
It all comes down to Solana core release 1.7.10, a relatively standard and innocuous release with a minor bullet point stating,
Allows stake accounts with mismatched observed credits to be merged (feature gated). This innocent line sowed the seed for our engineering team to create something great.
We observed that the primary difficulty in interacting with Solana stake accounts is purely the number of accounts you need to manage. There were methods on chain for merging and splitting stake accounts, but with two accounts needing the exact same balance to be merged (prior to 1.7.10 that is), it created UX barriers too great to actually expose to end users.
With the 1.7.10 release coming soon, step one for us was to actually surface the ability to issue merge instructions from the @solana/web3.js library. Previously, developers would have had to manually construct and encode these instructions making it a non-starter.
After getting that prerequisite out the way, we needed to correctly develop an integration that would meet our expectations for a silky smooth end user experience. The following constraints were in place for us:
Users needed to be able to delegate any amount via Omni
Users needed to be able to undelegate any amount via Omni (not all or nothing)
Users needed to see their stake as a single position, not multiple distinct stake accounts.
Given this, it was obvious that a system whereby Omni automatically rebases and splits stake accounts on behalf of users would be the optimal experience. So here’s how Solana staking works in Omni now:
When staking, Omni bundles together multiple instructions (create and delegate), allowing users to enter into a staked position with one transaction
When users stake more, Omni handles merging (using our contributions to @solana/web3.js and taking advantage of release 1.7.10) any previously unmerged stake accounts to maintain a single sub-account for staked assets
When users unstake, they can choose any amount. Omni handles issuing the correct split transactions to the stake accounts as needed, allowing unstaking a specific balance of SOL rather than everything
After the four day deactivating period (when it’s time to withdraw), Omni will notify users via push notification that their balance is ready to be claimed.
Omni's Solana staking integration is definitely one of the more challenging flows we’ve had to build. From waiting for core L1 functionality to be shipped, to making open source contributions to the canonical client SDK, this integration had it all.