-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* plugin: spl token * lint * get_solana_token_balance_by_mint_address * better
- Loading branch information
Showing
16 changed files
with
445 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"name": "@goat-sdk/plugin-spl-token", | ||
"version": "0.0.1", | ||
"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:*", | ||
"@solana/web3.js": "catalog:", | ||
"@solana/spl-token": "0.4.9", | ||
"zod": "catalog:" | ||
}, | ||
"peerDependencies": { | ||
"@goat-sdk/core": "workspace:*" | ||
}, | ||
"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"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./plugin"; | ||
export * from "./tokens"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { getAssociatedTokenAddressSync } from "@solana/spl-token"; | ||
import { type Connection, PublicKey } from "@solana/web3.js"; | ||
|
||
export async function balanceOf(connection: Connection, walletAddress: string, tokenAddress: string) { | ||
const tokenAccount = getAssociatedTokenAddressSync(new PublicKey(tokenAddress), new PublicKey(walletAddress)); | ||
const balance = await connection.getTokenAccountBalance(tokenAccount); | ||
return balance; | ||
} |
58 changes: 58 additions & 0 deletions
58
typescript/packages/plugins/spl-token/src/methods/transfer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import type { SolanaWalletClient } from "@goat-sdk/core"; | ||
import { | ||
createAssociatedTokenAccountInstruction, | ||
createTransferCheckedInstruction, | ||
getAssociatedTokenAddressSync, | ||
} from "@solana/spl-token"; | ||
import { type Connection, PublicKey, type TransactionInstruction } from "@solana/web3.js"; | ||
import type { SolanaNetwork } from "../tokens"; | ||
import { doesAccountExist } from "../utils/doesAccountExist"; | ||
import { getTokenByMintAddress } from "../utils/getTokenByMintAddress"; | ||
|
||
export async function transfer( | ||
connection: Connection, | ||
network: SolanaNetwork, | ||
walletClient: SolanaWalletClient, | ||
to: string, | ||
tokenMintAddress: string, | ||
amount: string, | ||
) { | ||
const token = getTokenByMintAddress(tokenMintAddress, network); | ||
if (!token) { | ||
throw new Error(`Token with mint address ${tokenMintAddress} not found`); | ||
} | ||
|
||
const tokenMintPublicKey = new PublicKey(tokenMintAddress); | ||
const fromPublicKey = new PublicKey(walletClient.getAddress()); | ||
const toPublicKey = new PublicKey(to); | ||
|
||
const fromTokenAccount = getAssociatedTokenAddressSync(tokenMintPublicKey, fromPublicKey); | ||
const toTokenAccount = getAssociatedTokenAddressSync(tokenMintPublicKey, toPublicKey); | ||
|
||
const fromAccountExists = await doesAccountExist(connection, fromTokenAccount); | ||
const toAccountExists = await doesAccountExist(connection, toTokenAccount); | ||
|
||
if (!fromAccountExists) { | ||
throw new Error(`From account ${fromTokenAccount.toBase58()} does not exist`); | ||
} | ||
|
||
const instructions: TransactionInstruction[] = []; | ||
|
||
if (!toAccountExists) { | ||
instructions.push( | ||
createAssociatedTokenAccountInstruction(fromPublicKey, toTokenAccount, toPublicKey, tokenMintPublicKey), | ||
); | ||
} | ||
instructions.push( | ||
createTransferCheckedInstruction( | ||
fromTokenAccount, | ||
tokenMintPublicKey, | ||
toTokenAccount, | ||
fromPublicKey, | ||
BigInt(amount) * BigInt(10) ** BigInt(token.decimals), | ||
token.decimals, | ||
), | ||
); | ||
|
||
return await walletClient.sendTransaction({ instructions }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { z } from "zod"; | ||
import { splTokenSymbolSchema } from "./tokens"; | ||
|
||
export const getTokenMintAddressBySymbolParametersSchema = z.object({ | ||
symbol: splTokenSymbolSchema.describe("The symbol of the token to get the mint address of"), | ||
}); | ||
|
||
export const getTokenBalanceByMintAddressParametersSchema = z.object({ | ||
walletAddress: z.string().describe("The address to get the balance of"), | ||
mintAddress: z.string().describe("The mint address of the token to get the balance of"), | ||
}); | ||
|
||
export const transferTokenByMintAddressParametersSchema = z.object({ | ||
mintAddress: z.string().describe("The mint address of the token to transfer"), | ||
to: z.string().describe("The address to transfer the token to"), | ||
amount: z.string().describe("The amount of tokens to transfer"), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import type { Plugin, SolanaWalletClient } from "@goat-sdk/core"; | ||
import type { Connection } from "@solana/web3.js"; | ||
import type { SolanaNetwork, Token } from "./tokens"; | ||
import { getTokensForNetwork } from "./utils/getTokensForNetwork"; | ||
import { getTools } from "./utils/getTools"; | ||
|
||
export function splToken({ | ||
connection, | ||
network, | ||
}: { connection: Connection; network: SolanaNetwork }): Plugin<SolanaWalletClient> { | ||
return { | ||
name: "splToken", | ||
supportsSmartWallets: () => false, | ||
supportsChain: (chain) => chain.type === "solana", | ||
getTools: async () => getTools(connection, network), | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { z } from "zod"; | ||
|
||
export type SolanaNetwork = "devnet" | "mainnet"; | ||
|
||
export const splTokenSymbolSchema = z.enum(["USDC"]); | ||
export type SplTokenSymbol = z.infer<typeof splTokenSymbolSchema>; | ||
|
||
export type Token = { | ||
decimals: number; | ||
symbol: SplTokenSymbol; | ||
name: string; | ||
mintAddresses: Record<SolanaNetwork, string | null>; | ||
}; | ||
|
||
export type NetworkSpecificToken = Omit<Token, "mintAddresses"> & { | ||
network: SolanaNetwork; | ||
mintAddress: string; | ||
}; | ||
|
||
export const USDC: Token = { | ||
decimals: 6, | ||
symbol: splTokenSymbolSchema.Enum.USDC, | ||
name: "USDC", | ||
mintAddresses: { | ||
devnet: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", | ||
mainnet: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", | ||
}, | ||
}; | ||
|
||
export const SPL_TOKENS: Token[] = [USDC]; |
6 changes: 6 additions & 0 deletions
6
typescript/packages/plugins/spl-token/src/utils/doesAccountExist.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import type { Connection, PublicKey } from "@solana/web3.js"; | ||
|
||
export async function doesAccountExist(connection: Connection, address: PublicKey) { | ||
const account = await connection.getAccountInfo(address); | ||
return account != null; | ||
} |
8 changes: 8 additions & 0 deletions
8
typescript/packages/plugins/spl-token/src/utils/getTokenByMintAddress.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { SPL_TOKENS, type SolanaNetwork } from "../tokens"; | ||
import { getTokensForNetwork } from "./getTokensForNetwork"; | ||
|
||
export function getTokenByMintAddress(mintAddress: string, network: SolanaNetwork) { | ||
const tokensForNetwork = getTokensForNetwork(network, SPL_TOKENS); | ||
const token = tokensForNetwork.find((token) => token.mintAddress === mintAddress); | ||
return token || null; | ||
} |
8 changes: 8 additions & 0 deletions
8
typescript/packages/plugins/spl-token/src/utils/getTokenMintAddressBySymbol.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { SPL_TOKENS, type SolanaNetwork, type SplTokenSymbol } from "../tokens"; | ||
import { getTokensForNetwork } from "./getTokensForNetwork"; | ||
|
||
export function getTokenMintAddressBySymbol(symbol: SplTokenSymbol, network: SolanaNetwork) { | ||
const tokensForNetwork = getTokensForNetwork(network, SPL_TOKENS); | ||
const token = tokensForNetwork.find((token) => [token.symbol, token.symbol.toLowerCase()].includes(symbol)); | ||
return token?.mintAddress || null; | ||
} |
20 changes: 20 additions & 0 deletions
20
typescript/packages/plugins/spl-token/src/utils/getTokensForNetwork.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import type { NetworkSpecificToken, SolanaNetwork, Token } from "../tokens"; | ||
|
||
export function getTokensForNetwork(network: SolanaNetwork, tokens: Token[]) { | ||
const result: NetworkSpecificToken[] = []; | ||
|
||
for (const token of tokens) { | ||
const mintAddress = token.mintAddresses[network]; | ||
if (mintAddress) { | ||
result.push({ | ||
decimals: token.decimals, | ||
symbol: token.symbol, | ||
name: token.name, | ||
network, | ||
mintAddress, | ||
}); | ||
} | ||
} | ||
|
||
return result; | ||
} |
50 changes: 50 additions & 0 deletions
50
typescript/packages/plugins/spl-token/src/utils/getTools.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import type { DeferredTool, SolanaWalletClient } from "@goat-sdk/core"; | ||
import type { Connection } from "@solana/web3.js"; | ||
import type { z } from "zod"; | ||
import { balanceOf } from "../methods/balance"; | ||
import { transfer } from "../methods/transfer"; | ||
import { | ||
getTokenBalanceByMintAddressParametersSchema, | ||
getTokenMintAddressBySymbolParametersSchema, | ||
transferTokenByMintAddressParametersSchema, | ||
} from "../parameters"; | ||
import type { SolanaNetwork } from "../tokens"; | ||
import { getTokenMintAddressBySymbol } from "./getTokenMintAddressBySymbol"; | ||
|
||
export function getTools(connection: Connection, network: SolanaNetwork): DeferredTool<SolanaWalletClient>[] { | ||
const tools: DeferredTool<SolanaWalletClient>[] = []; | ||
|
||
tools.push({ | ||
name: "get_token_mint_address_by_symbol", | ||
description: "This {{tool}} gets the mint address of an SPL token by its symbol", | ||
parameters: getTokenMintAddressBySymbolParametersSchema, | ||
method: async ( | ||
walletClient: SolanaWalletClient, | ||
parameters: z.infer<typeof getTokenMintAddressBySymbolParametersSchema>, | ||
) => getTokenMintAddressBySymbol(parameters.symbol, network), | ||
}); | ||
|
||
tools.push({ | ||
name: "get_token_balance_by_mint_address", | ||
description: | ||
"This {{tool}} gets the balance of an SPL token by its mint address. Use get_token_mint_address_by_symbol to get the mint address first.", | ||
parameters: getTokenBalanceByMintAddressParametersSchema, | ||
method: async ( | ||
walletClient: SolanaWalletClient, | ||
parameters: z.infer<typeof getTokenBalanceByMintAddressParametersSchema>, | ||
) => balanceOf(connection, parameters.walletAddress, parameters.mintAddress), | ||
}); | ||
|
||
tools.push({ | ||
name: "transfer_token_by_mint_address", | ||
description: | ||
"This {{tool}} transfers an SPL token by its mint address. Use get_token_mint_address_by_symbol to get the mint address first.", | ||
parameters: transferTokenByMintAddressParametersSchema, | ||
method: async ( | ||
walletClient: SolanaWalletClient, | ||
parameters: z.infer<typeof transferTokenByMintAddressParametersSchema>, | ||
) => transfer(connection, network, walletClient, parameters.to, parameters.mintAddress, parameters.amount), | ||
}); | ||
|
||
return tools; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}); |
Oops, something went wrong.