Skip to content

Commit

Permalink
Plugin: Solana cNFT Transfers (goat-sdk#13)
Browse files Browse the repository at this point in the history
* changes

* changes

* changes

* changes

* changes

* fix formatter

* more diff fixing

* changes

* changes

* temp example

* changes

* fix build

* changes

* fix

* changes
  • Loading branch information
bryan-eastwood3 authored and youssefea committed Dec 17, 2024
1 parent 7703f48 commit 1547668
Show file tree
Hide file tree
Showing 11 changed files with 5,835 additions and 82 deletions.
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"create-wallet": "ts-node create-custodial-wallet.ts",
"test": "vitest run --passWithNoTests"
},
"main": "index.ts",
"author": "",
"license": "MIT",
"dependencies": {
Expand All @@ -15,6 +16,7 @@
"@goat-sdk/core": "workspace:*",
"@goat-sdk/plugin-erc20": "workspace:*",
"@goat-sdk/crossmint": "workspace:*",
"@goat-sdk/plugin-solana-nfts": "workspace:*",
"@solana/web3.js": "1.95.8",
"ai": "^4.0.3",
"dotenv": "^16.4.5",
Expand Down
12 changes: 10 additions & 2 deletions typescript/packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
"name": "@goat-sdk/core",
"version": "0.3.10",
"sideEffects": false,
"files": ["dist/**/*", "README.md", "package.json"],
"files": [
"dist/**/*",
"README.md",
"package.json"
],
"scripts": {
"build": "tsup",
"clean": "rm -rf dist",
Expand All @@ -26,5 +30,9 @@
"bugs": {
"url": "https://github.com/goat-sdk/goat/issues"
},
"keywords": ["ai", "agents", "web3"]
"keywords": [
"ai",
"agents",
"web3"
]
}
2 changes: 1 addition & 1 deletion typescript/packages/core/src/wallets/solana.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TransactionInstruction } from "@solana/web3.js";
import type { Connection, TransactionInstruction } from "@solana/web3.js";
import type { WalletClient } from "./core";

export function isSolanaWalletClient(wallet: WalletClient): wallet is SolanaWalletClient {
Expand Down
39 changes: 39 additions & 0 deletions typescript/packages/plugins/solana-nfts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@goat-sdk/plugin-solana-nfts",
"version": "0.1.0",
"files": ["dist/**/*", "README.md", "package.json"],
"scripts": {
"build": "tsup",
"clean": "rm -rf dist",
"test": "vitest run --passWithNoTests"
},
"sideEffects": false,
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"dependencies": {
"@goat-sdk/core": "workspace:*",
"@metaplex-foundation/digital-asset-standard-api": "1.0.0",
"@metaplex-foundation/mpl-bubblegum": "3.1.0",
"@metaplex-foundation/umi": "^0.9.2",
"@metaplex-foundation/umi-bundle-defaults": "0.9.2",
"@metaplex-foundation/umi-web3js-adapters": "0.8.10",
"@solana/web3.js": "1.95.8",
"viem": "^2.21.49",
"zod": "^3.23.8"
},
"peerDependencies": {
"@goat-sdk/core": "workspace:*",
"viem": "^2.21.49"
},
"homepage": "https://ohmygoat.dev",
"repository": {
"type": "git",
"url": "git+https://github.com/goat-sdk/goat.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/goat-sdk/goat/issues"
},
"keywords": ["ai", "agents", "web3"]
}
1 change: 1 addition & 0 deletions typescript/packages/plugins/solana-nfts/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./nfts";
52 changes: 52 additions & 0 deletions typescript/packages/plugins/solana-nfts/src/nfts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { type Connection, PublicKey } from "@solana/web3.js";
import { z } from "zod";
import type { Plugin, SolanaWalletClient } from "@goat-sdk/core";
import { getAssetWithProof, mplBubblegum, transfer } from "@metaplex-foundation/mpl-bubblegum";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { fromWeb3JsPublicKey, toWeb3JsInstruction } from "@metaplex-foundation/umi-web3js-adapters";

export function nfts(connection: Connection): Plugin<SolanaWalletClient> {
return {
name: "nfts",
supportsSmartWallets: () => false,
supportsChain: (chain) => chain.type === "solana",
getTools: async () => {
return [
{
name: "transfer_nft",
description: "This {{tool}} sends an NFT from your wallet to an address on a Solana chain.",
parameters: transferNFTParametersSchema,
method: transferNFTMethod(connection),
},
];
},
};
}

const transferNFTParametersSchema = z.object({
recipientAddress: z.string().describe("The address to send the NFT to"),
assetId: z.string().describe("The asset ID of the NFT to send"),
});

const transferNFTMethod =
(connection: Connection) =>
async (
walletClient: SolanaWalletClient,
parameters: z.infer<typeof transferNFTParametersSchema>,
): Promise<string> => {
const { recipientAddress, assetId } = parameters;
const umi = createUmi(connection);
umi.use(mplBubblegum());
const assetWithProof = await getAssetWithProof(umi, fromWeb3JsPublicKey(new PublicKey(assetId)));
const instructions = transfer(umi, {
...assetWithProof,
leafOwner: fromWeb3JsPublicKey(new PublicKey(walletClient.getAddress())),
newLeafOwner: fromWeb3JsPublicKey(new PublicKey(recipientAddress)),
}).getInstructions();

const result = await walletClient.sendTransaction({
instructions: instructions.map(toWeb3JsInstruction),
});

return result.hash;
};
6 changes: 6 additions & 0 deletions typescript/packages/plugins/solana-nfts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../../../tsconfig.base.json",
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
6 changes: 6 additions & 0 deletions typescript/packages/plugins/solana-nfts/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineConfig } from "tsup";
import { treeShakableConfig } from "../../../tsup.config.base";

export default defineConfig({
...treeShakableConfig,
});
9 changes: 4 additions & 5 deletions typescript/packages/wallets/crossmint/src/custodial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function custodialFactory(apiKey: string) {
return async function custodial(params: CustodialOptions): Promise<SolanaWalletClient> {
const { connection, env = "staging" } = params;

const locator = `${getLocator(params)}:solana-custodial-wallet`;
const locator = `${getLocator(params)}`;
const client = createCrossmintAPI(apiKey, env);
const { address } = await client.getWallet(locator);

Expand Down Expand Up @@ -83,11 +83,10 @@ export function custodialFactory(apiKey: string) {
}
},
async sendTransaction({ instructions }: SolanaTransaction) {
const latestBlockhash = await connection.getLatestBlockhash("confirmed");
const publicKey = new PublicKey("11111111111111111111111111111112");
const message = new TransactionMessage({
// Placeholder payer key since Crossmint will override it
payerKey: new PublicKey("placeholder"),
recentBlockhash: latestBlockhash.blockhash,
payerKey: publicKey,
recentBlockhash: "11111111111111111111111111111111",
instructions,
}).compileToV0Message();
const transaction = new VersionedTransaction(message);
Expand Down
Loading

0 comments on commit 1547668

Please sign in to comment.