mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-13 23:16:55 +00:00
Add: tensor trade support
This commit is contained in:
7584
package-lock.json
generated
Normal file
7584
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,7 @@
|
||||
"@raydium-io/raydium-sdk-v2": "0.1.95-alpha",
|
||||
"@solana/spl-token": "^0.4.9",
|
||||
"@solana/web3.js": "^1.95.4",
|
||||
"@tensor-oss/tcomp-sdk": "^6.0.0",
|
||||
"@tiplink/api": "^0.3.1",
|
||||
"bn.js": "^5.2.1",
|
||||
"bs58": "^6.0.0",
|
||||
|
||||
@@ -37,6 +37,9 @@ import {
|
||||
create_gibwork_task,
|
||||
rock_paper_scissor,
|
||||
create_TipLink,
|
||||
listNFTForSale,
|
||||
buyNFT,
|
||||
cancelListing,
|
||||
} from "../tools";
|
||||
import {
|
||||
CollectionDeployment,
|
||||
@@ -349,4 +352,25 @@ export class SolanaAgentKit {
|
||||
async createTiplink(amount: number, splmintAddress?: PublicKey) {
|
||||
return create_TipLink(this, amount, splmintAddress);
|
||||
}
|
||||
|
||||
async tensorListNFT(
|
||||
nftMint: PublicKey,
|
||||
price: number,
|
||||
expirySeconds?: number
|
||||
): Promise<string> {
|
||||
return listNFTForSale(this, nftMint, price, expirySeconds);
|
||||
}
|
||||
|
||||
async tensorBuyNFT(
|
||||
nftMint: PublicKey,
|
||||
maxPrice: number
|
||||
): Promise<string> {
|
||||
return buyNFT(this, nftMint, maxPrice);
|
||||
}
|
||||
|
||||
async tensorCancelListing(
|
||||
nftMint: PublicKey
|
||||
): Promise<string> {
|
||||
return cancelListing(this, nftMint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1326,6 +1326,133 @@ export class SolanaTipLinkTool extends Tool {
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaListNFTForSaleTool extends Tool {
|
||||
name = "solana_list_nft_for_sale";
|
||||
description = `List an NFT for sale on Tensor Trade.
|
||||
|
||||
Inputs (input is a JSON string):
|
||||
nftMint: string, the mint address of the NFT (required)
|
||||
price: number, price in SOL (required)
|
||||
expirySeconds: number, expiry time in seconds (optional)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
|
||||
// Validate NFT ownership first
|
||||
const nftAccount = await this.solanaKit.connection.getTokenAccountsByOwner(
|
||||
this.solanaKit.wallet_address,
|
||||
{ mint: new PublicKey(parsedInput.nftMint) }
|
||||
);
|
||||
|
||||
if (nftAccount.value.length === 0) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: "NFT not found in wallet. Please make sure you own this NFT.",
|
||||
code: "NFT_NOT_FOUND"
|
||||
});
|
||||
}
|
||||
|
||||
const tx = await this.solanaKit.tensorListNFT(
|
||||
new PublicKey(parsedInput.nftMint),
|
||||
parsedInput.price,
|
||||
parsedInput.expirySeconds
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "NFT listed for sale successfully",
|
||||
transaction: tx,
|
||||
price: parsedInput.price,
|
||||
nftMint: parsedInput.nftMint
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaBuyNFTTool extends Tool {
|
||||
name = "solana_buy_nft";
|
||||
description = `Buy an NFT listed on Tensor Trade.
|
||||
|
||||
Inputs (input is a JSON string):
|
||||
nftMint: string, the mint address of the NFT (required)
|
||||
maxPrice: number, maximum price willing to pay in SOL (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
|
||||
const tx = await this.solanaKit.tensorBuyNFT(
|
||||
new PublicKey(parsedInput.nftMint),
|
||||
parsedInput.maxPrice
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "NFT purchased successfully",
|
||||
transaction: tx,
|
||||
maxPrice: parsedInput.maxPrice,
|
||||
nftMint: parsedInput.nftMint
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class SolanaCancelNFTListingTool extends Tool {
|
||||
name = "solana_cancel_nft_listing";
|
||||
description = `Cancel an NFT listing on Tensor Trade.
|
||||
|
||||
Inputs (input is a JSON string):
|
||||
nftMint: string, the mint address of the NFT (required)`;
|
||||
|
||||
constructor(private solanaKit: SolanaAgentKit) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected async _call(input: string): Promise<string> {
|
||||
try {
|
||||
const parsedInput = JSON.parse(input);
|
||||
|
||||
const tx = await this.solanaKit.tensorCancelListing(
|
||||
new PublicKey(parsedInput.nftMint)
|
||||
);
|
||||
|
||||
return JSON.stringify({
|
||||
status: "success",
|
||||
message: "NFT listing cancelled successfully",
|
||||
transaction: tx,
|
||||
nftMint: parsedInput.nftMint
|
||||
});
|
||||
} catch (error: any) {
|
||||
return JSON.stringify({
|
||||
status: "error",
|
||||
message: error.message,
|
||||
code: error.code || "UNKNOWN_ERROR"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
return [
|
||||
new SolanaBalanceTool(solanaKit),
|
||||
@@ -1362,5 +1489,8 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) {
|
||||
new SolanaCreateGibworkTask(solanaKit),
|
||||
new SolanaRockPaperScissorsTool(solanaKit),
|
||||
new SolanaTipLinkTool(solanaKit),
|
||||
new SolanaListNFTForSaleTool(solanaKit),
|
||||
new SolanaBuyNFTTool(solanaKit),
|
||||
new SolanaCancelNFTListingTool(solanaKit),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -40,3 +40,5 @@ export * from "./create_gibwork_task";
|
||||
|
||||
export * from "./rock_paper_scissor";
|
||||
export * from "./create_tiplinks";
|
||||
|
||||
export * from "./tensor_trade";
|
||||
|
||||
112
src/tools/tensor_trade.ts
Normal file
112
src/tools/tensor_trade.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { SolanaAgentKit } from "../index";
|
||||
import { TCompSDK } from "@tensor-oss/tcomp-sdk";
|
||||
import { PublicKey, Transaction } from "@solana/web3.js";
|
||||
import { AnchorProvider, Wallet } from "@coral-xyz/anchor";
|
||||
import { BN } from "bn.js";
|
||||
import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID, getAccount } from '@solana/spl-token';
|
||||
|
||||
export async function listNFTForSale(
|
||||
agent: SolanaAgentKit,
|
||||
nftMint: PublicKey,
|
||||
price: number,
|
||||
expirySeconds?: number
|
||||
): Promise<string> {
|
||||
try {
|
||||
const mintInfo = await agent.connection.getAccountInfo(nftMint);
|
||||
if (!mintInfo) {
|
||||
throw new Error(`NFT mint ${nftMint.toString()} does not exist`);
|
||||
}
|
||||
|
||||
const ata = await getAssociatedTokenAddress(
|
||||
nftMint,
|
||||
agent.wallet_address
|
||||
);
|
||||
|
||||
try {
|
||||
const tokenAccount = await getAccount(
|
||||
agent.connection,
|
||||
ata
|
||||
);
|
||||
console.log("Token Account:", tokenAccount);
|
||||
} catch (e) {
|
||||
console.error("Token account error:", e);
|
||||
throw new Error(`No token account found for mint ${nftMint.toString()}`);
|
||||
}
|
||||
|
||||
const provider = new AnchorProvider(
|
||||
agent.connection,
|
||||
new Wallet(agent.wallet),
|
||||
AnchorProvider.defaultOptions()
|
||||
);
|
||||
|
||||
const tcompSdk = new TCompSDK({ provider });
|
||||
const priceInLamports = new BN(price * 1e9);
|
||||
const expiry = expirySeconds ? new BN(expirySeconds) : null;
|
||||
|
||||
const { tx } = await tcompSdk.listCore({
|
||||
asset: nftMint,
|
||||
owner: agent.wallet_address,
|
||||
amount: priceInLamports,
|
||||
expireInSec: expiry
|
||||
});
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(...tx.ixs);
|
||||
return await agent.connection.sendTransaction(transaction, [agent.wallet, ...tx.extraSigners]);
|
||||
} catch (error: any) {
|
||||
console.error("Full error details:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function buyNFT(
|
||||
agent: SolanaAgentKit,
|
||||
nftMint: PublicKey,
|
||||
maxPrice: number
|
||||
): Promise<string> {
|
||||
const provider = new AnchorProvider(
|
||||
agent.connection,
|
||||
new Wallet(agent.wallet),
|
||||
AnchorProvider.defaultOptions()
|
||||
);
|
||||
|
||||
const tcompSdk = new TCompSDK({ provider });
|
||||
const maxPriceInLamports = new BN(maxPrice * 1e9);
|
||||
|
||||
const { tx } = await tcompSdk.buyCore({
|
||||
asset: nftMint,
|
||||
buyer: agent.wallet_address,
|
||||
maxAmount: maxPriceInLamports,
|
||||
owner: agent.wallet_address,
|
||||
rentDest: agent.wallet_address,
|
||||
payer: agent.wallet_address,
|
||||
makerBroker: null
|
||||
});
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(...tx.ixs);
|
||||
return await agent.connection.sendTransaction(transaction, [agent.wallet, ...tx.extraSigners]);
|
||||
}
|
||||
|
||||
export async function cancelListing(
|
||||
agent: SolanaAgentKit,
|
||||
nftMint: PublicKey
|
||||
): Promise<string> {
|
||||
const provider = new AnchorProvider(
|
||||
agent.connection,
|
||||
new Wallet(agent.wallet),
|
||||
AnchorProvider.defaultOptions()
|
||||
);
|
||||
|
||||
const tcompSdk = new TCompSDK({ provider });
|
||||
|
||||
const { tx } = await tcompSdk.delistCore({
|
||||
asset: nftMint,
|
||||
owner: agent.wallet_address,
|
||||
rentDest: agent.wallet_address
|
||||
});
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(...tx.ixs);
|
||||
return await agent.connection.sendTransaction(transaction, [agent.wallet, ...tx.extraSigners]);
|
||||
}
|
||||
Reference in New Issue
Block a user