This page describes overall architecture and possible interactions with staking protocol developed by swap.coffee.User-friendly interface is available at https://swap.coffee/stake, but this document is aiming at providing readers
with technical insights, TL-B schemes and others associated complexities.At the time of writing this article, we only support staking protocol for our own product, but we also have plans and
are in the process of implementation (by the time you read this, it’s likely already implemented) to support staking
protocol for partner products as well.
Staking protocol consists of 2 on-chain contracts: Master and Vault;
integral off-chain backend that is responsible for rewards calciulation;
and also interacts with swap.coffee’s rewards distribution system.
Master Contract is used both for storing crucial data about protocol itself and
keeping funds that are being distributed as a rewards.
It is also fully compatible with NFT standard by supporting all related methods of NFT Collection.You may retrieve staking-related information by calling contract’s get method get_stored_data, which returns:
Technical wallet that is a part of swap.coffee’s rewards distribution system
and which serves as a proxy point for users which want to claim their staking rewards.
Contains information about the rewards that were (or being) distributed across all the users that
participate(d) in staking.Cell is being represented as a cell-referencing dictionary, which can be read as follows:
Copy
(cell data, int found) = rewards.udict_get_ref?(256, slice_hash(jetton_wallet));if (found) { slice ds = data.begin_parse(); int duration = ds~load_uint(64); int finish_at = ds~load_uint(64); int started_at = finish_at - duration; int reward_per_point = ds~load_coins();}
Every time this cell is updated, external out message is being generated:
Simplified version of the code that allows you to calculate reward for specific staking position:
Copy
int staking_position_points = 0; ;; fill with your valueint staking_position_created_at = 0; ;; fill with your valueint acquiring_at = now(); ;; fill with your value: time at which user decides to acquire his rewardint reward_rate = 0; ;; must be retrieved by catching external out messageint NORMALIZER = 1_000_000_000_000_000_000;if (staking_position_created_at < updated_at) { ;; In real world things are a bit more complicated, because rewards distribution may be updated after ;; users' staking positions were created. Internally there's a mechanism that handles such updates ;; and recalculates every staking position's rewards accordingly. return 0;}if (acquiring_time > finish_at) { acquiring_time = finish_at;}int delta_time = acquiring_time - updated_at;return reward_rate * delta_time * NORMALIZER * staking_position_points / total_points;
Unlike many other staking protocols, ours supports staking of not only one specific token, but of any
(pre-defined by the protocol administrator) set of them. One of the purposes of the Master Contract is to be
an entry point to retrieve list of such supported tokens, and this exact cell contains them.Cell is being represented as a cell-referencing dictionary, which can be read as follows:
Only those jettons that are defined in this cell may be staked. Normalizer defines amount of points being accrued
for staking one piece of this jetton.
Investment of funds is possible only for one of the predetermined periods, which are stored in this exact cell.Cell is being represented as a cell-referencing dictionary, which can be read as follows:
Copy
(cell data, int found) = periods.udict_get_ref?(32, period_id);if (found) { slice ds = data.begin_parse(); int duration = ds~load_uint(64); int percentage = ds~load_uint(64);}
For a given period, user final points may be calculated as:
Copy
int base_points = jetton_staked_amount * jetton_normalizer; return mul_div_r(base_points, percentage, 100);
After such action, if succeeded, users’ assets will be held until he decides to withdraw them
(after lock period expires), and NFT Item that corresponds to Master Contract as a NFT collection will be created
and sent to the user who initiated this transaction.Example of full deposit transaction could be found here.
Despite being written under Vault Contract section, withdrawal is performed by sending a specific transaction to
the NFT Item user received after staking his jettons. Message’s body looks as follows:
If everything is ok, there will be a chain of messages initiated by the NFT Item that will go through the
Master Contract right to the Vault Contract, freeing user’s assets.
As briefly described before, our staking protocol hardly depends on the off-chain part that not only indexes blockchain
in order to track all the users actions related to staking, but also allows us to integrate staking protocol into
already existing swap.coffee’s rewards distribution system.This is a closed proprietary product, therefore there is not really much to write about it.
Despite the fact that there are some interactions that users will encounter when using our staking protocol such as
rewards claiming, we’re not ready yet to provide in-depth details about it. But stay tuned and maybe in some future
it will also appear on our documentation website :)