Merge branch 'main' into feat/squads_multisig

This commit is contained in:
A91y
2025-01-08 22:58:50 +05:30
65 changed files with 10161 additions and 320 deletions

View File

@@ -1,37 +0,0 @@
import {
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { ManifestClient } from "@cks-systems/manifest-sdk";
/**
* Cancels all orders from Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @returns Transaction signature
*/
export async function cancelAllOrders(
agent: SolanaAgentKit,
marketId: PublicKey,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const cancelAllOrdersIx = await mfxClient.cancelAllIx();
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(cancelAllOrdersIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Cancel all orders failed: ${error.message}`);
}
}

View File

@@ -0,0 +1,103 @@
import {
PublicKey,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../agent";
import {
AccountLayout,
createCloseAccountInstruction,
TOKEN_2022_PROGRAM_ID,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
/**
* Close Empty SPL Token accounts of the agent
* @param agent SolanaAgentKit instance
* @returns transaction signature and total number of accounts closed
*/
export async function closeEmptyTokenAccounts(
agent: SolanaAgentKit,
): Promise<{ signature: string; size: number }> {
try {
const spl_token = await create_close_instruction(agent, TOKEN_PROGRAM_ID);
const token_2022 = await create_close_instruction(
agent,
TOKEN_2022_PROGRAM_ID,
);
const transaction = new Transaction();
const MAX_INSTRUCTIONS = 40; // 40 instructions can be processed in a single transaction without failing
spl_token
.slice(0, Math.min(MAX_INSTRUCTIONS, spl_token.length))
.forEach((instruction) => transaction.add(instruction));
token_2022
.slice(0, Math.max(0, MAX_INSTRUCTIONS - spl_token.length))
.forEach((instruction) => transaction.add(instruction));
const size = spl_token.length + token_2022.length;
if (size === 0) {
return {
signature: "",
size: 0,
};
}
const signature = await agent.connection.sendTransaction(transaction, [
agent.wallet,
]);
return { signature, size };
} catch (error) {
throw new Error(`Error closing empty token accounts: ${error}`);
}
}
/**
* creates the close instuctions of a spl token account
* @param agnet SolanaAgentKit instance
* @param token_program Token Program Id
* @returns close instuction array
*/
async function create_close_instruction(
agent: SolanaAgentKit,
token_program: PublicKey,
): Promise<TransactionInstruction[]> {
const instructions = [];
const ata_accounts = await agent.connection.getTokenAccountsByOwner(
agent.wallet_address,
{ programId: token_program },
"confirmed",
);
const tokens = ata_accounts.value;
const accountExceptions = [
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
];
for (let i = 0; i < tokens.length; i++) {
const token_data = AccountLayout.decode(tokens[i].account.data);
if (
token_data.amount === BigInt(0) &&
!accountExceptions.includes(token_data.mint.toString())
) {
const closeInstruction = createCloseAccountInstruction(
ata_accounts.value[i].pubkey,
agent.wallet_address,
agent.wallet_address,
[],
token_program,
);
instructions.push(closeInstruction);
}
}
return instructions;
}

View File

@@ -0,0 +1,69 @@
import { createCollectionImp, createSingleImp } from "@3land/listings-sdk";
import {
StoreInitOptions,
CreateCollectionOptions,
CreateSingleOptions,
} from "@3land/listings-sdk/dist/types/implementation/implementationTypes";
/**
* Create a collection on 3Land
* @param optionsWithBase58 represents the privateKey of the wallet - can be an array of numbers, Uint8Array or base58 string
* @param collectionOpts represents the options for the collection creation
* @returns
*/
export async function createCollection(
optionsWithBase58: StoreInitOptions,
collectionOpts: CreateCollectionOptions,
) {
try {
const collection = await createCollectionImp(
optionsWithBase58,
collectionOpts,
);
return collection;
} catch (error: any) {
throw new Error(`Collection creation failed: ${error.message}`);
}
}
/**
* Create a single edition on 3Land
* @param optionsWithBase58 represents the privateKey of the wallet - can be an array of numbers, Uint8Array or base58 string
* @param collectionAccount represents the account for the nft collection
* @param createItemOptions the options for the creation of the single NFT listing
* @returns
*/
export async function createSingle(
optionsWithBase58: StoreInitOptions,
collectionAccount: string,
createItemOptions: CreateSingleOptions,
isMainnet: boolean,
) {
try {
const landStore = isMainnet
? "AmQNs2kgw4LvS9sm6yE9JJ4Hs3JpVu65eyx9pxMG2xA"
: "GyPCu89S63P9NcCQAtuSJesiefhhgpGWrNVJs4bF2cSK";
const singleEditionTx = await createSingleImp(
optionsWithBase58,
landStore,
collectionAccount,
createItemOptions,
);
return singleEditionTx;
} catch (error: any) {
throw new Error(`Single edition creation failed: ${error.message}`);
}
}
/**
* Buy a single edition on 3Land
* @param
* @returns
*/
// export async function buySingle() {
// try {
// } catch (error: any) {
// throw new Error(`Buying single edition failed: ${error.message}`);
// }
// }

View File

@@ -0,0 +1,118 @@
import { ComputeBudgetProgram } from "@solana/web3.js";
import { PoolConfig, Side } from "flash-sdk";
import { BN } from "@coral-xyz/anchor";
import { SolanaAgentKit } from "../index";
import {
CLOSE_POSITION_CU,
marketSdkInfo,
marketTokenMap,
getNftTradingAccountInfo,
fetchOraclePrice,
createPerpClient,
get_flash_privilege,
} from "../utils/flashUtils";
import { FlashCloseTradeParams } from "../types";
/**
* Closes an existing position on Flash.Trade
* @param agent SolanaAgentKit instance
* @param params Trade parameters
* @returns Transaction signature
*/
export async function flashCloseTrade(
agent: SolanaAgentKit,
params: FlashCloseTradeParams,
): Promise<string> {
try {
const { token, side } = params;
// Get market ID from token and side using marketTokenMap
const tokenMarkets = marketTokenMap[token];
if (!tokenMarkets) {
throw new Error(`Token ${token} not supported for trading`);
}
const sideEntry = tokenMarkets[side];
if (!sideEntry) {
throw new Error(`${side} side not available for ${token}`);
}
const market = sideEntry.marketID;
// Validate market data using marketSdkInfo
const marketData = marketSdkInfo[market];
if (!marketData) {
throw new Error(`Invalid market configuration for ${token}/${side}`);
}
// Get token information
const [targetSymbol, collateralSymbol] = marketData.tokenPair.split("/");
// Fetch oracle prices
const [targetPrice] = await Promise.all([
fetchOraclePrice(targetSymbol),
fetchOraclePrice(collateralSymbol),
]);
// Initialize pool configuration and perpClient
const poolConfig = PoolConfig.fromIdsByName(
marketData.pool,
"mainnet-beta",
);
const perpClient = createPerpClient(agent.connection, agent.wallet);
// Calculate price after slippage
const slippageBpsBN = new BN(100); // 1% slippage
const sideEnum = side === "long" ? Side.Long : Side.Short;
const priceWithSlippage = perpClient.getPriceAfterSlippage(
false, // isEntry = false for closing position
slippageBpsBN,
targetPrice.price,
sideEnum,
);
// Get NFT trading account info
const tradingAccounts = await getNftTradingAccountInfo(
agent.wallet_address,
perpClient,
poolConfig,
collateralSymbol,
);
if (
!tradingAccounts.nftTradingAccountPk ||
!tradingAccounts.nftReferralAccountPK ||
!tradingAccounts.nftOwnerRebateTokenAccountPk
) {
throw new Error("Required NFT trading accounts not found");
}
// Build and send transaction
const { instructions, additionalSigners } = await perpClient.closePosition(
targetSymbol,
collateralSymbol,
priceWithSlippage,
sideEnum,
poolConfig,
get_flash_privilege(agent),
tradingAccounts.nftTradingAccountPk,
tradingAccounts.nftReferralAccountPK,
tradingAccounts.nftOwnerRebateTokenAccountPk,
);
const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({
units: CLOSE_POSITION_CU,
});
return await perpClient.sendTransaction(
[computeBudgetIx, ...instructions],
{
additionalSigners: additionalSigners,
alts: perpClient.addressLookupTables,
prioritizationFee: 5000000,
},
);
} catch (error) {
throw new Error(`Flash trade close failed: ${error}`);
}
}

View File

@@ -0,0 +1,251 @@
import { ComputeBudgetProgram } from "@solana/web3.js";
import {
PerpetualsClient,
OraclePrice,
PoolConfig,
Side,
CustodyAccount,
Custody,
} from "flash-sdk";
import { BN } from "@coral-xyz/anchor";
import { SolanaAgentKit } from "../index";
import {
ALL_TOKENS,
marketSdkInfo,
marketTokenMap,
getNftTradingAccountInfo,
OPEN_POSITION_CU,
fetchOraclePrice,
createPerpClient,
get_flash_privilege,
} from "../utils/flashUtils";
import { FlashTradeParams } from "../types";
/**
* Opens a new position on Flash.Trade
* @param agent SolanaAgentKit instance
* @param params Trade parameters
* @returns Transaction signature
*/
export async function flashOpenTrade(
agent: SolanaAgentKit,
params: FlashTradeParams,
): Promise<string> {
try {
const { token, side, collateralUsd, leverage } = params;
// Get market ID from token and side using marketTokenMap
const tokenMarkets = marketTokenMap[token];
if (!tokenMarkets) {
throw new Error(`Token ${token} not supported for trading`);
}
const sideEntry = tokenMarkets[side];
if (!sideEntry) {
throw new Error(`${side} side not available for ${token}`);
}
const market = sideEntry.marketID;
// Validate market data using marketSdkInfo
const marketData = marketSdkInfo[market];
if (!marketData) {
throw new Error(`Invalid market configuration for ${token}/${side}`);
}
// Get token information
const [targetSymbol, collateralSymbol] = marketData.tokenPair.split("/");
const targetToken = ALL_TOKENS.find((t) => t.symbol === targetSymbol);
const collateralToken = ALL_TOKENS.find(
(t) => t.symbol === collateralSymbol,
);
if (!targetToken || !collateralToken) {
throw new Error(`Token not found for pair ${marketData.tokenPair}`);
}
// Fetch oracle prices
const [targetPrice, collateralPrice] = await Promise.all([
fetchOraclePrice(targetSymbol),
fetchOraclePrice(collateralSymbol),
]);
// Initialize pool configuration and perpClient
const poolConfig = PoolConfig.fromIdsByName(
marketData.pool,
"mainnet-beta",
);
const perpClient = createPerpClient(agent.connection, agent.wallet);
// Calculate position parameters
const leverageBN = new BN(leverage);
const collateralTokenPrice = convertPriceToNumber(collateralPrice.price);
const collateralAmount = calculateCollateralAmount(
collateralUsd,
collateralTokenPrice,
collateralToken.decimals,
);
// Get custody accounts
const { targetCustody, collateralCustody } = await fetchCustodyAccounts(
perpClient,
poolConfig,
targetSymbol,
collateralSymbol,
);
// Calculate position size
const positionSize = calculatePositionSize(
perpClient,
collateralAmount,
leverageBN,
targetToken,
collateralToken,
side,
targetPrice.price,
collateralPrice.price,
targetCustody,
collateralCustody,
);
// Get NFT trading account info
const tradingAccounts = await getNftTradingAccountInfo(
agent.wallet_address,
perpClient,
poolConfig,
collateralSymbol,
);
if (
!tradingAccounts.nftTradingAccountPk ||
!tradingAccounts.nftReferralAccountPK
) {
throw new Error("Required NFT trading accounts not found");
}
// Prepare transaction
const slippageBps = new BN(1000);
const priceWithSlippage = perpClient.getPriceAfterSlippage(
true,
slippageBps,
targetPrice.price,
side === "long" ? Side.Long : Side.Short,
);
// Build and send transaction
const { instructions, additionalSigners } = await perpClient.openPosition(
targetSymbol,
collateralSymbol,
priceWithSlippage,
collateralAmount,
positionSize,
side === "long" ? Side.Long : Side.Short,
poolConfig,
get_flash_privilege(agent),
tradingAccounts.nftTradingAccountPk,
tradingAccounts.nftReferralAccountPK,
tradingAccounts.nftOwnerRebateTokenAccountPk!,
false,
);
const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({
units: OPEN_POSITION_CU,
});
return await perpClient.sendTransaction(
[computeBudgetIx, ...instructions],
{
additionalSigners: additionalSigners,
alts: perpClient.addressLookupTables,
prioritizationFee: 5000000,
},
);
} catch (error) {
throw new Error(`Flash trade failed: ${error}`);
}
}
// Helper functions
function convertPriceToNumber(oraclePrice: OraclePrice): number {
const price = parseInt(oraclePrice.price.toString("hex"), 16);
const exponent = parseInt(oraclePrice.exponent.toString("hex"), 16);
return price * Math.pow(10, exponent);
}
function calculateCollateralAmount(
usdAmount: number,
tokenPrice: number,
decimals: number,
): BN {
return new BN((usdAmount / tokenPrice) * Math.pow(10, decimals));
}
async function fetchCustodyAccounts(
perpClient: PerpetualsClient,
poolConfig: PoolConfig,
targetSymbol: string,
collateralSymbol: string,
) {
const targetConfig = poolConfig.custodies.find(
(c) => c.symbol === targetSymbol,
);
const collateralConfig = poolConfig.custodies.find(
(c) => c.symbol === collateralSymbol,
);
if (!targetConfig || !collateralConfig) {
throw new Error("Custody configuration not found");
}
const accounts = await perpClient.provider.connection.getMultipleAccountsInfo(
[targetConfig.custodyAccount, collateralConfig.custodyAccount],
);
if (!accounts[0] || !accounts[1]) {
throw new Error("Failed to fetch custody accounts");
}
return {
targetCustody: CustodyAccount.from(
targetConfig.custodyAccount,
perpClient.program.coder.accounts.decode<Custody>(
"custody",
accounts[0].data,
),
),
collateralCustody: CustodyAccount.from(
collateralConfig.custodyAccount,
perpClient.program.coder.accounts.decode<Custody>(
"custody",
accounts[1].data,
),
),
};
}
function calculatePositionSize(
perpClient: PerpetualsClient,
collateralAmount: BN,
leverage: BN,
targetToken: any,
collateralToken: any,
side: "long" | "short",
targetPrice: OraclePrice,
collateralPrice: OraclePrice,
targetCustody: CustodyAccount,
collateralCustody: CustodyAccount,
): BN {
return perpClient.getSizeAmountFromLeverageAndCollateral(
collateralAmount,
leverage.toString(),
targetToken,
collateralToken,
side === "long" ? Side.Long : Side.Short,
targetPrice,
targetPrice,
targetCustody,
collateralPrice,
collateralPrice,
collateralCustody,
);
}

View File

@@ -1,6 +1,4 @@
export * from "./adrena_perp_trading";
export * from "./batch_order";
export * from "./cancel_all_orders";
export * from "./create_gibwork_task";
export * from "./create_image";
export * from "./create_tiplinks";
@@ -20,8 +18,7 @@ export * from "./get_tps";
export * from "./get_wallet_address";
export * from "./launch_pumpfun_token";
export * from "./lend";
export * from "./limit_order";
export * from "./manifest_create_market";
export * from "./manifest_trade";
export * from "./mint_nft";
export * from "./openbook_create_market";
export * from "./orca_close_position";
@@ -44,6 +41,12 @@ export * from "./send_compressed_airdrop";
export * from "./stake_with_jup";
export * from "./stake_with_solayer";
export * from "./tensor_trade";
export * from "./close_empty_token_accounts";
export * from "./trade";
export * from "./transfer";
export * from "./withdraw_all";
export * from "./flash_open_trade";
export * from "./flash_close_trade";
export * from "./create_3land_collectible";

View File

@@ -1,61 +0,0 @@
import {
PublicKey,
Transaction,
sendAndConfirmTransaction,
TransactionInstruction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import {
ManifestClient,
WrapperPlaceOrderParamsExternal,
OrderType,
} from "@cks-systems/manifest-sdk";
/**
* Place limit orders using Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @param quantity Amount to trade in tokens
* @param side Buy or Sell
* @param price Price in tokens ie. SOL/USDC
* @returns Transaction signature
*/
export async function limitOrder(
agent: SolanaAgentKit,
marketId: PublicKey,
quantity: number,
side: string,
price: number,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const orderParams: WrapperPlaceOrderParamsExternal = {
numBaseTokens: quantity,
tokenPrice: price,
isBid: side === "Buy",
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: Number(Math.random() * 1000),
};
const depositPlaceOrderIx: TransactionInstruction[] =
await mfxClient.placeOrderWithRequiredDepositIx(
agent.wallet.publicKey,
orderParams,
);
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(...depositPlaceOrderIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Limit Order failed: ${error.message}`);
}
}

View File

@@ -1,43 +0,0 @@
import { ManifestClient } from "@cks-systems/manifest-sdk";
import {
Keypair,
PublicKey,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
export async function manifestCreateMarket(
agent: SolanaAgentKit,
baseMint: PublicKey,
quoteMint: PublicKey,
): Promise<string[]> {
const marketKeypair: Keypair = Keypair.generate();
const FIXED_MANIFEST_HEADER_SIZE: number = 256;
const createAccountIx: TransactionInstruction = SystemProgram.createAccount({
fromPubkey: agent.wallet.publicKey,
newAccountPubkey: marketKeypair.publicKey,
space: FIXED_MANIFEST_HEADER_SIZE,
lamports: await agent.connection.getMinimumBalanceForRentExemption(
FIXED_MANIFEST_HEADER_SIZE,
),
programId: new PublicKey("MNFSTqtC93rEfYHB6hF82sKdZpUDFWkViLByLd1k1Ms"),
});
const createMarketIx = ManifestClient["createMarketIx"](
agent.wallet.publicKey,
baseMint,
quoteMint,
marketKeypair.publicKey,
);
const tx: Transaction = new Transaction();
tx.add(createAccountIx);
tx.add(createMarketIx);
const signature = await sendAndConfirmTransaction(agent.connection, tx, [
agent.wallet,
marketKeypair,
]);
return [signature, marketKeypair.publicKey.toBase58()];
}

View File

@@ -1,16 +1,159 @@
import {
PublicKey,
Transaction,
sendAndConfirmTransaction,
TransactionInstruction,
} from "@solana/web3.js";
import {
ManifestClient,
WrapperPlaceOrderParamsExternal,
OrderType,
WrapperPlaceOrderParamsExternal,
} from "@cks-systems/manifest-sdk";
import { SolanaAgentKit } from "../index";
import { BatchOrderPattern, OrderParams } from "../types";
import {
Keypair,
PublicKey,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { BatchOrderPattern, OrderParams, SolanaAgentKit } from "../index";
export async function manifestCreateMarket(
agent: SolanaAgentKit,
baseMint: PublicKey,
quoteMint: PublicKey,
): Promise<string[]> {
const marketKeypair: Keypair = Keypair.generate();
const FIXED_MANIFEST_HEADER_SIZE: number = 256;
const createAccountIx: TransactionInstruction = SystemProgram.createAccount({
fromPubkey: agent.wallet.publicKey,
newAccountPubkey: marketKeypair.publicKey,
space: FIXED_MANIFEST_HEADER_SIZE,
lamports: await agent.connection.getMinimumBalanceForRentExemption(
FIXED_MANIFEST_HEADER_SIZE,
),
programId: new PublicKey("MNFSTqtC93rEfYHB6hF82sKdZpUDFWkViLByLd1k1Ms"),
});
const createMarketIx = ManifestClient["createMarketIx"](
agent.wallet.publicKey,
baseMint,
quoteMint,
marketKeypair.publicKey,
);
const tx: Transaction = new Transaction();
tx.add(createAccountIx);
tx.add(createMarketIx);
const signature = await sendAndConfirmTransaction(agent.connection, tx, [
agent.wallet,
marketKeypair,
]);
return [signature, marketKeypair.publicKey.toBase58()];
}
/**
* Place limit orders using Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @param quantity Amount to trade in tokens
* @param side Buy or Sell
* @param price Price in tokens ie. SOL/USDC
* @returns Transaction signature
*/
export async function limitOrder(
agent: SolanaAgentKit,
marketId: PublicKey,
quantity: number,
side: string,
price: number,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const orderParams: WrapperPlaceOrderParamsExternal = {
numBaseTokens: quantity,
tokenPrice: price,
isBid: side === "Buy",
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: Number(Math.random() * 1000),
};
const depositPlaceOrderIx: TransactionInstruction[] =
await mfxClient.placeOrderWithRequiredDepositIx(
agent.wallet.publicKey,
orderParams,
);
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(...depositPlaceOrderIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Limit Order failed: ${error.message}`);
}
}
/**
* Cancels all orders from Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @returns Transaction signature
*/
export async function cancelAllOrders(
agent: SolanaAgentKit,
marketId: PublicKey,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const cancelAllOrdersIx = await mfxClient.cancelAllIx();
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(cancelAllOrdersIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Cancel all orders failed: ${error.message}`);
}
}
/**
* Withdraws all funds from Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @returns Transaction signature
*/
export async function withdrawAll(
agent: SolanaAgentKit,
marketId: PublicKey,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const withdrawAllIx = await mfxClient.withdrawAllIx();
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(...withdrawAllIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Withdraw all failed: ${error.message}`);
}
}
/**
* Generates an array of orders based on the specified pattern

View File

@@ -1,37 +0,0 @@
import {
PublicKey,
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
import { SolanaAgentKit } from "../index";
import { ManifestClient } from "@cks-systems/manifest-sdk";
/**
* Withdraws all funds from Manifest
* @param agent SolanaAgentKit instance
* @param marketId Public key for the manifest market
* @returns Transaction signature
*/
export async function withdrawAll(
agent: SolanaAgentKit,
marketId: PublicKey,
): Promise<string> {
try {
const mfxClient = await ManifestClient.getClientForMarket(
agent.connection,
marketId,
agent.wallet,
);
const withdrawAllIx = await mfxClient.withdrawAllIx();
const signature = await sendAndConfirmTransaction(
agent.connection,
new Transaction().add(...withdrawAllIx),
[agent.wallet],
);
return signature;
} catch (error: any) {
throw new Error(`Withdraw all failed: ${error.message}`);
}
}