@symmetry-hq/baskets-sdk
Version:
Software Development Kit for interacting with Symmetry Baskets Program
974 lines (907 loc) • 35.3 kB
text/typescript
import {
AddressLookupTableAccount,
ComputeBudgetProgram,
Connection,
GetProgramAccountsFilter,
Keypair,
PublicKey,
SystemProgram,
Transaction,
TransactionInstruction,
TransactionMessage,
TransactionSignature,
VersionedTransaction,
} from "@solana/web3.js";
import {
AnchorProvider,
Program,
Wallet,
BN,
Idl,
} from "@coral-xyz/anchor";
import { IDL, BasketsIDL } from "./basketsIDL";
import { Basket } from "./basketState";
import {
CreateBasketParams,
DATABASE_ADDESS,
FilterOption,
BasketError,
BASKETS_PROGRAM_ID,
BASKETS_PROGRAM_PDA,
TokenSettings,
TOKEN_LIST_ADDRESS,
ADDITIONAL_FEE,
SimpleEditParams,
SimpleCreateParams,
Side,
ADDITIONAL_UNITS,
SWB_PID,
BASKETS_LOOKUP_TABLE_1,
BASKETS_LOOKUP_TABLE_2,
TransactionToSend,
} from "./config";
import { confirmTransaction, delay, fetchTokenList, generateJupSwapInstruction, generateJupTxData, getAddressLookupTableAccounts, getCurrentComposition, getFilteredProgramAccounts, getOraclePrices, sendSignedTransactions, signTransactionsWithWallet, signVersionedTransactions, tryMetadata } from "./utils";
import { BuyState } from "./buyState";
import { simulate } from "./simulation";
import { TOKEN_PROGRAM_ID } from "./splTokenHelpers";
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
import { buildDepositAfterRebalanceIx, buildUpdateCurrentWeightsIx, buildWithdrawBeforeRebalanceIx, updateOraclesTxs } from "./instructionsBuilder";
import { buildRebalanceTransactions, calculateRebalanceAmounts, getConfirmedTimestamp, getFlashRebalanceInfo, getJupiterSwapData, getLookupTableAccount, getSortedRebalanceInfo, isForceRebalanceNeeded, shouldProcessRebalance, signAndSendTransactions } from "./flashRebalance";
export * as BasketInstructions from "./basketInstructions";
export * from "./config";
export * from "./basketState";
export * from "./buyState";
export * from "./utils";
export * from "./basketsIDL";
export class BasketsSDK {
private connection: Connection;
private program: Program<BasketsIDL>;
private swbProgram: Program;
private swbIDL: Idl;
private tokenList: TokenSettings[];
private lookups: AddressLookupTableAccount[];
private wallet?: Wallet;
private lamports: number;
private jupAPIkey: string = "https://quote-api.jup.ag/v6/";
constructor(
connection: Connection,
program: Program<BasketsIDL>,
swbProgram: Program,
swbIDL: Idl,
tokenList: TokenSettings[],
lookups: AddressLookupTableAccount[],
wallet?: Wallet
) {
this.connection = connection;
this.wallet = wallet;
this.program = program;
this.swbProgram = swbProgram;
this.swbIDL = swbIDL;
this.tokenList = tokenList;
this.lamports = ADDITIONAL_FEE;
this.lookups = lookups;
}
static async init(
connection: Connection,
wallet?: Wallet,
): Promise<BasketsSDK> {
let provider = new AnchorProvider(
connection,
wallet ? wallet : new NodeWallet(Keypair.generate()),
{
skipPreflight: true,
preflightCommitment: "recent",
commitment: "processed",
}
);
// const symmetryEngineIDL: BasketsIDL = (await Program.fetchIdl(BASKETS_PROGRAM_ID, provider))!;
let program = new Program<BasketsIDL>(IDL, provider);
let swbIDL = (await Program.fetchIdl(SWB_PID, provider))!;
let swbProgram = new Program(swbIDL, provider);
let tokenList = await fetchTokenList(program);
let lookups = await Promise.all([
getLookupTableAccount(program.provider.connection, BASKETS_LOOKUP_TABLE_1),
getLookupTableAccount(program.provider.connection, BASKETS_LOOKUP_TABLE_2)
]);
return new BasketsSDK(
connection,
program,
swbProgram,
swbIDL,
tokenList,
lookups,
wallet,
)
}
setWallet(wallet: Wallet) {
this.wallet = wallet;
let provider = new AnchorProvider(
this.connection,
wallet,
{
skipPreflight: true,
preflightCommitment: "recent",
commitment: "recent",
}
)
this.program = new Program<BasketsIDL>(IDL, provider);
this.swbProgram = new Program(this.swbIDL, provider);
}
setPriorityFee(lamports: number) {
this.lamports = lamports;
}
setJupAPIKey(apiKey: string) {
this.jupAPIkey = apiKey;
}
async loadFromPubkey(pubkey: PublicKey): Promise<Basket> {
return await Basket.loadFromPubkey(
this.program,
pubkey
);
}
async getCurrentCompositions(baskets: Basket[]): Promise<any> {
let oraclePriceData = await getOraclePrices(this.program, this.tokenList);
let parsed = baskets.map(basket => getCurrentComposition(basket, this.tokenList, oraclePriceData));
await Promise.all(parsed.map(x => tryMetadata(x))).then(metadatas => {
for (let i = 0; i < parsed.length; i++)
parsed[i].metadata = metadatas[i];
})
return parsed;
}
async findBaskets(filters: FilterOption[]): Promise<Basket[]> {
let accountFilters: GetProgramAccountsFilter[] = [{dataSize: 10208}];
accountFilters.push({memcmp: {
offset: 112,
bytes: "11111111"
}})
accountFilters = [...accountFilters, ...filters.map(filter => {
return {
memcmp: {
offset: (filter.filterType == "host") ? 128 : 16,
bytes: filter.filterPubkey.toBase58(),
}
}
})];
let accounts = await getFilteredProgramAccounts(
this.connection,
accountFilters
).catch((e) => {console.log(e); return [];});
return accounts
.map(account => Basket.loadFromRawData(this.program, account))
}
async findActiveSellStates(user: PublicKey): Promise<Basket[]> {
let accounts = await getFilteredProgramAccounts(
this.connection,
[
{ dataSize: 10208 },
{ memcmp: {
offset: 16,
bytes: user.toBase58()
}},
{ memcmp: {
offset: 112,
bytes: "Ahg1opVcGX",
}},
]
);
return accounts
.map(account => Basket.loadFromRawData(this.program, account))
}
async findActiveBuyStates(user: PublicKey): Promise<BuyState[]> {
let accounts = await getFilteredProgramAccounts(
this.connection,
[
{ dataSize: 680 },
{ memcmp: {
offset: 40,
bytes: user.toBase58()
}}
]
);
return await BuyState.loadMultiple(this.program, accounts);
}
async fetchAllBuyStates(filters: FilterOption[]): Promise<BuyState[]> {
let accountFilters: GetProgramAccountsFilter[] = [{ dataSize: 680 }];
accountFilters = [...accountFilters, ...filters.map(filter => {
return {
memcmp: {
offset: (filter.filterType == "host") ? 104 : 72,
bytes: filter.filterPubkey.toBase58(),
}
}
})];
let accounts = await getFilteredProgramAccounts(
this.connection,
accountFilters
);
return await BuyState.loadMultiple(this.program, accounts);
}
async fetchBuyStateFromPubkey(pubkey: PublicKey): Promise<BuyState> {
return await BuyState.loadFromPubkey(this.program, pubkey);
}
async fetchAllSellStates(filters: FilterOption[]): Promise<Basket[]> {
let accountFilters: GetProgramAccountsFilter[] = [{ dataSize: 10208 }];
accountFilters.push({memcmp: {
offset: 112,
bytes: "Ahg1opVcGX"
}})
accountFilters = [...accountFilters, ...filters.map(filter => {
return {
memcmp: {
offset: (filter.filterType == "host") ? 128 : 16,
bytes: filter.filterPubkey.toBase58(),
}
}
})];
let accounts = await getFilteredProgramAccounts(
this.connection,
accountFilters
);
return accounts
.map(account => Basket.loadFromRawData(this.program, account))
}
async fetchAllHoldings(user: PublicKey): Promise<{basketAddress: string, mint: string, balance: number, basketData: any}[]> {
let tokenAccountsRaw = await this.connection.getTokenAccountsByOwner(
new PublicKey(user),
{ programId: new PublicKey(TOKEN_PROGRAM_ID) },
"processed"
);
let tokenAccountsDecoded = tokenAccountsRaw.value.map(account => {
return {
mint: new PublicKey(account.account.data.slice(0,32)),
balance: parseInt(new BN(account.account.data.slice(64, 72), "le").toString()),
}
});
let basketsRaw = await getFilteredProgramAccounts(
this.connection,
[
{dataSize: 10208},
{
memcmp: {
offset: 112,
bytes: "11111111"
}
}
]
);
let basketsDecoded = basketsRaw.map(account => {
return {
decoded: this.program.coder.accounts.decode("fundState", account.account.data),
pubkey: account.pubkey
}
});
let basketHoldings = [];
for (let i = 0; i < basketsDecoded.length; i++) {
let ataIndex = tokenAccountsDecoded
.findIndex(x => x.mint.toBase58() == basketsDecoded[i].decoded.fundToken.toBase58());
if (ataIndex == -1) continue;
basketHoldings.push({
basketAddress: basketsDecoded[i].pubkey.toBase58(),
mint: basketsDecoded[i].decoded.fundToken.toBase58(),
balance: tokenAccountsDecoded[ataIndex].balance / 10 ** 6,
basketData: basketsDecoded[i].decoded,
})
}
return basketHoldings;
}
getTokenListData(): TokenSettings[] {
return this.tokenList.filter(x => x.isLive == true);
}
tokenIdFromMint(tokenMint: string): number {
for (let i = 0; i < this.tokenList.length; i++)
if (this.tokenList[i].tokenMint == tokenMint)
return this.tokenList[i].id;
throw new BasketError("Token not supported by Symmetry Engine")
}
async createBasket(createBasketParams: SimpleCreateParams): Promise<Basket> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await Basket.create(
this.program,
this.connection,
this.wallet,
this.tokenList,
this.lookups,
createBasketParams,
this.lamports,
)
}
async simulateBasket(createBasketParams: CreateBasketParams, simulationDays: number) {
return await simulate(
this.program,
DATABASE_ADDESS,
TOKEN_LIST_ADDRESS,
createBasketParams,
simulationDays
)
}
async editBasket(basket: Basket, editBasketParams: SimpleEditParams): Promise<TransactionSignature> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await basket.edit(
this.program,
this.connection,
this.wallet,
this.tokenList,
this.lookups,
editBasketParams,
this.lamports,
)
}
async setMetadata(basket: Basket, symbol: string, name: string, uri: string = ""): Promise<TransactionSignature> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await basket.setMetaData(
this.program,
this.wallet,
symbol,
name,
uri,
this.lamports,
)
}
async editManager(
basket: Basket,
newManager: PublicKey,
): Promise<TransactionSignature> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await basket.editManager(
this.program,
this.connection,
this.wallet,
newManager,
this.lamports,
)
}
// async simpleEditBasket(
// basket: Basket,
// basketParams: SimpleEditParams,
// ): Promise<TransactionSignature[]> {
// if (!this.wallet)
// throw new BasketError("Wallet not provided");
// return await basket.simpleEdit(
// this.program,
// this.connection,
// this.wallet,
// this.tokenList,
// basketParams,
// this.lamports,
// )
// }
async closeBasket(basket: Basket): Promise<TransactionSignature> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await basket.close(this.program, this.wallet, this.lamports);
}
async refilterBasketInstruction(basket: Basket): Promise<TransactionInstruction> {
//@ts-ignore
return await refilterInstruction(this.program, basket.ownAddress, this.wallet?.publicKey);
}
// async refilterBasket(basket: Basket): Promise<TransactionSignature> {
// if (!this.wallet)
// throw new BasketError("Wallet not provided");
// return await basket.refilter(
// this.program,
// this.wallet,
// this.lamports,
// );
// }
async reweightBasketInstruction(basket: Basket): Promise<TransactionInstruction> {
//@ts-ignore
return await reweightInstruction(this.program, basket.ownAddress, this.wallet?.publicKey);
}
// async reweightBasket(basket: Basket): Promise<TransactionSignature> {
// if (!this.wallet)
// throw new BasketError("Wallet not provided");
// return await basket.reweight(
// this.program,
// this.wallet,
// this.lamports,
// );
// }
// async rebalanceBasketToken(
// basket: Basket,
// token: PublicKey,
// updateOracles: boolean = true,
// ): Promise<TransactionSignature> {
// let oraclePriceData = await getOraclePrices(this.program, this.tokenList);
// //@ts-ignore
// let tokenSettings: TokenSettings = this.tokenList.find(x => x.tokenMint == token.toBase58());
// if (!this.wallet)
// throw new BasketError("Wallet not provided");
// if (!tokenSettings)
// throw new BasketError("Token not supported");
// let timestamp = await this.connection.getBlockTime(
// await this.connection.getSlot("finalized")
// ).catch((e) => null);
// let rebalanceInfos = basket.getRebalanceInfo(
// this.program,
// this.tokenList,
// oraclePriceData,
// timestamp ? timestamp : 2000000000,
// (this.wallet.publicKey.equals(basket.data.manager) && basket.data.activelyManaged.toNumber() == 1)
// );
// let rebalanceInfo = rebalanceInfos.find(info => info.tokenId == tokenSettings.id);
// if (!rebalanceInfo)
// throw new BasketError("Token not in composition");
// let jupSwapData = await generateJupSwapInstruction(
// rebalanceInfo,
// basket.data.rebalanceSlippage.toNumber(),
// this.connection,
// rebalanceInfo.side == Side.To ?
// oraclePriceData[rebalanceInfo.tokenId] / 10 ** this.tokenList[rebalanceInfo.tokenId].decimals :
// oraclePriceData[0] / 10 ** this.tokenList[0].decimals,
// rebalanceInfo.side == Side.From ?
// oraclePriceData[rebalanceInfo.tokenId] / 10 ** this.tokenList[rebalanceInfo.tokenId].decimals :
// oraclePriceData[0] / 10 ** this.tokenList[0].decimals,
// rebalanceInfo.tokenId == 48 ? this.tokenList[5].tokenMint : this.tokenList[1].tokenMint,
// rebalanceInfo.tokenId == 48 ? this.tokenList[5].pdaTokenAccount : this.tokenList[1].pdaTokenAccount,
// this.jupAPIkey,
// ).catch((e) => {console.log("JUP SWAP DATA", e.message); return null;})
// if (!jupSwapData)
// throw new BasketError("Couldn't load quote.");
// return await basket.rebalanceSingle(
// this.program,
// this.wallet,
// this.tokenList,
// jupSwapData,
// rebalanceInfo,
// this.lamports,
// updateOracles
// )
// }
async rebalanceBasket(basket: Basket, updateOracles: boolean = true): Promise<TransactionSignature[]> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
let [oraclePriceData, timestamp, updateOraclesTxData] = await Promise.all([
getOraclePrices(this.program, this.tokenList),
getConfirmedTimestamp(this.connection, basket),
updateOracles ? updateOraclesTxs(
this.swbProgram,
this.wallet.publicKey,
basket.getSwbFeeds(this.tokenList),
this.lamports,
) : []
]);
let rebalanceInfos = basket.getRebalanceInfo(
this.program,
this.tokenList,
oraclePriceData,
timestamp ? timestamp : 2000000000,
(this.wallet.publicKey.equals(basket.data.manager) && basket.data.activelyManaged.toNumber() == 1)
);
let jupSwapDatas = await Promise.all(
rebalanceInfos.map(rebalanceInfo =>
generateJupSwapInstruction(
rebalanceInfo,
basket.data.rebalanceSlippage.toNumber(),
this.connection,
rebalanceInfo.side == Side.To ?
oraclePriceData[rebalanceInfo.tokenId] / 10 ** this.tokenList[rebalanceInfo.tokenId].decimals :
oraclePriceData[0] / 10 ** this.tokenList[0].decimals,
rebalanceInfo.side == Side.From ?
oraclePriceData[rebalanceInfo.tokenId] / 10 ** this.tokenList[rebalanceInfo.tokenId].decimals :
oraclePriceData[0] / 10 ** this.tokenList[0].decimals,
rebalanceInfo.tokenId == 48 ? this.tokenList[5].tokenMint : this.tokenList[1].tokenMint,
rebalanceInfo.tokenId == 48 ? this.tokenList[5].pdaTokenAccount : this.tokenList[1].pdaTokenAccount,
this.jupAPIkey,
).catch((e) => {console.log("JUP SWAP DATA", e.message); return null;})
)
);
let txsToSend: TransactionToSend[] = updateOraclesTxData;
let updates = txsToSend.length;
await basket.rebalanceTo(
this.program,
this.wallet,
this.tokenList, //@ts-ignore
jupSwapDatas,
rebalanceInfos,
this.lookups,
this.lamports,
).then(result => txsToSend.push(...result));
let toSwaps = txsToSend.length - updates;
if (basket.data.sellState.toNumber() == 0)
await basket.rebalanceFrom(
this.program,
this.wallet,
this.tokenList, //@ts-ignore
jupSwapDatas,
rebalanceInfos,
this.lookups,
this.lamports,
).then(result => txsToSend.push(...result));
let blockhash = (await this.connection.getLatestBlockhash("confirmed")).blockhash;
let signedTransactions = await signVersionedTransactions(
this.wallet,
txsToSend.map(tx => new VersionedTransaction(
new TransactionMessage({
payerKey: tx.payerKey,
recentBlockhash: blockhash,
instructions: tx.instructions,
}).compileToV0Message(tx.lookupTables)
))
);
let updateTxs = await sendSignedTransactions(
this.connection,
signedTransactions.slice(0, updates),
1,
);
let rebalanceTo = await sendSignedTransactions(
this.connection,
signedTransactions.slice(updates, updates + toSwaps),
0,
);
let rebalanceFrom = await sendSignedTransactions(
this.connection,
signedTransactions.slice(updates + toSwaps, signedTransactions.length),
0,
);
let resultTxs = [...updateTxs, ...rebalanceFrom, ...rebalanceTo];
if (resultTxs.length > 0)
await confirmTransaction(this.connection, resultTxs[resultTxs.length - 1]).catch(() => {});
return resultTxs;
}
async updateAllSwbOracles() {
if (!this.wallet) {
throw new BasketError("Wallet not provided");
}
let feeds: PublicKey[] = [];
for (let i = 0; i < this.tokenList.length; i++)
if (this.tokenList[i].oracleType == "SwbOnDemand")
feeds.push(new PublicKey(this.tokenList[i].oracleAccount));
let txsToSend = await updateOraclesTxs(
this.swbProgram,
this.wallet.publicKey,
feeds,
this.lamports,
);
return signAndSendTransactions(txsToSend, this.connection, this.wallet, 0);
}
async rebalanceCronJob(
basket: Basket,
updateOracles: boolean = true,
maxAllowedAccounts: number = 45,
softCap: number = 5,
hardCap: number = 5000,
underTokens: number = 3,
overTokens: number = 3,
): Promise<TransactionSignature[]> {
if (!this.wallet) {
throw new BasketError("Wallet not provided");
}
const [oraclePriceData, timestamp, updateOraclesTxData] = await Promise.all([
getOraclePrices(this.program, this.tokenList),
getConfirmedTimestamp(this.connection, basket),
updateOracles ? updateOraclesTxs(
this.swbProgram,
this.wallet.publicKey,
basket.getSwbFeeds(this.tokenList),
this.lamports,
) : []
]);
const forceRebalance = isForceRebalanceNeeded(basket, this.wallet.publicKey);
const rebalanceInfos = getSortedRebalanceInfo(basket, oraclePriceData, timestamp, this.tokenList);
const txsToSend = await buildRebalanceTransactions(
basket,
rebalanceInfos,
oraclePriceData,
forceRebalance,
this.lookups,
maxAllowedAccounts,
this.wallet.publicKey,
this.connection,
this.program,
this.tokenList,
this.lamports,
updateOraclesTxData,
softCap,
hardCap,
underTokens,
overTokens,
this.jupAPIkey,
);
return signAndSendTransactions(txsToSend, this.connection, this.wallet, updateOracles == true ? 1 : 0);
}
async filterCronJobBaskets(allBaskets: Basket[], softCap: number = 10): Promise<Basket[]> {
const timestamp = Date.now() / 1000;
const oraclePriceData = await getOraclePrices(this.program, this.tokenList);
let basketsToRebalance = [];
for (let i = 0; i < allBaskets.length; i++) {
let basket = allBaskets[i];
let possibleRebalances = 0;
if (basket.data.disableRebalance.toNumber() == 1) continue;
let rebalanceInfos = getSortedRebalanceInfo(
basket,
oraclePriceData,
timestamp,
this.tokenList
);
for (const over of rebalanceInfos.over) {
for (const under of rebalanceInfos.under) {
if (!shouldProcessRebalance(over, under, false)) continue;
const { from, to, tokenAmount, value } = calculateRebalanceAmounts(
over,
under,
oraclePriceData,
this.tokenList,
10000,
);
if (value <= softCap) continue;
possibleRebalances += 1;
}
}
if (possibleRebalances > 0)
basketsToRebalance.push(basket)
}
return basketsToRebalance;
}
async buyBasket(basket: Basket, amountUsdc: number): Promise<BuyState> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await BuyState.createNew(
this.program,
this.wallet,
this.tokenList,
basket,
amountUsdc,
this.lamports,
)
}
async getOraclePrices(): Promise<number[]> {
let oraclePrices = await getOraclePrices(this.program, this.tokenList);
return oraclePrices;
}
async computeMintAmountWithMultipleTokens(basket: Basket, contribution: {token: PublicKey, amount: number}[]): Promise<number> {
let oraclePrices = await getOraclePrices(this.program, this.tokenList);
let amount = BuyState.computeMintAmountWithMultipleTokens(
this.tokenList,
basket,
contribution,
oraclePrices
);
return amount;
}
// async buyBasketWithMultipleTokens(
// basket: Basket,
// contribution: {token: PublicKey, amount: number}[],
// updateOracles: boolean = true,
// ): Promise<TransactionSignature> {
// if (!this.wallet)
// throw new BasketError("Wallet not provided");
// return await BuyState.multipleTokensDeposit(
// this.program,
// this.wallet,
// this.tokenList,
// basket,
// contribution,
// this.lamports,
// updateOracles,
// );
// }
async computeMintAmountWithSingleToken(basket: Basket, token: PublicKey, amount: number): Promise<number> {
let oraclePrices = await getOraclePrices(this.program, this.tokenList);
let tokenSettings = this.tokenList.find(x => x.tokenMint == token.toBase58());
if (!tokenSettings)
throw new BasketError("Token not in composition");
let exp = BuyState.computeMintAmountWithSingleToken(
this.tokenList,
basket,
tokenSettings,
amount,
oraclePrices
);
return exp;
}
async buyWithSingleToken(
basket: Basket,
token: PublicKey,
amount: number,
updateOracles: boolean = true,
): Promise<TransactionSignature> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await BuyState.singleTokenDeposit(
this.program,
this.wallet,
this.tokenList,
basket,
token,
amount,
this.lamports,
updateOracles,
);
}
async rebalanceBuyState(
buyState: BuyState,
updateOracles: boolean = true,
): Promise<TransactionSignature[]> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
let [oraclePriceData, updateOraclesTxData] = await Promise.all([
await getOraclePrices(this.program, this.tokenList),
updateOracles ? updateOraclesTxs(
this.swbProgram,
this.wallet.publicKey,
buyState.basket.getSwbFeeds(this.tokenList),
this.lamports,
) : []
]);
let rebalanceInfos = buyState.getBuyStateRebalanceInfo(this.tokenList);
let jupSwapDatas = await Promise.all(
rebalanceInfos.map(rebalanceInfo =>
generateJupSwapInstruction(
rebalanceInfo,
buyState.basket.data.rebalanceSlippage.toNumber(),
this.connection,
rebalanceInfo.side == Side.To ?
oraclePriceData[rebalanceInfo.tokenId] / 10 ** this.tokenList[rebalanceInfo.tokenId].decimals :
oraclePriceData[0] / 10 ** this.tokenList[0].decimals,
rebalanceInfo.side == Side.From ?
oraclePriceData[rebalanceInfo.tokenId] / 10 ** this.tokenList[rebalanceInfo.tokenId].decimals :
oraclePriceData[0] / 10 ** this.tokenList[0].decimals,
rebalanceInfo.tokenId == 48 ? this.tokenList[5].tokenMint : this.tokenList[1].tokenMint,
rebalanceInfo.tokenId == 48 ? this.tokenList[5].pdaTokenAccount : this.tokenList[1].pdaTokenAccount,
this.jupAPIkey
).catch((e) => {console.log("JUP SWAP DATA", e.message); return null;})
)
);
return await buyState.rebalanceBuyState(
this.program,
this.wallet,
this.tokenList, //@ts-ignore
jupSwapDatas,
this.lamports,
updateOraclesTxData,
this.lookups,
);
}
async mintBasket(
buyState: BuyState,
updateOracles: boolean = true,
): Promise<TransactionSignature[]> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await buyState.mint(
this.program,
this.swbProgram,
this.wallet,
this.tokenList,
this.lookups,
this.lamports,
updateOracles,
);
}
// async sellBasketToSingleToken(
// basket: Basket,
// withdrawToken: PublicKey,
// amount: number,
// updateOracles: boolean = true,
// ): Promise<TransactionSignature> {
// if (!this.wallet)
// throw new BasketError("Wallet not provided");
// return await basket.sellBasketToSingleToken(
// this.program,
// this.wallet,
// this.tokenList,
// withdrawToken,
// amount,
// this.lamports,
// updateOracles,
// )
// }
async computeOutputAmountWithSingleToken(basket: Basket, withdrawToken: PublicKey, amount: number): Promise<number> {
let oraclePrices = await getOraclePrices(this.program, this.tokenList);
let tokenSettings = this.tokenList.find(x => x.tokenMint == withdrawToken.toBase58());
if (!tokenSettings)
throw new BasketError("Token not in composition");
let exp = basket.computeOutputAmountWithSingleToken(
oraclePrices,
this.tokenList,
tokenSettings,
amount,
);
return exp;
}
async sellBasket(basket: Basket, amount: number, rebalance: number): Promise<Basket> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await basket.sell(
this.program,
this.wallet,
amount,
rebalance,
this.lamports,
)
}
async claimTokensFromBuyState(buyState: BuyState): Promise<TransactionSignature[]> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await buyState.claimTokens(
this.program,
this.wallet,
this.tokenList,
this.lamports,
)
}
async claimTokens(basket: Basket): Promise<TransactionSignature[]> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
return await basket.claimTokens(
this.program,
this.wallet,
this.tokenList,
this.lamports,
)
}
async removeDust(
basket: Basket,
updateOracles: boolean = true,
): Promise<TransactionSignature[]> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
let oraclePriceData = await getOraclePrices(this.program, this.tokenList);
return await basket.removeDust(
this.program,
this.wallet,
this.tokenList,
oraclePriceData,
this.lamports,
updateOracles,
);
}
async freezeProgram(): Promise<TransactionSignature> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
let transaction = new Transaction();
transaction = transaction.add(
await this.program.methods.freezeProgram().accounts({
owner: this.wallet?.publicKey,
tokenList: TOKEN_LIST_ADDRESS,
systemProgram: SystemProgram.programId,
}).instruction()
);
transaction = transaction.add(
ComputeBudgetProgram.setComputeUnitLimit({units: ADDITIONAL_UNITS})
).add(
ComputeBudgetProgram.setComputeUnitPrice({microLamports: this.lamports})
);
let signedTransactions = await signTransactionsWithWallet(
this.program.provider.connection,
this.wallet,
[{transaction: transaction, signers: []}]
);
return (await sendSignedTransactions(
this.program.provider.connection,
signedTransactions,
1
))[0]
}
async unfreezeProgram(): Promise<TransactionSignature> {
if (!this.wallet)
throw new BasketError("Wallet not provided");
let transaction = new Transaction();
transaction = transaction.add(
await this.program.methods.unfreezeProgram().accounts({
owner: this.wallet?.publicKey,
tokenList: TOKEN_LIST_ADDRESS,
systemProgram: SystemProgram.programId,
}).instruction()
);
transaction = transaction.add(
ComputeBudgetProgram.setComputeUnitLimit({units: ADDITIONAL_UNITS})
).add(
ComputeBudgetProgram.setComputeUnitPrice({microLamports: this.lamports})
);
let signedTransactions = await signTransactionsWithWallet(
this.program.provider.connection,
this.wallet,
[{transaction: transaction, signers: []}]
);
return (await sendSignedTransactions(
this.program.provider.connection,
signedTransactions,
1
))[0]
}
}