Documentation

Symmetry Funds SDK Documentation
Funds SDK can be installed using yarn or npm
yarn
npm
yarn add @symmetry-hq/funds-sdk
npm install @symmetry-hq/funds-sdk

Initializing the SDK & Other Tools

You can initialize the SDK by calling init() function.
You can also fetch supported tokens (that can be used with Symmetry) by calling getTokenInfoData()
import { FundsSDK } from "@symmetry-hq/funds-sdk";
let fundsSDK: FundsSDK = await FundsSDK.init(
// rpc connection
connection: Connection,
// wallet|Keypair (optional | can be provided later, using funds.setWallet
wallet: Wallet,
);
// Other functions you might need
// load list of Symmetry supported tokens
let tokens: TokenInfoData[] = fundsSdk.getTokenInfoData();
// set wallet if Wallet is not provided during init() function
fundsSdk.setWallet(wallet: Wallet);
// get tokenId(tokenId in symmetry supported tokens, used in FundParams) from it's mint address
let tokenId = fundsSdk.tokenIdFromMint("So11111111111111111111111111111111111111112");

Creating a Fund

To create a fund, createFund() needs to be called and CreateFundParams passed in
// CreateFundParams is an object containing the following information
let fundParams:CreateFundParams = {
hostPlatform: PublicKey, // Project integrating the SDK
hostPlatformFee: number, // Fee (bps) charged by the project integrating the SDK
manager: PublicKey, // Fund creator (User creating a fund / Project deploying a fund)
managerFee: number, // Fee bps charged by the fund creator (deposit fee)
activelyManaged: boolean, // true - actively managed fund, false - index fund
assetPool: number[], // array of assets (ids) that can be used to compose the fund
refilterInterval: number, // How often a fund refilter check gets triggered (in seconds)
reweightInterval: number, // How often fund reweigh check gets triggered (in seconds)
rebalanceInterval: number, // How often fund rebalancing check gets triggered (in seconds)
rebalanceThreshold: number, // (bps) How much composition assets need to deviate from target weights to trigger rebalancing
rebalanceSlippage: number, // (bps) Maxium slippage tolerance when rebalancing assets
lpOffsetThreshold: number, // (bps of rebalalanceThreshold) if an asset current weight is in range of targetWeight ± lpOffsetThreshold, it will be used to provide liquidity & earn LP fees
rules: {
filterBy: FilterType, // 0 - Fixed asset, 1 - Market Cap, 2 - Volume, 3 - Performance
filterDays: FilterTime, // 0 - Day, 1 - Week, 2 - Month, 3 - Quarter, 4 - Half a year, 5 - Year
sortBy: SortBy, // 0 - Filter by Top, 1 - Filter by bottom
totalWeight: number, // Relative weight of the rule compared to rest of the rules. (Sum = 100)
fixedAsset: number, // If filterBy = 0, asset id from getTokenInfoData()
numAssets: number, // Number of assets to be selected by the rule
weightBy: WeightType, // 0 - Fixed weight, 1 - Weigh by Market Cap, 2 - Weigh by Volume, 3 - Weigh by Performance
weightDays: WeightTime, // 0 - Day, 1 - Week, 2 - Month, 3 - Quarter, 4 - Half a year, 5 - Year
weightExpo: number, // Weigh the asset in the power of X (example: 0.5 means sqrt of weightBy value)
excludeAssets: number[] // Exclude specific assets (ids) when filtering (example: stablecoins)
}[], // An array of rules (each rule defines how a single or multiple assets are included & automated in the fund composition)
}
let fund: Fund = await fundsSdk.createFund(fundParams);
Lets go through an example implementation
In this example we'll create & deploy an actively managed fund with the following settings:
  • 0.1% Deposit Fee
  • BTC, ETH, SOL in the composition weighed by square root of their marketcaps
  • Refilter interval - 1 week
  • Reweigh interval - 1 day (target weights will update daily)
  • Rebalance interval - 2 hours (rebalancing check every 2 hours)
  • Rebalance Threshold - 5% (Trigger rebalancing if current weights deviate over 5% from their target weights)
  • Rebalance Slippage - 3% (3% slippage tolerance during rebalancing)
  • Liquidity Provision Threshold - 50% of Rebalance Threshold (liquidity is provided to dexes if asset weight is in 2.5% range of target weight)
import {
FundsSDK,
Fund,
BuyState,
FilterType,
FilterTime,
SortBy,
WeightType,
WeightTime
} from "@symmetry-hq/funds-sdk";
let wallet = // user wallet object
let connection = // rpc connection object
let PLATFORM_PUBKEY = // your platform public key
/* init funds sdk */
let fundsSDK: FundsSDK = await FundsSDK.init(
connection,
wallet
);
/* Create a fund (CreateFund + SetRules + Refilter&Reweight) */
let fund: Fund = await fundsSdk.createFund({
hostPlatform: PLATFORM_PUBKEY,
hostPlatformFee: 0,
manager: wallet.publicKey,
managerFee: 10, // fee in bps: 10 = 0.1%
activelyManaged: true, // actively managed
assetPool: [0, 1, 2, 26], // USDC, SOL, BTC, ETH (You can use fundsSdk.tokenIdFromMint() to get id by token mint address)
refilterInterval: 7 * 24 * 3600, // 1 week
reweightInterval: 24 * 3600, // 1 day
rebalanceInterval: 2 * 3600, // 2 hours
rebalanceThreshold: 500, // 5%
rebalanceSlippage: 300, // 3%
lpOffsetThreshold: 5000, // 50% of rebalance threshold
rules: [
{
filterBy: FilterType.MarketCap, // filter assets by marketcap
filterDays: FilterTime.Week, // 1 week average of marketcap
sortBy: SortBy.DescendingOrder, // select top coins by marketcap
totalWeight: 100, // 100 since this is the only rule
fixedAsset: 0,
numAssets: 3, // select 3 assets
weightBy: WeightType.Performace, // weigh by price performace
weightDays: WeightTime.Day, // 1 day performace
weightExpo: 0.5, // square root of performace
excludeAssets: [0] // Exclude USDC from the rule
}
]
});

Editing a Fund

After deploying a fund, you can edit it (if it's actively managed - activelyManaged: true) by passing a modified CreateFundsParam object
await fundsSdk.editFund(fund: Fund, params: CreateFundParams);
Example: Create a fund, then edit the fund with updated managerFee & assetPool
let fundParamsBefore = {
hostPlatform: PLATFORM_PUBKEY,
hostPlatformFee: 0,
manager: wallet.publicKey,
managerFee: 10, // fee in bps: 10 = 0.1%
activelyManaged: true, // actively managed
assetPool: [0, 1, 2, 26], // USDC, SOL, BTC, ETH
refilterInterval: 7 * 24 * 3600, // 1 week
reweightInterval: 24 * 3600, // 1 day
rebalanceInterval: 2 * 3600, // 2 hours
rebalanceThreshold: 500, // 5%
rebalanceSlippage: 300, // 3%
lpOffsetThreshold: 5000, // 50% of rebalance threshold
rules: [
{
filterBy: FilterType.MarketCap, // filter assets by marketcap
filterDays: FilterTime.Week, // 1 week average of marketcap
sortBy: SortBy.DescendingOrder, // select top coins by marketcap
totalWeight: 100, // 100 since this is the only rule
fixedAsset: 0,
numAssets: 3, // select 3 assets
weightBy: WeightType.Performace, // weigh by price performace
weightDays: WeightTime.Day, // 1 day performace
weightExpo: 0.5, // square root of performace
excludeAssets: [0] // Exclude USDC from the rule
}
]
}
let fund: Fund = await fundsSdk.createFund(fundParamsBefore);
let fundParamsAfter = {
hostPlatform: PLATFORM_PUBKEY,
hostPlatformFee: 0,
manager: wallet.publicKey,
managerFee: 20, // changed to 0.2%
activelyManaged: true,
assetPool: [0, 1, 2, 26, 9], // added FTT
refilterInterval: 7 * 24 * 3600,
reweightInterval: 24 * 3600,
rebalanceInterval: 2 * 3600,
rebalanceThreshold: 500,
rebalanceSlippage: 300,
lpOffsetThreshold: 5000,
rules: [
{
filterBy: FilterType.MarketCap,
filterDays: FilterTime.Week
sortBy: SortBy.DescendingOrder,
totalWeight: 100,
fixedAsset: 0,
numAssets: 3,
weightBy: WeightType.Performace,
weightDays: WeightTime.Day,
weightExpo: 0.5,
excludeAssets: [0]
}
]
}
let editedFund:Fund = await fundsSdk.editFund(fund, params: fundParamsAfter);

Loading a Fund

You can also load a fund to:
  • Change fund settings (if wallet provided during init is the fund creator)
  • See it's composition & settings
  • Buy / Sell fund tokens
There are 2 ways to load a fund
  1. 1.
    Load with a fund public key
let fund: Fund = await fundsSDK.loadFromPubkey(pubkey: PublicKey);
2. Load list of funds filtered by a public key of a fund creator or a host platform
let funds: Fund[] = await fundsSDK.findFunds(filters: FilterOption[]);
// Example
let funds: Fund[] = await fundsSDK.findFunds([{
filterType: "manager"|"host",
filterPubkey: PublicKey
}]);

Buying a Fund

To buy a fund, the following actions need to happen:
  1. 1.
    SDK creates a buy state
  2. 2.
    User transfers the USDC to the buy state
After the above, there are 2 options.
First Option - After USDC is transferred to the buy state, you can rebalance buy state (which converts USDC to underlying assets) and then call mintFund() function which mints fund tokens to the buyer.
Second Option - You can mint fund tokens to the buyer without purchasing the underlying assets first: in this case, sdk will calculate the value of contributed USDC by checking the oracle, and mint the fund tokens with the value * (100 - fund rebalancing slippage tolerance) This happens to protect the existing fund holders from dilution, because the tokens are minted before buyer's contribution is converted to underlying assets (which might be less due to slippage, conversion fees, etc).
By choosing Second Option, USDC will be directly added to the fund composition, and it will be converted to underlying assets over time by providing liquidity to DEXes. This means it will earn additional 0.05% of USDC_AMOUNT as an LP fee and add it to the composition.
// Create a Buy State
let buyState: BuyState = await fundsSdk.buyFund(fund: Fund, usdcAmount: number);
// First Option. If you're choosing second option, skip this step
let txs: TransactionSignature[] = await fundsSdk.rebalanceBuyState(buyState);
// Mint Fund tokens to the buyer
let tx: TransactionSignature = await fundsSdk.mintFund(buyState);

Finding Active Buy States for a User

If a user already has a buy state, you can retrieve it by calling findActiveBuyStates() function
let buyStates: BuyState[] = await fundsSdk.findActiveBuyStates(user: PublicKey);

Selling a Fund

Similarly to a Buy state, when selling a fund, we need to create a Sell State
This creates a new state & transfers underlying assets corresponding to the number of fund tokens user is selling to the new sell state.
let sellState: Fund = await fundsSdk.sellFund(fund: Fund, amountOfFundTokens: number, rebalance: boolean);
When calling sellFund() function, you can sell fund tokens & claim in two ways:
First Option - Convert underlying assets to USDC and transfer USDC to the seller by passing rebalance parameter as true
Second Option - Transfer underlying assets directly to the seller by passing rebalance parameter as false
After the sell state is created, if you chose the first option (to convert assets to USDC before transferring to the user), Symmetry cranker will rebalance them to USDC. Alternatively, you can force trigger rebalancing by calling rebalanceFund() and passing in the sellState.
let rebalanceTx: TransactionSignature[] = await fundsSdk.rebalanceFund(sellState: Fund);
Last step is to claim the underlying tokens (which transfers assets from sellState to user's wallet)
let claimTx: TransactionSignature[] = await fundsSdk.claimTokens(sellState: Fund);

Finding Active Sell States for a User

To find active sellStates for a user, you can call findActiveSellStates() like shown below:
let sellStates: Fund[] = await fundsSdk.findActiveSellStates(user: PublicKey);

Automation

Automation on all funds (Refilter/Reweight/Rebalance), as well as monitoring
active Buy/Sell states and rebalancing them is done by Symmetry Engine.
Platforms and Developers can run their own automation for their funds

Swap using Symmetry Funds Liquidity

Users can swap and check available swap liquidity for a specific fund
Find out more at (npm) @symmetry-hq/liquidity-sdk or check out Liquidity SDK