Search
Duplicate
Try Notion
Token Basketing Module
Concept
The Token Basketing Module allows users to combine multiple individual derivatives with the same denomination into a single, easily tradable and exchangeable token. For example, KIRA native liquid staking derivatives V<ID>_<denom> that are issued when staking tokens in KIRA network and which are specific to the consensus node V<ID>, can be aggregated using a basket. An other use case would be to aggregate different foreign tokens such as various USD stablecoins (similarly to Curve’s 3pool), or IBC wrapped tokens, into a single, more easily tradable and stakable asset.
However, unlike common liquidity pools like Curve or Uniswap, Token Baskets do not depend on a bonding curve equation to determine the price and are simply based on fixed weights assigned to each individual token. They are only intended to consolidate the liquidity of tokens that are collateralized/pegged by the same underlying asset. In addition, one of the unique properties of Token Baskets compared to liquidity pools is that the list of tokens in the basket can be expanded or contracted over time, while the name of the basket token representing the aggregated assets remains the same.
Token Baskets facilitate token swaps, which are subject to daily limits and are executed at fixed ratios with a programmed slippage. The surplus between the actual exchange ratio and the slippage serves as an insurance fund controlled by governance to protect token holders in the event of a depeg. Overall, the Token Basketing Module is not intended to operate as an exchange, but rather as a tool for insurance and risk management, allowing users to distribute their risks among multiple assets with the same underlying peg.
Governance
In order to create a proposal to add or modify entries in the Token Baskets module, an account must possess permission 🟢59. Similarly, for voting on any of these proposals, an account must have permission 🟢60. Additionally, permission 61 allows to perform some emergency actions on existing baskets.
Parameters
NAME
TYPE
EXAMPLE
DESCRIPTION
id
uint64
1
Basket identifier
suffix
string
usd
Basket token denom suffix. Resulting basket token denom would be B1_usd if suffix value is "usd"
description
string
description
Basket description
tokens
[]kira.BasketToken
[ {"denom": "usdt", "weight": "0.99", "amount": "1000000", "deposits": true, "withdraws": true, "swaps": true}, … ]
Array of aggregated tokens with their corresponding weights, current basket balance and transaction abilities status
amount
int
10000000000
Total supply of B1_usd that can be minted
tokens_cap
float
0.9
The maximum percentage of the basket supply that a single aggregated token can represent. Transactions such as minting, burning, and swapping will fail if they cause an aggregated token's supply to exceed this percentage. Decimal from 0 to 1
limits_period
uint64
86400
Period after which all mint, swap & burn limits are reset (in Unix time/seconds, default 1 day)
mints_disabled
boolean
false
true to disable all aggregated token deposits (B1_usd minting is disabled)
mints_min
int
10000000
Minimum amount of B1_usd that must be minted per transaction (spam prevention)
mints_max
int
10000000000
Maximum cumulative daily B1_usd issuance
burns_disabled
boolean
false
true to disable B1_usd redemptions
burns_min
int
100
Minimum amount of B1_usd redemption per transaction (spam prevention)
burns_max
int
1000000000
Maximum cumulative daily amount of B1_usd redemptions
swaps_disabled
boolean
false
true to disable basket swaps
swaps_min
int
100
Minimum amount of aggregate tokens, expressed in B1_usd, that must be swapped in a single transaction
swaps_max
int
100000000000
Maximum cumulative daily amount of basket swaps, expressed in B1_usd
swap_fee
float
0.0015
Percentage fee to be paid for swapping tokens. Decimal from 0 to 1, default 0.0015 (0.15%)
slippage_fee_min
float
0.0015
Minimum percentage to be paid as penalty for disbalancing the basket. Decimal from 0 to 1, default 0.0015 (0.15%)
surplus
[]sdk.Coin
["1000ukex","20000ueth"]
Insurance funds from excess tokens accumulated as result of fee rewards from KIRA’s staking derivative and/or swaps fees
Token weights
The specific tokens that can be deposited into a basket are pre-determined. To ensure that different tokens collateralized by the same underlying asset can be accurately represented in the basket, weights are assigned to each token. These weights define the corresponding amount of the underlying derivative for a given amount of the token. For example, a "USD fiat basket" can be created by assigning a weight of 1/3.6725 = 0.2722940776 to the United Arab Emirates dirham, which is pegged to 1 USD at a rate of 1 USD = 3.6725 AED. The weight of a token can also be used to unify the number of decimal places among multiple aggregate coins with different decimal places. For instance, if two tokens, Token A and Token B, both collateralized by the same underlying asset have different numbers of decimal places (e.g. Token A has 3 decimal places, Token B has 2 decimal places), weights we can be assigned to each token to unify their decimal places. For example, a weight of 1.00 can be assigned to Token A and a weight of 0.01 to Token B. This means that 1 unit of Token A is equal to 100 units of Token B, and the basket will be expressed in terms of Token A, which has 3 decimal places. This allows the basket to represent the underlying value of both tokens in a consistent way, using a single number of decimal places.
The governance must ensure that the weights of each token in the basket are properly configured to maintain the value of the issued basket tokens. Should the governance decide to re-configure one or many of the weight properties of the basket (for example due to peg changes), it is important to ensure that the sum of the products of the weight and amount of each token in the basket must be greater than or equal to the amount of issued basket tokens B<ID>_<denom> otherwise there will not be enough tokens in the basket to redeem. For example, if the basket B<ID> includes tokens A, B, and C, the governance must ensure that (Aamount×Aweight)+(Bamount×Bweight)+(Camount×Cweight)B<ID>_<denom>.total_amount_issued\small \left(A_{amount} \times A_{weight}\right) + \left(B_{amount} \times B_{weight}\right) + \left(C_{amount} \times C_{weight}\right) \geq B_{<ID>\_<denom>.total\_amount\_issued}. If the weights are not correctly configured, the governance proposal to update the basket weights will fail.
Token caps
To prevent scenarios where one or more of the aggregated tokens becomes worthless or loses its peg, a tokens_cap field sets the maximum percentage of the total weight-adjusted supply that can be deposited for a given aggregated token (default 1, or 100%). If the amount of tokens to be deposited or swapped would result in the tokens_cap being exceeded for any of the aggregated tokens, the transaction interacting with the basket will fail.
Deposits, Withdraws, and Swaps
Token baskets include deposits, withdraws, and swaps boolean fields that can globally prohibit deposits, withdraws, or swaps of one or more specific tokens in the basket. These fields can be disabled without the need to go through a governance proposal, although only accounts with the permission 61 can perform this action. This is meant to allow necessary flexibility in managing the basket, i.e. responding to potential depeg scenarios or other time-sensitive issues with individual tokens which require quick intervention.
Mint, Burn, and Swap Limits
To prevent abuse or manipulation of the Token Baskets (i.e. infinite supply of one of the aggregated tokens being flooded into the basket until the tokens_cap is reached), Token Baskets have limits on the amount of tokens that can be minted (created), burned (redeemed for tokens), or swapped over a defined period limits_period. These limits are defined by the mints_max, burns_max, and swaps_max fields, respectively. To prevent dust spam attacks, minimum amounts of the aggregate and basket tokens that must be minted, burned, or swapped in a single transaction are also defined by the mints_min, burns_min, and swaps_min fields, respectively. Transactions that do not meet these minimum amounts will not be processed.
Pool deposits and derivatives
When users deposit a combination of tokens A, B, C… which have the same underlying asset/peg <denom> into the corresponding basket B<ID>, they receive an amount of token B<ID>_<denom> which represent their weight-adjusted share of the total basket pool, similarly to Uniswap LP tokens. For instance, if a user deposits 100 units of token A with a weight of 0.5 into the basket B5_ABC, they will receive 50 units of B5_ABC tokens.
Claim process: auto-balancing pools
The claim process is designed to ensure that the basket remains balanced at all time by calculating the ratio at which each token should be credited to the withdrawing user to restore, or at least improve, the proper weighting of the pool’s balances after a withdrawal. This means that the redemption of pooled tokens against the pool’s derivative will always be adjusted based on the current pool balances, potentially resulting in a higher proportion of a specific token if the pool is imbalanced due to previous swaps and withdrawals.
Swapping tokens
Token Baskets implement a simple swap mechanism that enables users to exchange one or multiple aggregated tokens for a set of specific ones. This function provides a convenient way for users to consolidate their holdings into a desired set of tokens. However, the swap incurs a fixed swap_fee and a variable slippage_fee with a minimum slippage-fee-min defined in the basket properties. The fees are calculated dynamically based on the degree to which the swap is disbalancing the basket. The greater the disbalance, the higher the "slippage" penalty will be. The slippage is a programmatic function and do not result from a changes in token value as seen in Liquidity Pools, as the value of all tokens remains constant.
A crucial aspect of the swap mechanism is that the sum of products of individual token amounts and their weights remain constant before and after the swap. This is expressed mathematically as:
i=0tokens.Length1tokens[i].weighttokens[i].amount=constant\left \lfloor{ \sum_{i=0}^{tokens.Length - 1}tokens[i].weight \cdot tokens[i].amount}\right \rfloor = constant
This means that the cumulative value of the tokens in the basket remain unchanged (or slightly larger due to rounding errors). Any additional tokens due to the applied slippage is accounted for in the surplus, while the basket_swap_fee is be paid to the network as a fee reward. This ensures that the value of the basket remains constant, providing stability to the system.
Surplus: Basket’s insurance funds
Unlike Uniswap, where swap fees are given to LP providers by issuing LP tokens proportionally, baskets swap fees paid by users and deposits from the governance are recorded in a separate surplus and do not issue additional basket tokens B<ID>_<denom>. These surplus serve as insurance funds to protect users against depeg events and can also collect any potential staking rewards yielded by aggregated tokens and "donations". In the event of a token losing its peg, the deposits, withdraws, and swaps properties of the depegged token may be set to false, and the governance will deposit the necessary amount of tokens from the surplus and/or the community treasury into the basket to re-adjust the weights, so that the remaining basket tokens B<ID>_<denom> can redeem the equivalent value in the form of all aggregate tokens. Although surplus funds are dedicated to their corresponding basket, the governance has the ability to redeem their entire content for redistribution to other baskets if necessary.
Special case: KIRA staking derivatives
The Token basketing module deals with a unique scenario regarding KIRA's staking derivatives V<ID>_<denom>, which accumulate block and fee rewards for their holders over time. Users pooling their V<ID>_<denom> tokens to the corresponding basket are only entitled to the block rewards accumulated by the basket on their behalf. However, it is important to note that, due to how the basket token operates, block rewards become mutualized once the derivative is pooled, meaning users may gain or lose some percentage of block rewards (compared to simply holding the individual V<ID>_<denom> itself) based on consensus nodes performance and commission rate. That being said, in KIRA, a consensus node cannot set it’s commission above 50% (or lower, depending on current network properties), hence any potential loss is minimized and should be viewed as a reasonable fee for the superior liquidity service offered by the basket.
Block rewards: The staking derivative basket does not track individual users' B<ID>_V_<denom> holdings over time , nor does it issue new ones to account for these rewards. Instead, it adjusts the weight each different V<ID>_<denom> pooled in the basket to accommodate their respective earnings. As a result, the amount of pooled tokens that a B<ID>_V_<denom> will redeem increases as each of the pooled V<ID>_<denom> collateral continues to accumulate from block rewards, while the number of issued B<ID>_V_<denom> tokens remains the same.
Fee rewards: On the other hand, fee rewards are not accounted for and are simply sent to the pool's surplus insurance fund.
CLI functions description
tx/basket
proposal-create-basket - Cast a proposal to create a basket
proposal-edit-basket - Cast a proposal to edit a basket
disable-basket-deposits - Emergency function & permission to disable one or all deposits of one or all token in the basket
disable-basket-withdraws - Emergency function & permission to disable one or all withdraws of one or all token in the basket
disable-basket-swaps - Emergency function & permission to disable one or all swaps of one or all token in the basket
mint-basket-tokens - Mint basket tokens (deposit aggregated tokens)
burn-basket-tokens - Burn basket tokens (withdraw aggregated tokens)
swap-basket-tokens - Swap one or many of the basket tokens for one or many others
basket-claim-rewards - Register the derivative basket as delegators to accumulate rewards
proposal-basket-withdraw-surplus - Cast a proposal to withdraw the surplus from one or multiple baskets
query/basket
token-basket-by-denom - Query a single basket by denomination
token-basket-by-id - Query a single basket by id
token-baskets - List token baskets using filter
historical-mints - List basket historical mints performed within ‘limits_period’
historical-burns - List basket historical burns performed within ‘limits_period’
historical-swaps - List basket historical swaps performed within ‘limits_period’
Syntax & Examples
📌
Each CLI command and proposal process in KIRA requires specific permissions. These permissions must be added to the account's whitelist or obtained as sudo permissions for direct changes. Refer to the Roles & Permissions documentation for more details. $SIGNER represents the transaction signer's account name or address. For instructions on setting common flags as environment variables, such as $FLAGS_TX and $FLAGS_QR, see the CLI flags configuration section
$TITLE
string
title
The title of the proposal.
$DESCRIPTION
string
description
The description of the proposal, it can be a url, some text, et
$BASKET_SUFFIX
string
usd
The suffix of the basket token
$BASKET_DESCRIPTION
string
usd stable coins collection
The description of the basket
$BASKET_TOKENS
[]kira.BasketToken
uusdt#0.99#true#true#true, uusdc#1#true#true#true
Comma-separated list of aggregated tokens with corresponding rates and abilities in the format denom#weight#deposits#withdraws#swaps,.... Amount field is not editable.
$TOKENS_CAP
float
1.0
Tokens cap on the basket
$LIMITS_PERIOD
int
86400
Period after which all mint, swap & burn limits are reset (in Unix time/seconds, default 1 day)
$MINTS_DISABLED
boolean
false
true to disable all basket’s deposits
$MINTS_MIN
int
10000
Minimum amount of basket token issuance per transaction (min aggregated tokens deposit)
$MINTS_MAX
int
1000000
Maximum cumulative daily basket token issuance (max cumulative aggregated tokens deposits)
$BURNS_DISABLED
boolean
false
true to disable all basket’s redemptions
$BURNS_MIN
int
10000
Minimum amount of basket token redemption per transaction (min aggregated tokens withdrawal)
$BURNS_MAX
int
1000000
Maximum cumulative daily amount of basket token redemptions (max cumulative aggregated tokens withdrawals)
$SWAPS_DISABLED
boolean
false
true to disable all basket swaps
$SWAPS_MIN
int
10000
Minimum amount of aggregated tokens swaps per transaction, expressed in basket token
$SWAPS_MAX
int
10000
Maximum cumulative daily amount of aggregated tokens swaps, expressed in basket token
$SWAP_FEE
float
0.0015
Percentage fee to be paid for swapping tokens. Decimal from 0 to 1, default 0.0015 (0.15%)
$SLIPPAGE_FEE_MIN
float
0.0015
Minimum percentage to be paid as penalty for disbalancing the basket. Decimal from 0 to 1, default 0.0015 (0.15%)
$BASKET_ID
int
1
Unique ID of the basket, automatically assigned at creation
$DEPOSIT_AMOUNTS
[]sdk.Coin
20000uusdc,20000uusdt
Coin denomination and amount to be deposited. Single entry or comma separated list in the format <amount><denom>
$REDEMPTION
sdk.Coin
40000b1_usd
Amount of basket token to be redeemed (burned) against some aggregated tokens in the format <amount><denom>
$IN_AMOUNT
sdk.Coin
1000uusdt
Amount of a given aggregated token to be swapped against an other in the format <amount><denom>
$OUT_DENOM
string
uusdc
Denomination of the targeted aggregated token to be swapped against
$TOKENS
[]sdk.Coin
20000uusdc,20000uusdt
N/A
$RECEIVER
string
kira1psu….
Account address destination of the surplus withdrawal
Create and edit baskets
The proposal-create-basket command can be used by accounts with permission 🟢59 to create a token basket through a proposal process. To vote on the proposal, an account must have permission 🟢60.
Bash
Copy
sekaid tx basket proposal-create-basket \ --from=$SIGNER $FLAGS_TX \ --title=$TITLE --description=$DESCRIPTION \ --basket-suffix=$BASKET_SUFFIX --basket-description=$BASKET_DESCRIPTION \ --basket-tokens=$BASKET_TOKENS --tokens-cap=$TOKENS_CAP --limits-period=$LIMITS_PERIOD \ --mints-disabled=$MINTS_DISABLED \ --mints-min=$MINTS_MIN --mints-max=$MINTS_MAX \ --burns-disabled=$BURNS_DISABLED \ --burns-min=$BURNS_MIN --burns-max=$BURNS_MAX \ --swaps-disabled=$SWAPS_DISABLED \ --swaps-min=$SWAPS_MIN --swaps-max=$SWAPS_MAX \ --swap-fee=$SWAP_FEE --slippage-fee-min=$SLIPPAGE_FEE_MIN
Subsequent editing of existing baskets are performed using proposal-edit-basket with the same governance permissions and by specifying the basket’s id $BASKET_ID.
Bash
Copy
sekaid tx basket proposal-edit-basket \ --from=$SIGNER $FLAGS_TX \ --title=$TITLE --description=$DESCRIPTION \ --basket-id=$BASKET_ID --basket-suffix=$BASKET_SUFFIX --basket-description=$BASKET_DESCRIPTION \ (....)
Deposit aggregated tokens
Depositing some aggregated tokens into the relevant basket is done using the mint-basket-tokens command and specifying the basket’s id $BASKET_ID.
Bash
Copy
sekaid tx basket mint-basket-tokens \ --from=$SIGNER $FLAGS_TX \ $BASKET_ID $DEPOSIT_AMOUNTS
Withdraw aggregated tokens
Withdrawing some aggregated tokens from the relevant basket is done using the burn-basket-tokens command and specifying the basket’s id $BASKET_ID. This command will burn the corresponding amount of basket token $REDEMPTION.
Bash
Copy
sekaid tx basket burn-basket-tokens \ --from=$SIGNER $FLAGS_TX \ $BASKET_ID $REDEMPTION
Swap aggregated tokens
Swapping between two aggregated tokens of a given basket is done using the swap-basket-tokens command.
Bash
Copy
sekaid tx basket burn-basket-tokens \ --from=$SIGNER $FLAGS_TX \ $BASKET_ID $IN_AMOUNT $OUT_DENOM
Disable deposits, withdrawals and swaps
Global basket abilities can be disabled at once with the disable-basket-deposits, disable-basket-withdraws and disable-basket-swaps commands which requires permission 61 and by providing the basket’s id $BASKET_ID.
Bash
Copy
sekaid tx basket disable-basket-deposits \ --from=$SIGNER $FLAGS_TX \ $BASKET_ID $MINTS_DISABLED
Claim derivatives basket rewards
Rewards accumulated by staking derivative baskets is done using the basket-claim-rewards command and specifying the basket’s id $BASKET_ID. Currently: basket-claim-rewards only registers the basket module as delegator to the corresponding pools. All rewards are accumulated in the surplus insurance fund. The $TOKENS argument is useless but must be provided with a value for the Msg to be sent.
Bash
Copy
sekaid tx basket basket-claim-rewards \ --from=$SIGNER $FLAGS_TX \ $TOKENS
Withdraw baskets insurance funds
The surplus insurance fund of one or multiple baskets can be withdrawn at once by governance using the basket-claim-rewards command and by specifying the basket’s ids $BASKET_IDS (which is a comma-separated list of $BASKET_ID) and specifying the receiving KIRA account address $RECEIVER.
Bash
Copy
sekaid tx basket basket-claim-rewards \ --from=$SIGNER $FLAGS_TX \ $BASKET_IDS $RECEIVER
Queries
List baskets using filters
Using the basket token denom B<ID>_<denom>
Bash
Copy
sekaid query basket token-basket-by-denom $DENOM $FLAGS_QR | jq
Using the basket ID
Bash
Copy
sekaid query basket token-basket-by-id $BASKET_ID $FLAGS_QR | jq
Using a list of aggregated tokens denom <denom>,... $DENOMS and specify whether the tokens should be staking derivatives or not by providing $IS_DERIVATIVE (true/false)
Bash
Copy
sekaid query basket token-baskets $DENOMS $IS_DERIVATIVE $FLAGS_QR | jq
List a baskets limits_period historical activity
List all historical mints (aggregated token deposits) made within the past limits_period. Note that any older activity is automatically deleted.
Bash
Copy
sekaid query basket historical-mints $BASKET_ID $FLAGS_QR | jq
List all historical burns (aggregated token withdrawals) made within the past limits_period. Note that any older activity is automatically deleted.
Bash
Copy
sekaid query basket historical-burns $BASKET_ID $FLAGS_QR | jq
List all historical swaps performed within the past limits_period. Note that any older activity is automatically deleted.
Bash
Copy
sekaid query basket historical-swaps $BASKET_ID $FLAGS_QR | jq