mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-18 15:10:33 +00:00
Merge branch 'sendaifun:main' into feature/totalbalance
This commit is contained in:
103
src/tools/close_empty_token_accounts.ts
Normal file
103
src/tools/close_empty_token_accounts.ts
Normal 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;
|
||||
}
|
||||
69
src/tools/create_3land_collectible.ts
Normal file
69
src/tools/create_3land_collectible.ts
Normal 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}`);
|
||||
// }
|
||||
// }
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ComputeBudgetProgram } from "@solana/web3.js";
|
||||
import { PoolConfig, Privilege, Side } from "flash-sdk";
|
||||
import { PoolConfig, Side } from "flash-sdk";
|
||||
import { BN } from "@coral-xyz/anchor";
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import {
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getNftTradingAccountInfo,
|
||||
fetchOraclePrice,
|
||||
createPerpClient,
|
||||
get_flash_privilege,
|
||||
} from "../utils/flashUtils";
|
||||
import { FlashCloseTradeParams } from "../types";
|
||||
|
||||
@@ -93,7 +94,7 @@ export async function flashCloseTrade(
|
||||
priceWithSlippage,
|
||||
sideEnum,
|
||||
poolConfig,
|
||||
Privilege.Referral,
|
||||
get_flash_privilege(agent),
|
||||
tradingAccounts.nftTradingAccountPk,
|
||||
tradingAccounts.nftReferralAccountPK,
|
||||
tradingAccounts.nftOwnerRebateTokenAccountPk,
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
PerpetualsClient,
|
||||
OraclePrice,
|
||||
PoolConfig,
|
||||
Privilege,
|
||||
Side,
|
||||
CustodyAccount,
|
||||
Custody,
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
OPEN_POSITION_CU,
|
||||
fetchOraclePrice,
|
||||
createPerpClient,
|
||||
get_flash_privilege,
|
||||
} from "../utils/flashUtils";
|
||||
import { FlashTradeParams } from "../types";
|
||||
|
||||
@@ -141,7 +141,7 @@ export async function flashOpenTrade(
|
||||
positionSize,
|
||||
side === "long" ? Side.Long : Side.Short,
|
||||
poolConfig,
|
||||
Privilege.Referral,
|
||||
get_flash_privilege(agent),
|
||||
tradingAccounts.nftTradingAccountPk,
|
||||
tradingAccounts.nftReferralAccountPK,
|
||||
tradingAccounts.nftOwnerRebateTokenAccountPk!,
|
||||
|
||||
@@ -9,17 +9,14 @@ export async function getTokenDataByAddress(
|
||||
throw new Error("Mint address is required");
|
||||
}
|
||||
|
||||
const response = await fetch("https://tokens.jup.ag/tokens?tags=verified", {
|
||||
const response = await fetch(`https://tokens.jup.ag/token/${mint}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const data = (await response.json()) as JupiterTokenData[];
|
||||
const token = data.find((token: JupiterTokenData) => {
|
||||
return token.address === mint.toBase58();
|
||||
});
|
||||
const token = (await response.json()) as JupiterTokenData;
|
||||
return token;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Error fetching token data: ${error.message}`);
|
||||
|
||||
@@ -41,7 +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 "./flash_open_trade";
|
||||
export * from "./flash_close_trade";
|
||||
|
||||
export * from "./create_3land_collectible";
|
||||
|
||||
52
src/tools/squads_multisig/approve_proposal.ts
Normal file
52
src/tools/squads_multisig/approve_proposal.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import * as multisig from "@sqds/multisig";
|
||||
const { Multisig } = multisig.accounts;
|
||||
|
||||
/**
|
||||
* Approves a proposal in a Solana multisig wallet.
|
||||
*
|
||||
* @param {SolanaAgentKit} agent - The Solana agent kit instance.
|
||||
* @param {number | bigint} [transactionIndex] - The index of the transaction to approve. If not provided, the current transaction index will be used.
|
||||
* @returns {Promise<string>} - A promise that resolves to the transaction ID of the approved proposal.
|
||||
* @throws {Error} - Throws an error if the approval process fails.
|
||||
*/
|
||||
export async function approve_proposal(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const createKey = agent.wallet;
|
||||
const [multisigPda] = multisig.getMultisigPda({
|
||||
createKey: createKey.publicKey,
|
||||
});
|
||||
const multisigInfo = await Multisig.fromAccountAddress(
|
||||
agent.connection,
|
||||
multisigPda,
|
||||
);
|
||||
const currentTransactionIndex = Number(multisigInfo.transactionIndex);
|
||||
if (!transactionIndex) {
|
||||
transactionIndex = BigInt(currentTransactionIndex);
|
||||
} else if (typeof transactionIndex !== "bigint") {
|
||||
transactionIndex = BigInt(transactionIndex);
|
||||
}
|
||||
// const [proposalPda, proposalBump] = multisig.getProposalPda({
|
||||
// multisigPda,
|
||||
// transactionIndex,
|
||||
// });
|
||||
const multisigTx = multisig.transactions.proposalApprove({
|
||||
blockhash: (await agent.connection.getLatestBlockhash()).blockhash,
|
||||
feePayer: agent.wallet.publicKey,
|
||||
multisigPda,
|
||||
transactionIndex: transactionIndex,
|
||||
member: agent.wallet.publicKey,
|
||||
});
|
||||
|
||||
multisigTx.sign([agent.wallet]);
|
||||
const tx = await agent.connection.sendRawTransaction(
|
||||
multisigTx.serialize(),
|
||||
);
|
||||
return tx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Transfer failed: ${error}`);
|
||||
}
|
||||
}
|
||||
62
src/tools/squads_multisig/create_multisig.ts
Normal file
62
src/tools/squads_multisig/create_multisig.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import * as multisig from "@sqds/multisig";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
|
||||
/**
|
||||
* Creates a new Squads multisig account.
|
||||
*
|
||||
* @param agent - The SolanaAgentKit instance containing the connection and wallet information.
|
||||
* @param creator - The public key of the creator who will be a member of the multisig.
|
||||
* @returns A promise that resolves to the transaction ID of the multisig creation transaction.
|
||||
*
|
||||
* @throws Will throw an error if the transaction fails.
|
||||
*/
|
||||
export async function create_squads_multisig(
|
||||
agent: SolanaAgentKit,
|
||||
creator: PublicKey,
|
||||
): Promise<string> {
|
||||
const connection = agent.connection;
|
||||
const createKey = agent.wallet; // can be any keypair, using the agent wallet as only one multisig is required
|
||||
console.log("Multisig Create Key:", createKey.publicKey.toBase58());
|
||||
|
||||
const [multisigPda] = multisig.getMultisigPda({
|
||||
createKey: createKey.publicKey,
|
||||
});
|
||||
|
||||
const programConfigPda = multisig.getProgramConfigPda({})[0];
|
||||
|
||||
const programConfig =
|
||||
await multisig.accounts.ProgramConfig.fromAccountAddress(
|
||||
connection,
|
||||
programConfigPda,
|
||||
);
|
||||
|
||||
const configTreasury = programConfig.treasury;
|
||||
const tx = multisig.transactions.multisigCreateV2({
|
||||
blockhash: (await connection.getLatestBlockhash()).blockhash,
|
||||
treasury: configTreasury,
|
||||
createKey: createKey.publicKey,
|
||||
creator: agent.wallet.publicKey,
|
||||
multisigPda,
|
||||
configAuthority: null,
|
||||
timeLock: 0,
|
||||
threshold: 2,
|
||||
rentCollector: null,
|
||||
members: [
|
||||
{
|
||||
key: agent.wallet.publicKey,
|
||||
permissions: multisig.types.Permissions.all(),
|
||||
},
|
||||
{
|
||||
key: creator,
|
||||
permissions: multisig.types.Permissions.all(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
tx.sign([agent.wallet, createKey]);
|
||||
|
||||
const txId = connection.sendRawTransaction(tx.serialize());
|
||||
|
||||
return txId;
|
||||
}
|
||||
48
src/tools/squads_multisig/create_proposal.ts
Normal file
48
src/tools/squads_multisig/create_proposal.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import * as multisig from "@sqds/multisig";
|
||||
const { Multisig } = multisig.accounts;
|
||||
|
||||
/**
|
||||
* Creates a proposal for a multisig transaction.
|
||||
*
|
||||
* @param {SolanaAgentKit} agent - The Solana agent kit instance.
|
||||
* @param {number | bigint} [transactionIndex] - Optional transaction index. If not provided, the current transaction index will be used.
|
||||
* @returns {Promise<string>} - The transaction ID of the created proposal.
|
||||
* @throws {Error} - Throws an error if the proposal creation fails.
|
||||
*/
|
||||
export async function create_proposal(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const createKey = agent.wallet;
|
||||
const [multisigPda] = multisig.getMultisigPda({
|
||||
createKey: createKey.publicKey,
|
||||
});
|
||||
const multisigInfo = await Multisig.fromAccountAddress(
|
||||
agent.connection,
|
||||
multisigPda,
|
||||
);
|
||||
const currentTransactionIndex = Number(multisigInfo.transactionIndex);
|
||||
if (!transactionIndex) {
|
||||
transactionIndex = BigInt(currentTransactionIndex);
|
||||
} else if (typeof transactionIndex !== "bigint") {
|
||||
transactionIndex = BigInt(transactionIndex);
|
||||
}
|
||||
const multisigTx = multisig.transactions.proposalCreate({
|
||||
blockhash: (await agent.connection.getLatestBlockhash()).blockhash,
|
||||
feePayer: agent.wallet_address,
|
||||
multisigPda,
|
||||
transactionIndex,
|
||||
creator: agent.wallet_address,
|
||||
});
|
||||
|
||||
multisigTx.sign([agent.wallet]);
|
||||
const tx = await agent.connection.sendRawTransaction(
|
||||
multisigTx.serialize(),
|
||||
);
|
||||
return tx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Transfer failed: ${error}`);
|
||||
}
|
||||
}
|
||||
91
src/tools/squads_multisig/deposit_to_multisig.ts
Normal file
91
src/tools/squads_multisig/deposit_to_multisig.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import { PublicKey, SystemProgram, Transaction } from "@solana/web3.js";
|
||||
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
|
||||
import {
|
||||
getAssociatedTokenAddress,
|
||||
createTransferInstruction,
|
||||
getMint,
|
||||
createAssociatedTokenAccountInstruction,
|
||||
} from "@solana/spl-token";
|
||||
import * as multisig from "@sqds/multisig";
|
||||
|
||||
/**
|
||||
* Transfer SOL or SPL tokens to a multisig vault.
|
||||
* @param agent SolanaAgentKit instance
|
||||
* @param amount Amount to transfer
|
||||
* @param vaultIndex Optional vault index, default is 0
|
||||
* @param mint Optional mint address for SPL tokens
|
||||
* @returns Transaction signature
|
||||
*/
|
||||
export async function deposit_to_multisig(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
vaultIndex?: number,
|
||||
mint?: PublicKey,
|
||||
): Promise<string> {
|
||||
try {
|
||||
let tx: string;
|
||||
if (!vaultIndex) {
|
||||
vaultIndex = 0;
|
||||
}
|
||||
const createKey = agent.wallet;
|
||||
const [multisigPda] = multisig.getMultisigPda({
|
||||
createKey: createKey.publicKey,
|
||||
});
|
||||
const [vaultPda] = multisig.getVaultPda({
|
||||
multisigPda,
|
||||
index: vaultIndex,
|
||||
});
|
||||
const to = vaultPda;
|
||||
if (!mint) {
|
||||
// Transfer native SOL
|
||||
const transaction = new Transaction().add(
|
||||
SystemProgram.transfer({
|
||||
fromPubkey: agent.wallet_address,
|
||||
toPubkey: to,
|
||||
lamports: amount * LAMPORTS_PER_SOL,
|
||||
}),
|
||||
);
|
||||
|
||||
tx = await agent.connection.sendTransaction(transaction, [agent.wallet]);
|
||||
} else {
|
||||
// Transfer SPL token
|
||||
const fromAta = await getAssociatedTokenAddress(
|
||||
mint,
|
||||
agent.wallet_address,
|
||||
);
|
||||
let transaction = new Transaction();
|
||||
const toAta = await getAssociatedTokenAddress(mint, to, true);
|
||||
const toTokenAccountInfo = await agent.connection.getAccountInfo(toAta);
|
||||
// Create associated token account if it doesn't exist
|
||||
if (!toTokenAccountInfo) {
|
||||
transaction.add(
|
||||
createAssociatedTokenAccountInstruction(
|
||||
agent.wallet_address,
|
||||
toAta,
|
||||
to,
|
||||
mint,
|
||||
),
|
||||
);
|
||||
}
|
||||
// Get mint info to determine decimals
|
||||
const mintInfo = await getMint(agent.connection, mint);
|
||||
const adjustedAmount = amount * Math.pow(10, mintInfo.decimals);
|
||||
|
||||
transaction.add(
|
||||
createTransferInstruction(
|
||||
fromAta,
|
||||
toAta,
|
||||
agent.wallet_address,
|
||||
adjustedAmount,
|
||||
),
|
||||
);
|
||||
|
||||
tx = await agent.connection.sendTransaction(transaction, [agent.wallet]);
|
||||
}
|
||||
|
||||
return tx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Transfer failed: ${error}`);
|
||||
}
|
||||
}
|
||||
49
src/tools/squads_multisig/execute_proposal.ts
Normal file
49
src/tools/squads_multisig/execute_proposal.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import * as multisig from "@sqds/multisig";
|
||||
const { Multisig } = multisig.accounts;
|
||||
|
||||
/**
|
||||
* Executes a transaction on the Solana blockchain using the provided agent.
|
||||
*
|
||||
* @param {SolanaAgentKit} agent - The Solana agent kit instance containing the wallet and connection.
|
||||
* @param {number | bigint} [transactionIndex] - Optional transaction index to execute. If not provided, the current transaction index from the multisig account will be used.
|
||||
* @returns {Promise<string>} - A promise that resolves to the transaction signature string.
|
||||
* @throws {Error} - Throws an error if the transaction execution fails.
|
||||
*/
|
||||
export async function execute_transaction(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const createKey = agent.wallet;
|
||||
const [multisigPda] = multisig.getMultisigPda({
|
||||
createKey: createKey.publicKey,
|
||||
});
|
||||
const multisigInfo = await Multisig.fromAccountAddress(
|
||||
agent.connection,
|
||||
multisigPda,
|
||||
);
|
||||
const currentTransactionIndex = Number(multisigInfo.transactionIndex);
|
||||
if (!transactionIndex) {
|
||||
transactionIndex = BigInt(currentTransactionIndex);
|
||||
} else if (typeof transactionIndex !== "bigint") {
|
||||
transactionIndex = BigInt(transactionIndex);
|
||||
}
|
||||
const multisigTx = await multisig.transactions.vaultTransactionExecute({
|
||||
connection: agent.connection,
|
||||
blockhash: (await agent.connection.getLatestBlockhash()).blockhash,
|
||||
feePayer: agent.wallet.publicKey,
|
||||
multisigPda,
|
||||
transactionIndex,
|
||||
member: agent.wallet.publicKey,
|
||||
});
|
||||
|
||||
multisigTx.sign([agent.wallet]);
|
||||
const tx = await agent.connection.sendRawTransaction(
|
||||
multisigTx.serialize(),
|
||||
);
|
||||
return tx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Transfer failed: ${error}`);
|
||||
}
|
||||
}
|
||||
52
src/tools/squads_multisig/reject_proposal.ts
Normal file
52
src/tools/squads_multisig/reject_proposal.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import * as multisig from "@sqds/multisig";
|
||||
const { Multisig } = multisig.accounts;
|
||||
|
||||
/**
|
||||
* Rejects a proposal in a Solana multisig setup.
|
||||
*
|
||||
* @param agent - The SolanaAgentKit instance containing the wallet and connection.
|
||||
* @param transactionIndex - Optional. The index of the transaction to reject. If not provided, the current transaction index will be used.
|
||||
* @returns A promise that resolves to the transaction ID of the rejection transaction.
|
||||
* @throws Will throw an error if the transaction fails.
|
||||
*/
|
||||
export async function reject_proposal(
|
||||
agent: SolanaAgentKit,
|
||||
transactionIndex?: number | bigint,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const createKey = agent.wallet;
|
||||
const [multisigPda] = multisig.getMultisigPda({
|
||||
createKey: createKey.publicKey,
|
||||
});
|
||||
const multisigInfo = await Multisig.fromAccountAddress(
|
||||
agent.connection,
|
||||
multisigPda,
|
||||
);
|
||||
const currentTransactionIndex = Number(multisigInfo.transactionIndex);
|
||||
if (!transactionIndex) {
|
||||
transactionIndex = BigInt(currentTransactionIndex);
|
||||
} else if (typeof transactionIndex !== "bigint") {
|
||||
transactionIndex = BigInt(transactionIndex);
|
||||
}
|
||||
// const [proposalPda, proposalBump] = multisig.getProposalPda({
|
||||
// multisigPda,
|
||||
// transactionIndex,
|
||||
// });
|
||||
const multisigTx = multisig.transactions.proposalReject({
|
||||
blockhash: (await agent.connection.getLatestBlockhash()).blockhash,
|
||||
feePayer: agent.wallet.publicKey,
|
||||
multisigPda,
|
||||
transactionIndex: transactionIndex,
|
||||
member: agent.wallet.publicKey,
|
||||
});
|
||||
|
||||
multisigTx.sign([agent.wallet]);
|
||||
const tx = await agent.connection.sendRawTransaction(
|
||||
multisigTx.serialize(),
|
||||
);
|
||||
return tx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Transfer failed: ${error}`);
|
||||
}
|
||||
}
|
||||
98
src/tools/squads_multisig/transfer_from_multisig.ts
Normal file
98
src/tools/squads_multisig/transfer_from_multisig.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { SolanaAgentKit } from "../../index";
|
||||
import {
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
TransactionInstruction,
|
||||
TransactionMessage,
|
||||
} from "@solana/web3.js";
|
||||
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
|
||||
import {
|
||||
getAssociatedTokenAddress,
|
||||
createTransferInstruction,
|
||||
getMint,
|
||||
} from "@solana/spl-token";
|
||||
import * as multisig from "@sqds/multisig";
|
||||
const { Multisig } = multisig.accounts;
|
||||
|
||||
/**
|
||||
* Transfer SOL or SPL tokens to a recipient from a multisig vault.
|
||||
* @param agent - SolanaAgentKit instance.
|
||||
* @param amount - Amount to transfer.
|
||||
* @param to - Recipient's public key.
|
||||
* @param vaultIndex - Optional vault index, default is 0.
|
||||
* @param mint - Optional mint address for SPL tokens.
|
||||
* @returns Transaction signature.
|
||||
*/
|
||||
export async function transfer_from_multisig(
|
||||
agent: SolanaAgentKit,
|
||||
amount: number,
|
||||
to: PublicKey,
|
||||
vaultIndex: number = 0,
|
||||
mint?: PublicKey,
|
||||
): Promise<string> {
|
||||
try {
|
||||
let transferInstruction: TransactionInstruction;
|
||||
|
||||
const createKey = agent.wallet;
|
||||
const [multisigPda] = multisig.getMultisigPda({
|
||||
createKey: createKey.publicKey,
|
||||
});
|
||||
const multisigInfo = await Multisig.fromAccountAddress(
|
||||
agent.connection,
|
||||
multisigPda,
|
||||
);
|
||||
const currentTransactionIndex = Number(multisigInfo.transactionIndex);
|
||||
const transactionIndex = BigInt(currentTransactionIndex + 1);
|
||||
const [vaultPda] = multisig.getVaultPda({
|
||||
multisigPda,
|
||||
index: vaultIndex,
|
||||
});
|
||||
|
||||
if (!mint) {
|
||||
// Transfer native SOL
|
||||
transferInstruction = SystemProgram.transfer({
|
||||
fromPubkey: agent.wallet_address,
|
||||
toPubkey: to,
|
||||
lamports: amount * LAMPORTS_PER_SOL,
|
||||
});
|
||||
} else {
|
||||
// Transfer SPL token
|
||||
const fromAta = await getAssociatedTokenAddress(mint, vaultPda, true);
|
||||
const toAta = await getAssociatedTokenAddress(mint, to, true);
|
||||
const mintInfo = await getMint(agent.connection, mint);
|
||||
const adjustedAmount = amount * Math.pow(10, mintInfo.decimals);
|
||||
|
||||
transferInstruction = createTransferInstruction(
|
||||
fromAta,
|
||||
toAta,
|
||||
agent.wallet_address,
|
||||
adjustedAmount,
|
||||
);
|
||||
}
|
||||
|
||||
const transferMessage = new TransactionMessage({
|
||||
payerKey: vaultPda,
|
||||
recentBlockhash: (await agent.connection.getLatestBlockhash()).blockhash,
|
||||
instructions: [transferInstruction],
|
||||
});
|
||||
|
||||
const multisigTx = multisig.transactions.vaultTransactionCreate({
|
||||
blockhash: (await agent.connection.getLatestBlockhash()).blockhash,
|
||||
feePayer: agent.wallet_address,
|
||||
multisigPda,
|
||||
transactionIndex,
|
||||
creator: agent.wallet_address,
|
||||
vaultIndex: 0,
|
||||
ephemeralSigners: 0,
|
||||
transactionMessage: transferMessage,
|
||||
});
|
||||
|
||||
multisigTx.sign([agent.wallet]);
|
||||
const tx = await agent.connection.sendRawTransaction(
|
||||
multisigTx.serialize(),
|
||||
);
|
||||
return tx;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Transfer failed: ${error}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user