├── .yarnrc.yml ├── src ├── schema │ ├── index.ts │ └── schema.ts ├── tools │ ├── index.ts │ ├── caishen │ │ ├── cash │ │ │ ├── index.ts │ │ │ ├── get-supported-tokens.ts │ │ │ ├── balance.ts │ │ │ ├── deposit.ts │ │ │ ├── send.ts │ │ │ └── withdraw.ts │ │ ├── crypto │ │ │ ├── index.ts │ │ │ ├── get_chains.ts │ │ │ ├── balance_others.ts │ │ │ ├── get_rpc.ts │ │ │ ├── balance.ts │ │ │ ├── swap.ts │ │ │ ├── send.ts │ │ │ └── swap_route.ts │ │ └── index.ts │ ├── tool-base.ts │ ├── interfaces │ │ └── index.ts │ └── get-tools.ts ├── constants │ ├── index.ts │ ├── app.ts │ ├── chain-ids.ts │ └── public-rpc-endpoints.ts ├── crypto │ ├── index.ts │ ├── send.ts │ ├── balance.ts │ ├── sign.ts │ ├── swap.ts │ └── wallets.ts ├── adapters │ ├── index.ts │ ├── eleven-labs │ │ └── createElevenLabsTools.ts │ ├── langchain │ │ └── createLangChainTools.ts │ └── vercel-ai │ │ └── createVercelAITools.ts ├── index.ts ├── api │ └── index.ts ├── mcp │ └── index.ts ├── cash │ ├── index.ts │ └── schema.ts ├── types │ └── index.ts └── caishen.ts ├── test ├── support │ ├── index.ts │ └── blockchain-configs.ts └── integration │ ├── cash.spec.ts │ ├── auth.spec.ts │ ├── crypto.spec.ts │ └── swap.spec.ts ├── jest.config.js ├── .prettierrc ├── tsconfig.json ├── .gitignore ├── package.json └── README.md /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /src/schema/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schema' -------------------------------------------------------------------------------- /src/tools/index.ts: -------------------------------------------------------------------------------- 1 | export * from './caishen'; -------------------------------------------------------------------------------- /test/support/index.ts: -------------------------------------------------------------------------------- 1 | export * from './blockchain-configs'; 2 | -------------------------------------------------------------------------------- /src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app'; 2 | export * from './chain-ids'; 3 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | }; -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all", 4 | "tabWidth": 2, 5 | "semi": true 6 | } 7 | -------------------------------------------------------------------------------- /src/crypto/index.ts: -------------------------------------------------------------------------------- 1 | export * from './send'; 2 | export * from './sign'; 3 | export * from './swap'; 4 | export * from './balance'; 5 | export * from './wallets'; 6 | -------------------------------------------------------------------------------- /src/adapters/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./eleven-labs/createElevenLabsTools" 2 | export * from "./langchain/createLangChainTools" 3 | export * from "./vercel-ai/createVercelAITools" 4 | -------------------------------------------------------------------------------- /src/tools/caishen/cash/index.ts: -------------------------------------------------------------------------------- 1 | export * from './send'; 2 | export * from './deposit'; 3 | export * from './withdraw'; 4 | export * from "./get-supported-tokens"; 5 | export * from './balance'; -------------------------------------------------------------------------------- /src/tools/caishen/crypto/index.ts: -------------------------------------------------------------------------------- 1 | export * from './balance'; 2 | export * from './balance_others'; 3 | export * from './get_chains'; 4 | export * from './get_rpc'; 5 | export * from './send'; 6 | export * from './swap'; 7 | export * from './swap_route'; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { CaishenSDK } from './caishen'; 2 | import { createAgentTools } from './tools'; 3 | import { McpClient } from './mcp'; 4 | 5 | export * from './constants' 6 | export * from './types' 7 | export * from './adapters' 8 | 9 | export { CaishenSDK, McpClient, createAgentTools }; 10 | -------------------------------------------------------------------------------- /src/tools/tool-base.ts: -------------------------------------------------------------------------------- 1 | import type { z } from 'zod'; 2 | 3 | export function toolBase({ 4 | name, 5 | description, 6 | parameters, 7 | execute, 8 | }: { 9 | name: string; 10 | description: string; 11 | parameters: T; 12 | execute: (params: z.infer) => Promise; 13 | }) { 14 | return { 15 | name, 16 | description, 17 | parameters, 18 | execute, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/constants/app.ts: -------------------------------------------------------------------------------- 1 | export const BASE_URL = 'https://build.caishen.tech'; 2 | export enum ChainType { 3 | BITCOIN = 'BITCOIN', 4 | LITECOIN = 'LITECOIN', 5 | DASHCOIN = 'DASHCOIN', 6 | DOGECOIN = 'DOGECOIN', 7 | SOLANA = 'SOLANA', 8 | ETHEREUM = 'ETHEREUM', 9 | SUI = 'SUI', 10 | APTOS = 'APTOS', 11 | TON = 'TON', 12 | NEAR = 'NEAR', 13 | TRON = 'TRON', 14 | XRP = 'XRP', 15 | CARDANO = 'CARDANO', 16 | COSMOS = 'COSMOS', 17 | } 18 | -------------------------------------------------------------------------------- /src/api/index.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export const ApiClient = axios.create({ 4 | baseURL: process.env.CAISHEN_API_URL || 'http://localhost:8080/api', 5 | headers: { 6 | 'Content-Type': 'application/json', 7 | }, 8 | }); 9 | 10 | ApiClient.interceptors.request.use((config) => { 11 | return config; 12 | }); 13 | 14 | ApiClient.interceptors.response.use( 15 | (response) => response, 16 | (error) => { 17 | return Promise.reject(error); 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "ESNext", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "sourceMap": true, 8 | "outDir": "dist", 9 | "resolveJsonModule": true, 10 | "esModuleInterop": true, 11 | "moduleResolution": "node", 12 | "strict": true, 13 | "isolatedModules": true, 14 | "skipLibCheck": true, 15 | "experimentalDecorators": true, 16 | "emitDecoratorMetadata": true 17 | }, 18 | "include": ["src"], 19 | "exclude": ["dist", "node_modules", "test"] 20 | } 21 | -------------------------------------------------------------------------------- /src/tools/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | import { toolBase } from '../tool-base'; 2 | 3 | export interface Tools { 4 | cash_get_balance: ReturnType; 5 | cash_deposit: ReturnType; 6 | cash_send: ReturnType; 7 | cash_withdraw: ReturnType; 8 | crypto_get_balance: ReturnType; 9 | send_crypto: ReturnType; 10 | sign_and_send: ReturnType; 11 | sign: ReturnType; 12 | swap_crypto: ReturnType; 13 | crypto_get_swap_route: ReturnType; 14 | } -------------------------------------------------------------------------------- /src/adapters/eleven-labs/createElevenLabsTools.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | import { CaishenSDK } from '../../caishen'; 3 | import { getTools } from '../../tools/get-tools'; 4 | 5 | type Tool = (params: z.infer) => Promise; 6 | 7 | export async function createElevenLabsTools({ sdk }: { sdk: CaishenSDK }) { 8 | const tools = await getTools({ sdk }); 9 | 10 | return Object.values(tools).reduce((acc, tool) => { 11 | acc[tool.name] = async (params: any) => { 12 | return await tool.execute(params); 13 | }; 14 | return acc; 15 | }, {} as Record>); 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | dist 5 | node_modules 6 | 7 | /.yarn 8 | .yarn 9 | .pnp.loader.mjs 10 | .pnp.cjs 11 | .yarn/* 12 | 13 | # Logs 14 | logs 15 | *.log 16 | npm-debug.log* 17 | pnpm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | lerna-debug.log* 21 | 22 | # OS 23 | .DS_Store 24 | 25 | # Tests 26 | /coverage 27 | /.nyc_output 28 | 29 | # IDEs and editors 30 | /.idea 31 | .project 32 | .classpath 33 | .c9/ 34 | *.launch 35 | .settings/ 36 | *.sublime-workspace 37 | 38 | # IDE - VSCode 39 | .vscode/* 40 | !.vscode/settings.json 41 | !.vscode/tasks.json 42 | !.vscode/launch.json 43 | !.vscode/extensions.json 44 | 45 | #Env 46 | *.env -------------------------------------------------------------------------------- /src/adapters/langchain/createLangChainTools.ts: -------------------------------------------------------------------------------- 1 | import { tool } from '@langchain/core/tools'; 2 | import { z } from 'zod'; 3 | import { CaishenSDK } from '../../caishen'; 4 | import { getTools } from '../../tools/get-tools'; 5 | 6 | export async function createLangchainTools({ sdk }: { sdk: CaishenSDK }) { 7 | const tools = getTools({ sdk }); 8 | 9 | return Object.values(tools).map((t) => 10 | tool( 11 | async (arg) => { 12 | const execute = t.execute as unknown as ( 13 | params: z.infer, 14 | ) => Promise>; 15 | return await execute(arg); 16 | }, 17 | { 18 | name: t.name, 19 | description: t.description, 20 | schema: t.parameters, 21 | }, 22 | ), 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /src/adapters/vercel-ai/createVercelAITools.ts: -------------------------------------------------------------------------------- 1 | import { tool, ToolSet } from 'ai'; 2 | import { z } from 'zod'; 3 | import { CaishenSDK } from '../../caishen'; 4 | import { getTools } from '../../tools/get-tools'; 5 | 6 | export async function createVercelAITools({ sdk }: { sdk: CaishenSDK }) { 7 | const tools = await getTools({ sdk }); 8 | 9 | const vercelAITools = Object.values(tools).reduce((acc, t) => { 10 | acc[t.name] = tool({ 11 | description: t.description, 12 | parameters: t.parameters, 13 | execute: async (params) => { 14 | const execute = t.execute as unknown as ( 15 | params: z.infer, 16 | ) => Promise>; 17 | return await execute(params); 18 | }, 19 | }); 20 | return acc; 21 | }, {} as ToolSet); 22 | 23 | return vercelAITools; 24 | } 25 | -------------------------------------------------------------------------------- /src/mcp/index.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { BASE_URL } from '../constants'; 4 | import { InvokeTool } from '../types'; 5 | 6 | export class McpClient { 7 | /** 8 | * Fetches all available MCP tools 9 | */ 10 | async getAllTools() { 11 | const response = await axios.get(`${BASE_URL}/mcp/tools`); 12 | return response.data; 13 | } 14 | 15 | /** 16 | * Fetches schema for a specific tool 17 | */ 18 | async getToolSchema(toolId: string) { 19 | const response = await axios.get(`${BASE_URL}/mcp/tools/${toolId}`); 20 | return response.data; 21 | } 22 | 23 | /** 24 | * Calls a tool endpoint with config obtained from `getToolSchema`. 25 | */ 26 | async invokeTool(invokeToolDto: InvokeTool) { 27 | const response = await axios.post(`${BASE_URL}/mcp/invokeTool`, invokeToolDto); 28 | return response.data; 29 | } 30 | } -------------------------------------------------------------------------------- /src/tools/caishen/cash/get-supported-tokens.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCashGetSupportedTokensTool extends Tool { 5 | name = 'cash_get_supported_tokens'; 6 | description = `Fetch the list of supported tokens for cash operations. 7 | 8 | No input required. 9 | `; 10 | 11 | constructor(private sdk: CaishenSDK) { 12 | super(); 13 | } 14 | 15 | protected async _call(_input: string): Promise { 16 | try { 17 | const tokens = await this.sdk.cash.getSupportedTokens(); 18 | 19 | return JSON.stringify({ 20 | status: 'success', 21 | tokens, 22 | }); 23 | } catch (error: any) { 24 | return JSON.stringify({ 25 | status: 'error', 26 | message: error.message, 27 | code: error.code || 'CASH_GET_SUPPORTED_TOKENS_ERROR', 28 | }); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/tools/caishen/crypto/get_chains.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCryptoGetSupportedChainTypesTool extends Tool { 5 | name = 'crypto_get_supported_chain_types'; 6 | description = `Fetch the list of supported chain types for creating wallets. 7 | 8 | No input required. 9 | `; 10 | 11 | constructor(private sdk: CaishenSDK) { 12 | super(); 13 | } 14 | 15 | protected async _call(_input: string): Promise { 16 | try { 17 | const chainTypes = await this.sdk.crypto.getSupportedChainTypes(); 18 | 19 | return JSON.stringify({ 20 | status: 'success', 21 | chainTypes, 22 | }); 23 | } catch (error: any) { 24 | return JSON.stringify({ 25 | status: 'error', 26 | message: error.message || 'Failed to get supported chain types', 27 | code: error.code || 'CRYPTO_GET_SUPPORTED_CHAIN_TYPES_ERROR', 28 | }); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/crypto/send.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { BASE_URL } from '../constants'; 4 | import type { CaishenSDK } from '../caishen'; 5 | import { BaseRequest, SendTransactionPayload, WalletAccount } from '../types'; 6 | 7 | /** 8 | * Execute basic token transfer. 9 | * @param request 10 | */ 11 | export async function send( 12 | this: CaishenSDK, 13 | request: BaseRequest 14 | ): Promise { 15 | const { 16 | wallet, 17 | payload, 18 | authToken = this.userToken || this.agentToken, 19 | } = request; 20 | 21 | if (!authToken) { 22 | throw new Error('Authentication token required. Connect as user/agent first or pass authorization token separately.'); 23 | } 24 | 25 | const url = `${BASE_URL}/api/crypto/send`; 26 | const response = await axios.post( 27 | url, 28 | { 29 | wallet, 30 | payload, 31 | }, 32 | { 33 | headers: { 34 | Authorization: `Bearer ${authToken}`, 35 | }, 36 | }, 37 | ); 38 | 39 | return response.data; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/crypto/balance.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import type { CaishenSDK } from '../caishen'; 4 | import { BaseRequest, WalletAccount, GetBalancePayload } from '../types'; 5 | import { BASE_URL } from '../constants'; 6 | 7 | /** 8 | * Gets token balance. 9 | * @param request 10 | */ 11 | export async function getBalance( 12 | this: CaishenSDK, 13 | request: BaseRequest< 14 | WalletAccount, 15 | GetBalancePayload | undefined 16 | >, 17 | ): Promise { 18 | const { 19 | wallet, 20 | payload = {}, 21 | authToken = this.userToken || this.agentToken, 22 | } = request; 23 | 24 | if (!authToken) { 25 | throw new Error('Authentication token required. Connect as user/agent first or pass authorization token separately.'); 26 | } 27 | 28 | const url = `${BASE_URL}/api/crypto/balance`; 29 | const response = await axios.get(url, { 30 | params: { 31 | ...wallet, 32 | tokenAddress: payload.token, 33 | }, 34 | headers: { 35 | Authorization: `Bearer ${authToken}`, 36 | }, 37 | }); 38 | return BigInt(response.data); 39 | } 40 | -------------------------------------------------------------------------------- /src/tools/caishen/cash/balance.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCashGetBalanceTool extends Tool { 5 | name = 'cash_get_balance'; 6 | description = `Retrieve the cash balance of a specified account. 7 | 8 | Inputs (JSON string): 9 | - account: number (required) — the account number to fetch the balance for. 10 | `; 11 | 12 | constructor(private sdk: CaishenSDK) { 13 | super(); 14 | } 15 | 16 | protected async _call(input: string): Promise { 17 | try { 18 | const parsedInput = JSON.parse(input); 19 | 20 | if (typeof parsedInput.account !== 'number') { 21 | throw new Error('account field must be a number'); 22 | } 23 | 24 | const result = await this.sdk.cash.getBalance(parsedInput); 25 | 26 | return JSON.stringify({ 27 | status: 'success', 28 | balance: result, 29 | }); 30 | } catch (error: any) { 31 | return JSON.stringify({ 32 | status: 'error', 33 | message: error.message, 34 | code: error.code || 'CASH_GET_BALANCE_ERROR', 35 | }); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/tools/caishen/crypto/balance_others.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenBalanceOtherTool extends Tool { 5 | name = 'caishen_balance_other'; 6 | description = `Get the balance of ANOTHER wallet (not your own) or token account on Caishen.`; 7 | 8 | constructor(private sdk: CaishenSDK) { 9 | super(); 10 | } 11 | 12 | protected async _call(input: string): Promise { 13 | try { 14 | const parsedInput = JSON.parse(input); 15 | 16 | const balance = await this.sdk.crypto.getBalance({ 17 | wallet: { 18 | chainType: parsedInput.chainType, 19 | account: parsedInput.account, 20 | chainId: parsedInput.chainId, 21 | }, 22 | payload: { token: parsedInput.tokenAddress }, 23 | }); 24 | 25 | return JSON.stringify({ 26 | status: 'success', 27 | balance, 28 | }); 29 | } catch (error: any) { 30 | return JSON.stringify({ 31 | status: 'error', 32 | message: error.message, 33 | code: error.code || 'UNKNOWN_ERROR', 34 | }); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/tools/caishen/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cash'; 2 | export * from './crypto'; 3 | 4 | import type { CaishenSDK } from '../../caishen'; 5 | import { 6 | CaishenCryptoGetBalanceTool, 7 | CaishenCryptoGetRPCTool, 8 | CaishenCryptoGetSupportedChainTypesTool, 9 | CaishenCryptoGetSwapRouteTool, 10 | CaishenCryptoSendTool, 11 | CaishenBalanceOtherTool, 12 | CaishenCryptoSwapTool, 13 | CaishenCashDepositTool, 14 | CaishenCashGetBalanceTool, 15 | CaishenCashGetSupportedTokensTool, 16 | CaishenCashSendTool, 17 | CaishenCashWithdrawTool 18 | } from './index'; 19 | 20 | export function createAgentTools(sdk: CaishenSDK) { 21 | return [ 22 | new CaishenCryptoGetBalanceTool(sdk), 23 | new CaishenCryptoGetRPCTool(sdk), 24 | new CaishenCryptoGetSupportedChainTypesTool(sdk), 25 | new CaishenCryptoGetSwapRouteTool(sdk), 26 | new CaishenCryptoSendTool(sdk), 27 | new CaishenBalanceOtherTool(sdk), 28 | new CaishenCryptoSwapTool(sdk), 29 | new CaishenCashDepositTool(sdk), 30 | new CaishenCashGetBalanceTool(sdk), 31 | new CaishenCashGetSupportedTokensTool(sdk), 32 | new CaishenCashSendTool(sdk), 33 | new CaishenCashWithdrawTool(sdk), 34 | ]; 35 | } 36 | -------------------------------------------------------------------------------- /src/tools/caishen/crypto/get_rpc.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCryptoGetRPCTool extends Tool { 5 | name = 'crypto_get_rpc'; 6 | description = `Fetch the RPC endpoint for a given chain ID. 7 | 8 | Input (JSON string): 9 | - chainId: The chain ID for which you want the RPC endpoint (e.g., 1 for Ethereum). 10 | `; 11 | 12 | constructor(private sdk: CaishenSDK) { 13 | super(); 14 | } 15 | 16 | protected async _call(input: string): Promise { 17 | try { 18 | const parsedInput = JSON.parse(input); 19 | const { chainId } = parsedInput; 20 | 21 | if (!chainId) { 22 | throw new Error('chainId is required'); 23 | } 24 | 25 | const rpcEndpoint = await this.sdk.crypto.getRPC(chainId); 26 | 27 | return JSON.stringify({ 28 | status: 'success', 29 | chainId, 30 | rpcEndpoint, 31 | }); 32 | } catch (error: any) { 33 | return JSON.stringify({ 34 | status: 'error', 35 | message: error.message || 'Failed to get RPC endpoint', 36 | code: error.code || 'CRYPTO_GET_RPC_ERROR', 37 | }); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/constants/chain-ids.ts: -------------------------------------------------------------------------------- 1 | enum ChainIds { 2 | AURORA = 1313161554, 3 | MAINNET = 1, 4 | RINKEBY = 4, 5 | GOERLI = 5, 6 | GNOSIS = 100, 7 | OPTIMISM = 10, 8 | KOVAN = 42, 9 | FUJI = 43113, 10 | AVALANCHE = 43114, 11 | NEWMONEY_CHAIN = 7234935, 12 | SMART_CHAIN = 56, 13 | SMART_CHAIN_TEST = 97, 14 | MOONBASE_ALPHA = 1287, 15 | MOONRIVER = 1285, 16 | MUMBAI = 80001, 17 | MATIC = 137, 18 | MODE = 34443, 19 | HECO = 128, 20 | FANTOM = 250, 21 | SHIDEN = 336, 22 | IOTEX = 4689, 23 | HARMONY = 1666600000, 24 | CRONOS = 25, 25 | OKEX = 66, 26 | MULTIVAC = 62621, 27 | METIS_NETWORK = 1088, 28 | MOONBEAM = 1284, 29 | METIS_STARDUST = 588, 30 | ARBITRUM = 42161, 31 | ARBITRUM_TEST = 421611, 32 | KLAYTN = 8217, 33 | BASE = 8453, 34 | MANTLE = 5000, 35 | SOLANA = 101, 36 | SOLANA_LIFI = 1151111081099710, 37 | SOLANA_LEGACY = 3333, 38 | BITCOIN = 1800, 39 | LITECOIN = 1801, 40 | DASHCOIN = 1802, 41 | DOGECOIN = 1803, 42 | BITCOIN_LIFI = 20000000000001, 43 | SUI = 2, 44 | APTOS = 1400, 45 | RIPPLE = 1500, 46 | TON = 1600, 47 | COSMOS = 1900, 48 | TRON = 2000, 49 | NEAR = 3000, 50 | CARDANO = 13000, 51 | LINEA = 59144, 52 | ABSTRACT = 2741, 53 | BLAST = 81457, 54 | } 55 | 56 | export default ChainIds; 57 | -------------------------------------------------------------------------------- /src/tools/caishen/cash/deposit.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCashDepositTool extends Tool { 5 | name = 'cash_deposit'; 6 | description = `Deposit cash into your account using Caishen. 7 | 8 | Inputs (JSON string): 9 | - amount: string (required) — the amount to deposit 10 | - tokenAddress: string (required)- the token address 11 | - account: number (required) - account number 12 | `; 13 | 14 | constructor(private sdk: CaishenSDK) { 15 | super(); 16 | } 17 | 18 | protected async _call(input: string): Promise { 19 | try { 20 | const parsedInput = JSON.parse(input); 21 | 22 | if (!parsedInput.amount || !parsedInput.account || !parsedInput.tokenAddress) { 23 | throw new Error('amount, account, and tokenAddress fields are required'); 24 | } 25 | 26 | const result = await this.sdk.cash.deposit(parsedInput); 27 | 28 | return JSON.stringify({ 29 | status: 'success', 30 | transaction: result, 31 | }); 32 | } catch (error: any) { 33 | return JSON.stringify({ 34 | status: 'error', 35 | message: error.message, 36 | code: error.code || 'CASH_DEPOSIT_ERROR', 37 | }); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/tools/caishen/cash/send.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCashSendTool extends Tool { 5 | name = 'cash_send'; 6 | description = `Send cash to another account or destination using Caishen. 7 | 8 | Inputs (JSON string): 9 | - amount: string (required) — amount to send 10 | - toAddress: string (required)- another account or destination address 11 | - account: number (required) - account number 12 | `; 13 | 14 | constructor(private sdk: CaishenSDK) { 15 | super(); 16 | } 17 | 18 | protected async _call(input: string): Promise { 19 | try { 20 | const parsedInput = JSON.parse(input); 21 | 22 | if (!parsedInput.amount || !parsedInput.account || !parsedInput.toAddress) { 23 | throw new Error('amount, account, and toAddress are required fields'); 24 | } 25 | 26 | const result = await this.sdk.cash.send(parsedInput); 27 | 28 | return JSON.stringify({ 29 | status: 'success', 30 | transaction: result, 31 | }); 32 | } catch (error: any) { 33 | return JSON.stringify({ 34 | status: 'error', 35 | message: error.message, 36 | code: error.code || 'CASH_SEND_ERROR', 37 | }); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/tools/caishen/cash/withdraw.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCashWithdrawTool extends Tool { 5 | name = 'cash_withdraw'; 6 | description = `Withdraw cash from your Caishen account to a specified destination. 7 | 8 | Inputs (JSON string): 9 | - amount: string (required) — amount to withdraw 10 | - tokenAddress: string (required) — the token address 11 | - account: number (required) - account number 12 | `; 13 | 14 | constructor(private sdk: CaishenSDK) { 15 | super(); 16 | } 17 | 18 | protected async _call(input: string): Promise { 19 | try { 20 | const parsedInput = JSON.parse(input); 21 | 22 | if (!parsedInput.amount || !parsedInput.account || !parsedInput.tokenAddress) { 23 | throw new Error('amount, account, and tokenAddress are required fields'); 24 | } 25 | 26 | const result = await this.sdk.cash.withdraw(parsedInput); 27 | 28 | return JSON.stringify({ 29 | status: 'success', 30 | transaction: result, 31 | }); 32 | } catch (error: any) { 33 | return JSON.stringify({ 34 | status: 'error', 35 | message: error.message, 36 | code: error.code || 'CASH_WITHDRAW_ERROR', 37 | }); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/tools/caishen/crypto/balance.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCryptoGetBalanceTool extends Tool { 5 | name = "crypto_get_balance"; 6 | description = `Get the crypto balance for a wallet address. 7 | 8 | Inputs (JSON string): 9 | - wallet: object 10 | - address: string (required) 11 | - chainType: string (required, e.g., "EVM", "SOLANA") 12 | - chainId: number (optional) 13 | - publicKey: string (optional) 14 | - account: number (optional) 15 | - payload: object 16 | - token: string (optional) — token address or symbol to check balance for (default is native token like ETH, SOL). 17 | 18 | Returns the balance as a string.`; 19 | 20 | constructor(private sdk: CaishenSDK) { 21 | super(); 22 | } 23 | 24 | protected async _call(input: string): Promise { 25 | try { 26 | const parsedInput = JSON.parse(input); 27 | 28 | const wallet = parsedInput.wallet; 29 | const payload = parsedInput.payload || {}; 30 | 31 | if (!wallet || !wallet.address || !wallet.chainType) { 32 | throw new Error("wallet.address and wallet.chainType are required"); 33 | } 34 | 35 | const balance = await this.sdk.crypto.getBalance({ 36 | wallet, 37 | payload, 38 | }); 39 | 40 | return JSON.stringify({ 41 | status: 'success', 42 | balance, 43 | }); 44 | } catch (error: any) { 45 | return JSON.stringify({ 46 | status: 'error', 47 | message: error.message, 48 | code: error.code || 'GET_BALANCE_ERROR', 49 | }); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/tools/caishen/crypto/swap.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from "langchain/tools"; 2 | import { CaishenSDK } from "../../../caishen"; 3 | 4 | export class CaishenCryptoSwapTool extends Tool { 5 | name = 'swap_crypto'; 6 | description = `Execute a crypto swap for a wallet after receiving a confirmation code. 7 | 8 | Inputs (JSON string): 9 | - wallet: object 10 | - account: number (required) 11 | - chainType: string (required, e.g., "EVM", "SOLANA") 12 | - payload: object 13 | - confirmationCode: string (required) — swap route confirmation code 14 | 15 | Returns the swap route output upon success.`; 16 | 17 | constructor(private sdk: CaishenSDK) { 18 | super(); 19 | } 20 | 21 | protected async _call(input: string): Promise { 22 | try { 23 | const parsedInput = JSON.parse(input); 24 | 25 | const wallet = parsedInput.wallet; 26 | const payload = parsedInput.payload; 27 | 28 | if (!wallet || wallet.account === undefined || !wallet.chainType) { 29 | throw new Error('wallet.account and wallet.chainType are required'); 30 | } 31 | if (!payload || !payload.confirmationCode) { 32 | throw new Error('payload.confirmationCode is required'); 33 | } 34 | 35 | const routeOutput = await this.sdk.crypto.swap({ 36 | wallet, 37 | payload, 38 | }); 39 | 40 | return JSON.stringify({ 41 | status: 'success', 42 | routeOutput, 43 | }); 44 | } catch (error: any) { 45 | return JSON.stringify({ 46 | status: 'error', 47 | message: error.message, 48 | code: error.code || 'SWAP_CRYPTO_ERROR', 49 | }); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/constants/public-rpc-endpoints.ts: -------------------------------------------------------------------------------- 1 | import ChainIds from './chain-ids'; 2 | 3 | const PublicRpcEndpoints: any = { 4 | [ChainIds.MAINNET]: 'https://rpc.ankr.com/eth', 5 | [ChainIds.SMART_CHAIN]: 'https://bsc-dataseed.binance.org/', 6 | [ChainIds.MATIC]: 'https://polygon-rpc.com/', 7 | [ChainIds.OPTIMISM]: 'https://optimism.publicnode.com', 8 | [ChainIds.ARBITRUM]: 'https://arb1.arbitrum.io/rpc', 9 | [ChainIds.AVALANCHE]: 'https://api.avax.network/ext/bc/C/rpc', 10 | [ChainIds.BASE]: 'https://mainnet.base.org', 11 | [ChainIds.MANTLE]: 'https://rpc.mantle.xyz', 12 | [ChainIds.MODE]: 'https://mainnet.mode.network', 13 | [ChainIds.SOLANA]: 'https://solana-mainnet.g.alchemy.com/v2/demo', 14 | [ChainIds.SUI]: 'https://fullnode.mainnet.sui.io', 15 | [ChainIds.BITCOIN]: 'https://api.blockcypher.com/v1/btc/main', 16 | [ChainIds.NEWMONEY_CHAIN]: 'https://cashchain-rpc.newmoney.ai', 17 | [ChainIds.ABSTRACT]: 'https://abstract.drpc.org', 18 | [ChainIds.LINEA]: 'https://linea-rpc.publicnode.com', 19 | [ChainIds.BLAST]: 'https://rpc.blast.io', 20 | [ChainIds.LITECOIN]: 'https://go.getblock.io/687a16d871f54299b19a285be54bc891', 21 | [ChainIds.DOGECOIN]: 'https://go.getblock.io/f6ac2b4b5ce246829db698141d9f0bfe', 22 | [ChainIds.DASHCOIN]: 'https://dash-rpc.publicnode.com', 23 | [ChainIds.TON]: 'https://toncenter.com/api/v2/jsonRPC', 24 | [ChainIds.TRON]: 'https://api.trongrid.io', 25 | [ChainIds.RIPPLE]: 'wss://s2.ripple.com:443', 26 | [ChainIds.COSMOS]: 'https://cosmos-rpc.publicnode.com:443', 27 | [ChainIds.NEAR]: 'https://rpc.mainnet.near.org', 28 | [ChainIds.APTOS]: 'https://1rpc.io/aptos', 29 | [ChainIds.CARDANO]: 'wss://go.getblock.io/68afeff066af41bb89baed64b21671b8', 30 | } as const; 31 | 32 | export default PublicRpcEndpoints; 33 | -------------------------------------------------------------------------------- /test/integration/cash.spec.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | // @ts-ignore 3 | import env from 'env-var'; 4 | import * as assert from 'assert'; 5 | 6 | import { CaishenSDK } from '../../src'; 7 | 8 | describe('Integration: SDK Cash', function () { 9 | const sdk = new CaishenSDK({ 10 | projectKey: env.get('PROJECT_KEY').required().asString(), 11 | }); 12 | 13 | before(async () => { 14 | await sdk.connectAsUser({ 15 | token: env.get('USER_TOKEN').required().asString(), 16 | provider: env.get('USER_PROVIDER').default('custom').asString(), 17 | }); 18 | }); 19 | 20 | describe('Supported Tokens', () => { 21 | it('should get supported tokens', async () => { 22 | const tokens = await sdk.cash.getSupportedTokens(); 23 | 24 | assert.strictEqual( 25 | Array.isArray(tokens) && 26 | tokens.every( 27 | (token) => typeof token === 'object' && 'address' in token, 28 | ), 29 | true, 30 | 'should return array of supported tokens', 31 | ); 32 | }); 33 | }); 34 | 35 | describe('Check Balance', () => { 36 | it('should get balance', async () => { 37 | const balance = await sdk.cash.getBalance({ account: 1 }); 38 | 39 | assert.strictEqual( 40 | 'balance' in balance && 41 | 'balanceRaw' in balance && 42 | +balance.balance >= 0, 43 | true, 44 | 'should return balance of account', 45 | ); 46 | }); 47 | }); 48 | 49 | describe('Deposit', () => { 50 | it('should get balance', async () => { 51 | const result = await sdk.cash.deposit({ 52 | amount: '1', 53 | account: 1, 54 | tokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', 55 | chainId: 42161, 56 | }); 57 | 58 | assert.ok(result); 59 | }); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/crypto/sign.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | import { BASE_URL } from '../constants'; 4 | import type { CaishenSDK } from '../caishen'; 5 | import { BaseRequest, SignAndSendPayload, SignPayload, WalletAccount } from '../types'; 6 | 7 | /** 8 | * Signs prepared transaction and broadcasts it to a network. 9 | * @param request 10 | */ 11 | export async function signAndSend( 12 | this: CaishenSDK, 13 | request: BaseRequest, 14 | ): Promise { 15 | const { 16 | wallet, 17 | payload, 18 | authToken = this.userToken || this.agentToken, 19 | } = request; 20 | 21 | if (!authToken) { 22 | throw new Error('Authentication token required. Connect as user/agent first or pass authorization token separately.'); 23 | } 24 | 25 | const url = `${BASE_URL}/api/crypto/signAndSend`; 26 | const response = await axios.post( 27 | url, 28 | { 29 | wallet, 30 | payload, 31 | }, 32 | { 33 | headers: { 34 | Authorization: `Bearer ${authToken}`, 35 | }, 36 | }, 37 | ); 38 | return response.data; 39 | } 40 | 41 | /** 42 | * Signs without broadcasting to the network. 43 | * @param request 44 | */ 45 | export async function sign( 46 | this: CaishenSDK, 47 | request: BaseRequest, 48 | ): Promise { 49 | const { 50 | wallet, 51 | payload, 52 | authToken = this.userToken || this.agentToken, 53 | } = request; 54 | 55 | if (!authToken) { 56 | throw new Error('Authentication token required. Connect as user/agent first or pass authorization token separately.'); 57 | } 58 | 59 | const url = `${BASE_URL}/api/crypto/sign`; 60 | const response = await axios.post( 61 | url, 62 | { 63 | wallet, 64 | payload, 65 | }, 66 | { 67 | headers: { 68 | Authorization: `Bearer ${authToken}`, 69 | }, 70 | }, 71 | ); 72 | return response.data; 73 | } 74 | -------------------------------------------------------------------------------- /src/tools/caishen/crypto/send.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCryptoSendTool extends Tool { 5 | name = 'send_crypto'; 6 | description = `Send crypto from a wallet to another address. 7 | 8 | Inputs (JSON string): 9 | - wallet: object 10 | - address: string (required) 11 | - chainType: string (required, e.g., "EVM", "SOLANA") 12 | - chainId: number (optional) 13 | - publicKey: string (optional) 14 | - account: number (optional) 15 | - payload: object 16 | - toAddress: string (required) — recipient address 17 | - amount: string (required) — amount to send 18 | - token: string (optional) — token address or symbol (send gas token if not specified) 19 | - memo: number (optional) — transaction memo (for Solana, etc.) 20 | 21 | Returns the transaction signature as a string.`; 22 | 23 | constructor(private sdk: CaishenSDK) { 24 | super(); 25 | } 26 | 27 | protected async _call(input: string): Promise { 28 | try { 29 | const parsedInput = JSON.parse(input); 30 | 31 | const wallet = parsedInput.wallet; 32 | const payload = parsedInput.payload; 33 | 34 | if (!wallet || !wallet.address || !wallet.chainType) { 35 | throw new Error('wallet.address and wallet.chainType are required'); 36 | } 37 | if (!payload || !payload.toAddress || !payload.amount) { 38 | throw new Error('payload.toAddress and payload.amount are required'); 39 | } 40 | 41 | const signature = await this.sdk.crypto.send({ 42 | wallet, 43 | payload, 44 | }); 45 | 46 | return JSON.stringify({ 47 | status: 'success', 48 | signature, 49 | }); 50 | } catch (error: any) { 51 | return JSON.stringify({ 52 | status: 'error', 53 | message: error.message, 54 | code: error.code || 'SEND_CRYPTO_ERROR', 55 | }); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/crypto/swap.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { BASE_URL, ChainType } from '../constants'; 3 | 4 | import type { CaishenSDK } from '../caishen'; 5 | import { 6 | BaseRequest, 7 | ExecuteSwapPayload, 8 | GetSwapPayload, 9 | RouteExecutedResponse, 10 | RouteOutput, 11 | WalletAccount, 12 | } from '../types'; 13 | 14 | export async function swap( 15 | this: CaishenSDK, 16 | request: BaseRequest< 17 | Pick, 18 | ExecuteSwapPayload 19 | > 20 | ): Promise { 21 | const { 22 | wallet, 23 | payload, 24 | authToken = this.userToken || this.agentToken, 25 | } = request; 26 | 27 | if (!authToken) { 28 | throw new Error('Authentication token required. Connect as user/agent first or pass authorization token separately.'); 29 | } 30 | 31 | const url = `${BASE_URL}/api/crypto/swap`; 32 | const { data: routeOutput } = await axios.post( 33 | url, 34 | { 35 | wallet, 36 | payload, 37 | }, 38 | { 39 | headers: { 40 | Authorization: `Bearer ${authToken}`, 41 | }, 42 | }, 43 | ); 44 | 45 | return routeOutput; 46 | } 47 | 48 | export async function getSwapRoute( 49 | this: CaishenSDK, 50 | request: BaseRequest< 51 | Pick, 52 | GetSwapPayload 53 | > 54 | ): Promise { 55 | const { 56 | wallet, 57 | payload, 58 | } = request 59 | const authToken = this.userToken || this.agentToken; 60 | 61 | if (!authToken) { 62 | throw new Error('Authentication required. Connect as user or agent first.'); 63 | } 64 | 65 | const url = `${BASE_URL}/api/crypto/swap-route`; 66 | const { data: routeOutput } = await axios.post( 67 | url, 68 | { 69 | wallet, 70 | payload, 71 | }, 72 | { 73 | headers: { 74 | Authorization: `Bearer ${authToken}`, 75 | }, 76 | }, 77 | ); 78 | 79 | return routeOutput; 80 | } 81 | -------------------------------------------------------------------------------- /src/tools/caishen/crypto/swap_route.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from 'langchain/tools'; 2 | import { CaishenSDK } from '../../../caishen'; 3 | 4 | export class CaishenCryptoGetSwapRouteTool extends Tool { 5 | name = 'crypto_get_swap_route'; 6 | description = `Get a swap route to exchange tokens between two chains or within the same chain. 7 | 8 | Inputs (JSON string): 9 | - wallet: object 10 | - account: number (required) 11 | - payload: object 12 | - amount: string (required) — amount to swap (in token units) 13 | - from: object (required) 14 | - tokenAddress: string (required) 15 | - chainType: string (required, e.g., "EVM", "SOLANA") 16 | - chainId: number (optional) 17 | - to: object (required) 18 | - tokenAddress: string (required) 19 | - chainType: string (required) 20 | - chainId: number (optional) 21 | 22 | Returns swap route data needed to later execute the swap.`; 23 | 24 | constructor(private sdk: CaishenSDK) { 25 | super(); 26 | } 27 | 28 | protected async _call(input: string): Promise { 29 | try { 30 | const parsedInput = JSON.parse(input); 31 | 32 | const wallet = parsedInput.wallet; 33 | const payload = parsedInput.payload; 34 | 35 | if (!wallet || wallet.account === undefined) { 36 | throw new Error('wallet.account is required'); 37 | } 38 | if (!payload || !payload.amount || !payload.from || !payload.to) { 39 | throw new Error('payload.amount, payload.from, and payload.to are required'); 40 | } 41 | 42 | const routeOutput = await this.sdk.crypto.getSwapRoute({ 43 | wallet, 44 | payload, 45 | }); 46 | 47 | return JSON.stringify({ 48 | status: 'success', 49 | routeOutput, 50 | }); 51 | } catch (error: any) { 52 | return JSON.stringify({ 53 | status: 'error', 54 | message: error.message, 55 | code: error.code || 'GET_SWAP_ROUTE_ERROR', 56 | }); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/crypto/wallets.ts: -------------------------------------------------------------------------------- 1 | import { BASE_URL } from '../constants'; 2 | import ChainIds from '../constants/chain-ids'; 3 | import PublicRpcEndpoints from '../constants/public-rpc-endpoints'; 4 | import axios from 'axios'; 5 | 6 | import type { CaishenSDK } from '../caishen'; 7 | import { WalletAccount, WalletInfo } from '../types'; 8 | 9 | export async function getWallet( 10 | this: CaishenSDK, 11 | walletAccount: Pick & { 12 | account: number | number[]; 13 | authToken?: string; 14 | }, 15 | ): Promise { 16 | const { 17 | chainType, 18 | chainId, 19 | account, 20 | authToken = this.agentToken || this.userToken 21 | } = walletAccount 22 | 23 | if (!chainType || account === undefined) { 24 | throw new Error('chainType and account number are required'); 25 | } 26 | 27 | if (!authToken) { 28 | throw new Error('Authentication token required. Connect as user/agent first or pass authorization token separately.'); 29 | } 30 | 31 | const response = await axios.get(`${BASE_URL}/api/crypto/wallets`, { 32 | params: { chainType, account, chainId }, 33 | headers: { Authorization: `Bearer ${authToken}` }, 34 | }); 35 | 36 | return response.data; 37 | } 38 | 39 | export async function getSupportedChainTypes( 40 | this: CaishenSDK, 41 | authToken?: string 42 | ): Promise { 43 | const _authToken = authToken || this.agentToken || this.userToken; 44 | 45 | if (!_authToken) { 46 | throw new Error('Authentication token required. Connect as user/agent first or pass authorization token separately.'); 47 | } 48 | 49 | const response = await axios.get( 50 | `${BASE_URL}/api/crypto/wallets/supported`, 51 | { 52 | headers: { Authorization: `Bearer ${_authToken}` }, 53 | }, 54 | ); 55 | 56 | return response.data; 57 | } 58 | 59 | export async function getRPC(chainId: ChainIds) { 60 | if (!PublicRpcEndpoints[chainId]) { 61 | throw new Error(`RPC for ${chainId} not supported`); 62 | } 63 | 64 | return PublicRpcEndpoints[chainId]; 65 | } 66 | -------------------------------------------------------------------------------- /src/cash/index.ts: -------------------------------------------------------------------------------- 1 | import { ApiClient } from '../api'; 2 | import { 3 | BalanceResponse, CashGetBalanceParams, 4 | DepositCashParams, 5 | SendTransactionParams, 6 | Token, 7 | TransactionResponse, 8 | WithdrawCashParams, 9 | } from './schema'; 10 | 11 | import type { CaishenSDK } from '../caishen'; 12 | 13 | export async function send( 14 | this: CaishenSDK, 15 | params: SendTransactionParams, 16 | ): Promise { 17 | const authToken = params.authToken || this.userToken || this.agentToken; 18 | const response = await ApiClient.post('/cash/send', params, { 19 | headers: { 20 | Authorization: `Bearer ${authToken}`, 21 | }, 22 | }); 23 | 24 | return response.data; 25 | } 26 | 27 | export async function deposit( 28 | this: CaishenSDK, 29 | params: DepositCashParams, 30 | ): Promise { 31 | const authToken = params.authToken || this.userToken || this.agentToken; 32 | const response = await ApiClient.post('/cash/deposit', params, { 33 | headers: { 34 | Authorization: `Bearer ${authToken}`, 35 | }, 36 | }); 37 | 38 | return response.data; 39 | } 40 | 41 | export async function withdraw( 42 | this: CaishenSDK, 43 | params: WithdrawCashParams, 44 | ): Promise { 45 | const authToken = params.authToken || this.userToken || this.agentToken; 46 | const response = await ApiClient.post('/cash/withdraw', params, { 47 | headers: { 48 | Authorization: `Bearer ${authToken}`, 49 | }, 50 | }); 51 | 52 | return response.data; 53 | } 54 | 55 | export async function getBalance( 56 | this: CaishenSDK, 57 | params: CashGetBalanceParams, 58 | ): Promise { 59 | const authToken = params.authToken || this.userToken || this.agentToken; 60 | const response = await ApiClient.get('/cash/balance', { 61 | params, 62 | headers: { 63 | Authorization: `Bearer ${authToken}`, 64 | }, 65 | }); 66 | 67 | return response.data; 68 | } 69 | 70 | export async function getSupportedTokens(this: CaishenSDK): Promise { 71 | const authToken = this.userToken || this.agentToken; 72 | const response = await ApiClient.get('/cash/tokens', { 73 | headers: { 74 | Authorization: `Bearer ${authToken}`, 75 | }, 76 | }); 77 | 78 | return response.data; 79 | } 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@caishen/sdk", 3 | "version": "1.0.9", 4 | "type": "module", 5 | "description": "The Caishen SDK gives every agent or user access to unlimited multi-chain crypto wallets", 6 | "main": "./dist/index.cjs", 7 | "module": "./dist/index.js", 8 | "types": "./dist/index.d.ts", 9 | "exports": { 10 | "import": { 11 | "types": "./dist/index.d.ts", 12 | "import": "./dist/index.js" 13 | }, 14 | "require": { 15 | "types": "./dist/index.d.cts", 16 | "require": "./dist/index.cjs" 17 | } 18 | }, 19 | "scripts": { 20 | "dev": "tsup src/index.ts --watch", 21 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 22 | "test": "mocha --timeout 30000 --import=tsx", 23 | "test:all": "mocha --timeout 30000 --import=tsx 'test/**/*.spec.ts'", 24 | "build": "tsup src/index.ts --format cjs,esm --dts --clean --sourcemap --minify" 25 | }, 26 | "publishConfig": { 27 | "access": "public" 28 | }, 29 | "author": "Caishen (https://caishen.tech)", 30 | "license": "MIT", 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/CaishenTech/caishen-sdk" 34 | }, 35 | "homepage": "https://github.com/CaishenTech/caishen-sdk#readme", 36 | "bugs": { 37 | "url": "https://github.com/CaishenTech/caishen-sdk/issues" 38 | }, 39 | "keywords": [ 40 | "crypto", 41 | "wallet", 42 | "sdk", 43 | "caishen" 44 | ], 45 | "peerDependencies": { 46 | "zod": "3.x" 47 | }, 48 | "files": [ 49 | "dist" 50 | ], 51 | "dependencies": { 52 | "@langchain/core": "^0.3.44", 53 | "@types/axios": "^0.14.4", 54 | "ai": "^4.3.9", 55 | "axios": "^1.8.1", 56 | "crypto": "^1.0.1", 57 | "dotenv": "^16.5.0", 58 | "langchain": "^0.3.21", 59 | "reflect-metadata": "^0.2.2", 60 | "uuid": "^11.1.0", 61 | "zod": "3.x" 62 | }, 63 | "devDependencies": { 64 | "@types/jest": "^29.5.14", 65 | "@types/mocha": "^7.0.2", 66 | "@types/node": "^22.5.5", 67 | "axios-mock-adapter": "^2.1.0", 68 | "env-var": "^7.5.0", 69 | "jest": "^29.7.0", 70 | "mocha": "^10.2.0", 71 | "mocha-junit-reporter": "^2.2.1", 72 | "prettier": "^3.0.0", 73 | "terser": "^5.37.0", 74 | "ts-jest": "^29.3.1", 75 | "ts-node": "^10.9.1", 76 | "tsup": "^8.0.2", 77 | "tsx": "^4.19.3", 78 | "typescript": "^5.6.2" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/cash/schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | export const BaseCashSchema = { 4 | authToken: z.string().optional(), 5 | } 6 | 7 | export const CashGetBalanceSchema = z.object({ 8 | account: z.number().describe('The account number to fetch the balance for'), 9 | }).extend(BaseCashSchema); 10 | 11 | export const SendTransactionSchema = z.object({ 12 | toAddress: z 13 | .string() 14 | .describe('The recipient account or destination address'), 15 | amount: z.string().describe('The amount to send'), 16 | account: z.number().describe('The account number to send from'), 17 | }).extend(BaseCashSchema); 18 | 19 | export const DepositCashSchema = z.object({ 20 | amount: z.string().describe('The amount to deposit'), 21 | account: z.number().describe('The account number to deposit to'), 22 | tokenAddress: z.string().describe('The token address to deposit'), 23 | chainId: z.number().describe('The chain ID where the token is located'), 24 | }).extend(BaseCashSchema); 25 | 26 | export const WithdrawCashSchema = z.object({ 27 | amount: z.string().describe('The amount to withdraw'), 28 | account: z.number().describe('The account number to withdraw from'), 29 | tokenAddress: z.string().describe('The token address to withdraw'), 30 | chainId: z 31 | .number() 32 | .describe('The chain ID where the token should be withdrawn to'), 33 | }).extend(BaseCashSchema); 34 | 35 | export const TokenSchema = z.object({ 36 | address: z.string(), 37 | chainId: z.number(), 38 | decimals: z.number(), 39 | name: z.string(), 40 | symbol: z.string(), 41 | }); 42 | 43 | export const BalanceResponseSchema = z.object({ 44 | success: z.boolean(), 45 | balance: z.string(), 46 | balanceRaw: z.string(), 47 | }); 48 | 49 | export const TransactionResponseSchema = z.object({ 50 | success: z.boolean(), 51 | message: z.string().optional(), 52 | txHash: z.string().optional(), 53 | isSuccess: z.boolean().optional(), 54 | }); 55 | 56 | export type CashGetBalanceParams = z.infer; 57 | export type SendTransactionParams = z.infer; 58 | export type DepositCashParams = z.infer; 59 | export type WithdrawCashParams = z.infer; 60 | export type Token = z.infer; 61 | export type BalanceResponse = z.infer; 62 | export type TransactionResponse = z.infer; 63 | -------------------------------------------------------------------------------- /src/schema/schema.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod'; 2 | 3 | export const CryptoSendSchema = z.object({ 4 | chainType: z.string().describe('The blockchain type (e.g., "EVM", "SOLANA")'), 5 | chainId: z.number().optional().describe('The chain ID for the blockchain'), 6 | account: z.number().describe('The account number'), 7 | toAddress: z.string().describe('The recipient address to send to'), 8 | amount: z.string().describe('The amount to send'), 9 | token: z 10 | .string() 11 | .optional() 12 | .describe('Token address or symbol (send gas token if not specified)'), 13 | memo: z.number().optional().describe('Transaction memo (for Solana, etc.)'), 14 | }); 15 | 16 | export const CryptoSignAndSendSchema = z.object({ 17 | chainType: z.string().describe('The blockchain type (e.g., "EVM", "SOLANA")'), 18 | chainId: z.number().optional().describe('The chain ID for the blockchain'), 19 | account: z.number().describe('The account number'), 20 | serializedTransaction: z.string().describe('Serialized transaction into Hex format'), 21 | }); 22 | 23 | export const CryptoSignSchema = z.object({ 24 | chainType: z.string().describe('The blockchain type (e.g., "EVM", "SOLANA")'), 25 | account: z.number().describe('The account number'), 26 | transactionData: z.string().describe(' Either serialized transaction or any transaction data to issue signature.'), 27 | }); 28 | 29 | export const CryptoGetBalanceSchema = z.object({ 30 | chainType: z.string().describe('The blockchain type (e.g., "EVM", "SOLANA")'), 31 | chainId: z.number().optional().describe('The chain ID for the blockchain'), 32 | publicKey: z.string().optional().describe('The public key of the wallet'), 33 | account: z.number().describe('The account number'), 34 | token: z 35 | .string() 36 | .optional() 37 | .describe( 38 | 'Token address or symbol to check balance for (default is native token like ETH, SOL)', 39 | ), 40 | }); 41 | 42 | export const CryptoSwapSchema = z.object({ 43 | account: z.number().describe('The wallet account number to perform the swap from'), 44 | chainType: z.string().describe('The blockchain type (e.g., "EVM", "SOLANA")'), 45 | confirmationCode: z.string().describe('The swap route confirmation code'), 46 | }); 47 | 48 | export const CryptoGetSwapRouteSchema = z.object({ 49 | account: z.number().describe('The account number'), 50 | amount: z.string().describe('The amount to swap (in token units)'), 51 | fromAddress: z.string().describe('The source token address'), 52 | fromChainType: z 53 | .string() 54 | .describe('The source blockchain type (e.g., "EVM", "SOLANA")'), 55 | fromChainId: z.number().optional().describe('The source chain ID'), 56 | toAddress: z.string().describe('The destination token address'), 57 | toChainType: z.string().describe('The destination blockchain type'), 58 | toChainId: z.number().optional().describe('The destination chain ID'), 59 | }); 60 | 61 | export type CryptoSendParams = z.infer; 62 | export type CryptoGetBalanceParams = z.infer; 63 | export type CryptoSwapParams = z.infer; 64 | export type CryptoGetSwapRouteParams = z.infer; 65 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | import { ChainType } from '../constants'; 2 | import { Token } from '../cash/schema'; 3 | import { Method } from 'axios'; 4 | 5 | export type BaseRequest = { 6 | wallet: Wallet; 7 | payload: Payload; 8 | /** 9 | * Optionally, you may specify another authorization token on the fly in order to access Caishen API. 10 | */ 11 | authToken?: string; 12 | } 13 | 14 | export interface GetBalancePayload { 15 | /** 16 | * If not specified, native token will be used. 17 | */ 18 | token?: string; 19 | } 20 | 21 | export interface InitCaishenSDK { 22 | projectKey: string; 23 | } 24 | 25 | export interface ConnectAsAgentPayload { 26 | agentId?: string; 27 | userId?: string; 28 | } 29 | 30 | export interface ConnectAsUserPayload { 31 | provider?: string | 'custom'; 32 | token: string; 33 | } 34 | 35 | export type IssueAuthTokenPayload = 36 | | ConnectAsUserPayload & { connectAs: 'user' } 37 | | ConnectAsAgentPayload & { connectAs: 'agent' } 38 | 39 | export interface SendTransactionPayload { 40 | /** 41 | * If not specified, native token will be used. 42 | */ 43 | token?: string; 44 | amount: string; 45 | toAddress: string; 46 | memo?: number; 47 | } 48 | 49 | export interface SignPayload { 50 | /** 51 | * Either serialized transaction or any transaction data to issue signature. 52 | */ 53 | transactionData: string 54 | } 55 | 56 | export interface SignAndSendPayload { 57 | /** 58 | * Serialized transaction (e.g. with [serializeTransaction]{@link https://viem.sh/docs/utilities/serializeTransaction.html}) - Hex 59 | */ 60 | serializedTransaction: string; 61 | } 62 | 63 | type TokenWithPrice = Token & { 64 | priceUSD: string; 65 | }; 66 | 67 | export interface RouteOutput { 68 | id: string; 69 | 70 | fromChainId: number; 71 | fromAmountUSD: string; 72 | fromAmount: string; 73 | fromToken: TokenWithPrice; 74 | fromAddress?: string; 75 | 76 | toChainId: number; 77 | toAmountUSD: string; 78 | toAmount: string; 79 | toAmountMin: string; 80 | toToken: TokenWithPrice; 81 | toAddress?: string; 82 | 83 | confirmationCode: string; 84 | } 85 | 86 | export interface RouteExecutedResponse { 87 | transactionStatus: string; 88 | transactionHash: string | null; 89 | fees: string | null; 90 | error: string | null; 91 | } 92 | 93 | export interface WalletAccount { 94 | account: number; 95 | chainType: string; 96 | chainId?: number; 97 | rpc?: string; 98 | /** 99 | * Your custom URL API endpoint to fetch UTXOs for BTC-based chains like BTC, LTC, etc. 100 | * The endpoint MUST return an array structure like 101 | * 102 | * ``` 103 | * Array<{ 104 | * vout: number; 105 | * value: number; // satoshi 106 | * txId: string; 107 | * }> 108 | * ``` 109 | */ 110 | utxoUrl?: string; 111 | } 112 | 113 | export interface WalletInfo { 114 | account: number; 115 | address: string; 116 | chainType: string; 117 | publicKey: string; 118 | privateKey?: string; 119 | } 120 | 121 | export interface ExecuteSwapPayload { 122 | confirmationCode: string; 123 | } 124 | 125 | export interface GetSwapPayload { 126 | amount: string; 127 | from: { 128 | tokenAddress: string; 129 | chainType: ChainType; 130 | chainId?: number; 131 | }; 132 | to: { 133 | tokenAddress: string; 134 | chainType: ChainType; 135 | chainId?: number; 136 | }; 137 | } 138 | 139 | export interface InvokeTool { 140 | tool: string; 141 | method: Method; 142 | route: string; 143 | query?: Record; 144 | headers?: Record; 145 | body?: Record; 146 | } -------------------------------------------------------------------------------- /test/integration/auth.spec.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | // @ts-ignore 3 | import env from 'env-var'; 4 | import * as assert from 'assert'; 5 | 6 | import { CaishenSDK } from '../../src'; 7 | 8 | describe('Integration: SDK Authorization', function () { 9 | describe('Connect As User', () => { 10 | const sdk = new CaishenSDK({ 11 | projectKey: env.get('PROJECT_KEY').required().asString(), 12 | }); 13 | 14 | const provider = env.get('USER_PROVIDER').default('custom').asString(); 15 | const token = env.get('USER_TOKEN').required().asString(); 16 | 17 | // TODO: add more providers as list (not via env) 18 | it(`should connect as user (${provider} provider)`, async () => { 19 | const authToken = await sdk.connectAsUser({ 20 | token, 21 | provider, 22 | }); 23 | 24 | assert.strictEqual( 25 | typeof authToken, 26 | 'string', 27 | 'should return auth token', 28 | ); 29 | }); 30 | }); 31 | 32 | describe('Connect As Agent', () => { 33 | const sdk = new CaishenSDK({ 34 | projectKey: env.get('PROJECT_KEY').required().asString(), 35 | }); 36 | 37 | it('should connect as agent', async () => { 38 | const authToken = await sdk.connectAsAgent({ 39 | agentId: env.get('AGENT_ID').required().asString(), 40 | }); 41 | 42 | assert.strictEqual( 43 | typeof authToken, 44 | 'string', 45 | 'should return auth token', 46 | ); 47 | }); 48 | }); 49 | 50 | // it(`should connect as user (${provider} provider)`, async () => { 51 | // const authToken = await sdk.connectAsUser({ 52 | // token, 53 | // provider, 54 | // }); 55 | // 56 | // assert.strictEqual( 57 | // typeof authToken, 58 | // 'string', 59 | // 'should return auth token', 60 | // ); 61 | // // /// ================ elevenLabsData ============= 62 | // const elevenLabsData = await createElevenLabsTools({sdk}) 63 | // const tools = castToToolRecord(elevenLabsData); 64 | // const elevenLabs_input_text = "Hello, please give me the balance of account 15!"; 65 | // const elevenLabsData_result = await generateText({ 66 | // model: openai("gpt-4o-mini"), 67 | // tools: tools, 68 | // maxSteps: 10, 69 | // prompt: elevenLabs_input_text, 70 | // }); 71 | // console.log("elevenLabs data result text: ", elevenLabsData_result.text); 72 | // /// ================ vercelAIData ============= 73 | // const vercelAIData_text = "Hello, please give me the balance of account 15!"; 74 | // const vercelAIData = await createVercelAITools({sdk}) 75 | // const vercelAIData_result = await generateText({ 76 | // model: openai("gpt-4o-mini"), 77 | // tools: castToToolRecord(vercelAIData), 78 | // maxSteps: 10, // Maximum number of tool invocations per request 79 | // prompt: vercelAIData_text, 80 | // }); 81 | // console.log("vercelAIData Result text: ", vercelAIData_result.text); 82 | // console.log("\n-------------------\n"); 83 | // console.log("RESPONSE"); 84 | // console.log("\n-------------------\n"); 85 | // /// ================ langchainData ============= 86 | // const langchain_tools = createAgentTools(sdk) 87 | // const langchainData_text = "Fetch my cash balance account 12345"; 88 | // // const langchainTools = await createLangchainTools({ sdk }); 89 | // const llm = new ChatOpenAI({ 90 | // temperature: 0, 91 | // modelName: "gpt-4o-mini", // or "gpt-3.5-turbo", whatever you're using 92 | // }); 93 | // const executor = await initializeAgentExecutorWithOptions( 94 | // langchain_tools, 95 | // llm, // your model (OpenAI, Anthropic, etc) 96 | // { 97 | // agentType: "openai-functions",//"zero-shot-react-description", 98 | // verbose: true, 99 | // } 100 | // ); 101 | // // now you can run 102 | // const res = await executor.call({ input: langchainData_text }); 103 | // console.log("langchain output: ", res.output); 104 | // }); 105 | }); 106 | -------------------------------------------------------------------------------- /test/integration/crypto.spec.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | import * as assert from 'assert'; 3 | // @ts-ignore 4 | import env from 'env-var'; 5 | 6 | import { CaishenSDK } from '../../src'; 7 | import { BLOCKCHAIN_CONFIGS } from '../support'; 8 | 9 | describe('Integration: SDK Crypto', function () { 10 | const sdk = new CaishenSDK({ 11 | projectKey: env.get('PROJECT_KEY').required().asString(), 12 | }); 13 | 14 | before(async () => { 15 | await sdk.connectAsUser({ 16 | token: env.get('USER_TOKEN').required().asString(), 17 | provider: env.get('USER_PROVIDER').default('custom').asString(), 18 | }); 19 | }); 20 | 21 | beforeEach((done) => { 22 | setTimeout(done, 600); 23 | }); 24 | 25 | describe('Supported Wallets', function () { 26 | it('should get supported wallet types', async () => { 27 | const walletsSupported = await sdk.crypto.getSupportedChainTypes(); 28 | 29 | assert.strictEqual( 30 | Array.isArray(walletsSupported) && 31 | walletsSupported.every((v) => typeof v === 'string'), 32 | true, 33 | 'should return supported blockchain types', 34 | ); 35 | }); 36 | }); 37 | 38 | for (const config of BLOCKCHAIN_CONFIGS) { 39 | const chainId = config.chainId 40 | ? ` (Chain ID: ${config.chainId} - ${config.name})` 41 | : ''; 42 | 43 | describe(`${config.type.toUpperCase()}${chainId}`, function () { 44 | it('should get wallet', async () => { 45 | const wallet = await sdk.crypto.getWallet({ 46 | account: 1, 47 | chainType: config.type, 48 | chainId: config.chainId, 49 | }); 50 | 51 | const actual = 52 | typeof wallet.chainType === 'string' && 53 | typeof wallet.address === 'string' && 54 | typeof wallet.publicKey === 'string' && 55 | (!wallet.privateKey || typeof wallet.privateKey === 'string') && 56 | +wallet.account >= 1; 57 | 58 | assert.strictEqual( 59 | actual, 60 | true, 61 | 'should return address, public key, account number and private key as string (optional)', 62 | ); 63 | }); 64 | 65 | for (const token of config.tokens || []) { 66 | it(`should get balance (${token.symbol})`, async function () { 67 | const balance = await sdk.crypto.getBalance({ 68 | wallet: { 69 | account: 1, 70 | chainId: config.chainId, 71 | chainType: config.type, 72 | }, 73 | payload: { 74 | token: ('address' in token && token.address as string) || undefined, 75 | }, 76 | }); 77 | 78 | assert.strictEqual( 79 | BigInt(balance) >= BigInt(0), 80 | true, 81 | 'should return balance in base units and equal or greater than zero', 82 | ); 83 | }); 84 | } 85 | 86 | // NOTE: may fail due to insufficient balance 87 | for (const token of config.tokens || []) { 88 | const minUnits4Send = '1000'; 89 | 90 | it(`should send ${minUnits4Send} units of ${token.symbol} token`, async function () { 91 | const transactionHash = await sdk.crypto.send({ 92 | wallet: { 93 | account: 1, 94 | chainId: config.chainId, 95 | chainType: config.type, 96 | rpc: 97 | (config.chainId && 98 | (await sdk.crypto 99 | .getRPC(config.chainId) 100 | .catch(() => undefined))) || 101 | undefined, 102 | }, 103 | payload: { 104 | token: ('address' in token && token.address as string) || undefined, 105 | toAddress: config.transferDest.address, 106 | memo: config.transferDest.memo, 107 | amount: minUnits4Send, 108 | }, 109 | }); 110 | 111 | assert.strictEqual( 112 | typeof transactionHash, 113 | 'string', 114 | 'should return transaction hash', 115 | ); 116 | }); 117 | } 118 | }); 119 | } 120 | }); 121 | -------------------------------------------------------------------------------- /test/integration/swap.spec.ts: -------------------------------------------------------------------------------- 1 | import 'dotenv/config'; 2 | import * as assert from 'assert'; 3 | // @ts-ignore 4 | import env from 'env-var'; 5 | 6 | import { CaishenSDK } from '../../src'; 7 | import { ChainType } from '../../src/constants'; 8 | 9 | describe('Integration: SDK Swap', function () { 10 | const sdk = new CaishenSDK({ 11 | projectKey: env.get('PROJECT_KEY').required().asString(), 12 | }); 13 | 14 | before(async () => { 15 | await sdk.connectAsUser({ 16 | token: env.get('USER_TOKEN').required().asString(), 17 | provider: env.get('USER_PROVIDER').default('custom').asString(), 18 | }); 19 | }); 20 | 21 | beforeEach((done) => { 22 | setTimeout(done, 1_000); 23 | }); 24 | 25 | const MIN_UNITS0 = '1000000000000'; 26 | const MIN_UNITS1 = '1000000000000000'; 27 | const MIN_UNITS2 = '1000000'; 28 | 29 | describe(`Swap on ARB`, function () { 30 | it(`should swap ${MIN_UNITS0} wei to USDT0`, async () => { 31 | const route = await sdk.crypto.getSwapRoute({ 32 | wallet: { 33 | account: 1, 34 | }, 35 | payload: { 36 | amount: MIN_UNITS0, 37 | from: { 38 | tokenAddress: '0x0000000000000000000000000000000000000000', 39 | chainType: ChainType.ETHEREUM, 40 | chainId: 42161, 41 | }, 42 | to: { 43 | tokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', 44 | chainType: ChainType.ETHEREUM, 45 | chainId: 42161, 46 | }, 47 | }, 48 | }); 49 | 50 | assert.strictEqual( 51 | typeof route?.confirmationCode, 52 | 'string', 53 | 'should return confirmation code to execute route', 54 | ); 55 | 56 | const result = await sdk.crypto.swap({ 57 | wallet: { 58 | account: 1, 59 | chainType: ChainType.ETHEREUM, 60 | }, 61 | payload: { 62 | confirmationCode: route.confirmationCode, 63 | }, 64 | }); 65 | 66 | assert.ok(result); 67 | }); 68 | }); 69 | 70 | describe(`Bridge ETH (Arbitrum) -> USDT (Solana)`, function () { 71 | it(`should swap ${MIN_UNITS1} wei on ARB to USDT on Solana`, async () => { 72 | const route = await sdk.crypto.getSwapRoute({ 73 | wallet: { 74 | account: 1, 75 | }, 76 | payload: { 77 | amount: MIN_UNITS1, 78 | from: { 79 | tokenAddress: '0x0000000000000000000000000000000000000000', 80 | chainType: ChainType.ETHEREUM, 81 | chainId: 42161, 82 | }, 83 | to: { 84 | tokenAddress: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', 85 | chainType: ChainType.SOLANA, 86 | }, 87 | }, 88 | }); 89 | 90 | assert.strictEqual( 91 | typeof route?.confirmationCode, 92 | 'string', 93 | 'should return confirmation code to execute route', 94 | ); 95 | 96 | const result = await sdk.crypto.swap({ 97 | wallet: { 98 | account: 1, 99 | chainType: ChainType.ETHEREUM, 100 | }, 101 | payload: { 102 | confirmationCode: route.confirmationCode, 103 | }, 104 | }); 105 | 106 | assert.ok(result); 107 | }); 108 | }); 109 | 110 | describe(`Bridge BTC -> BNB (Binance Smart Chain)`, function () { 111 | it(`should swap ${MIN_UNITS2} satoshi to BNB on BSC`, async () => { 112 | const route = await sdk.crypto.getSwapRoute({ 113 | wallet: { 114 | account: 1, 115 | }, 116 | payload: { 117 | amount: MIN_UNITS1, 118 | from: { 119 | tokenAddress: 'bitcoin', 120 | chainType: ChainType.BITCOIN, 121 | }, 122 | to: { 123 | tokenAddress: '0x0000000000000000000000000000000000000000', 124 | chainType: ChainType.ETHEREUM, 125 | chainId: 56, 126 | }, 127 | }, 128 | }); 129 | 130 | assert.strictEqual( 131 | typeof route?.confirmationCode, 132 | 'string', 133 | 'should return confirmation code to execute route', 134 | ); 135 | 136 | const result = await sdk.crypto.swap({ 137 | wallet: { 138 | account: 1, 139 | chainType: ChainType.BITCOIN, 140 | }, 141 | payload: { 142 | confirmationCode: route.confirmationCode, 143 | }, 144 | }); 145 | 146 | assert.ok(result); 147 | }); 148 | }); 149 | }); 150 | -------------------------------------------------------------------------------- /src/caishen.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { BASE_URL } from './constants'; 3 | 4 | import * as CASH from './cash'; 5 | import * as CRYPTO from './crypto'; 6 | import { ConnectAsAgentPayload, ConnectAsUserPayload, InitCaishenSDK, IssueAuthTokenPayload } from './types'; 7 | 8 | type ModuleBind = { 9 | [key: string]: unknown; 10 | }; 11 | 12 | type BoundFunctions = { 13 | [K in keyof T as T[K] extends (...args: any[]) => any 14 | ? K 15 | : never]: T[K] extends (...args: infer A) => infer R 16 | ? (...args: A) => R 17 | : never; 18 | }; 19 | 20 | export class CaishenSDK { 21 | protected projectKey: string; 22 | protected agentToken: string | null = null; 23 | protected userToken: string | null = null; 24 | protected connectedAs: 'agent' | 'user' | null = null; 25 | 26 | cash: BoundFunctions; 27 | crypto: BoundFunctions; 28 | 29 | constructor(initData: InitCaishenSDK) { 30 | this.projectKey = initData.projectKey; 31 | this.cash = this.bindModule(CASH); 32 | this.crypto = this.bindModule(CRYPTO); 33 | } 34 | 35 | private bindModule(m: ModuleBind): BoundFunctions { 36 | const bound: ModuleBind = {}; 37 | 38 | for (const key of Object.keys(m)) { 39 | const fn = m[key]; 40 | if (typeof fn === 'function') { 41 | bound[key] = fn.bind(this); // binds SDK context to each function 42 | } 43 | } 44 | 45 | return bound as BoundFunctions; 46 | } 47 | 48 | /** 49 | * Connects you as agent and stores authorization token inside the current class instance. 50 | * @param payload 51 | */ 52 | async connectAsAgent(payload: ConnectAsAgentPayload): Promise { 53 | const { 54 | agentId, 55 | userId, 56 | } = payload; 57 | 58 | if (this.connectedAs) { 59 | throw new Error( 60 | 'Already connected as a user or agent. Create a new instance to connect again.', 61 | ); 62 | } 63 | 64 | try { 65 | const response = await axios.post<{ agentToken: string }>( 66 | `${BASE_URL}/auth/agents/connect`, 67 | { agentId, userId }, 68 | { headers: { projectKey: this.projectKey } }, 69 | ); 70 | const authToken = response.data.agentToken; 71 | 72 | this.userToken = authToken; 73 | this.connectedAs = 'agent'; 74 | 75 | return authToken; 76 | } catch (error: any) { 77 | throw new Error( 78 | `Agent authentication failed: ${ 79 | error.response?.data?.message || error.message 80 | }`, 81 | ); 82 | } 83 | } 84 | 85 | /** 86 | * Connects you as user and stores authorization token inside the current class instance. 87 | * 88 | * @param payload 89 | */ 90 | async connectAsUser(payload: ConnectAsUserPayload): Promise { 91 | const { 92 | token, 93 | provider= 'custom', 94 | } = payload; 95 | 96 | if (this.connectedAs) { 97 | throw new Error( 98 | 'Already connected as a user or agent. Create a new instance to connect again.', 99 | ); 100 | } 101 | 102 | try { 103 | const response = await axios.post<{ userToken: string }>( 104 | `${BASE_URL}/auth/users/connect`, 105 | { provider, token }, 106 | { headers: { projectKey: this.projectKey } }, 107 | ); 108 | const authToken = response.data.userToken; 109 | 110 | this.userToken = authToken; 111 | this.connectedAs = 'user'; 112 | 113 | return authToken; 114 | } catch (error: any) { 115 | throw new Error( 116 | `User authentication failed: ${ 117 | error.response?.data?.message || error.message 118 | }`, 119 | ); 120 | } 121 | } 122 | 123 | /** 124 | * Works mostly the same way as `CaishenSDK` and issues an authorization token for Caishen API 125 | * without storing it into the current class instance. 126 | * @param payload 127 | */ 128 | async issueAuthToken(payload: IssueAuthTokenPayload): Promise { 129 | try { 130 | if (payload.connectAs === 'user' ) { 131 | const { provider = 'custom', token } = payload 132 | const response = await axios.post<{ userToken: string }>( 133 | `${BASE_URL}/auth/users/connect`, 134 | { provider, token }, 135 | { headers: { projectKey: this.projectKey } }, 136 | ); 137 | const authToken = response.data.userToken; 138 | return authToken; 139 | } 140 | 141 | const { userId, agentId } = payload 142 | const response = await axios.post<{ agentToken: string }>( 143 | `${BASE_URL}/auth/agents/connect`, 144 | { agentId, userId }, 145 | { headers: { projectKey: this.projectKey } }, 146 | ); 147 | 148 | const authToken = response.data.agentToken; 149 | return authToken; 150 | } catch (error: any) { 151 | throw new Error( 152 | `Authentication failed: ${ 153 | error.response?.data?.message || error.message 154 | }`, 155 | ); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /test/support/blockchain-configs.ts: -------------------------------------------------------------------------------- 1 | /*** Uncomment blockchains that should be tested ***/ 2 | 3 | export const BLOCKCHAIN_CONFIGS = [ 4 | { 5 | type: 'BITCOIN', 6 | name: 'BITCOIN', 7 | tokens: [ 8 | { 9 | symbol: 'BTC', 10 | }, 11 | ], 12 | transferDest: { 13 | address: 'bc1q4mxn3kzmw96e3el7fzkyv7rxyqcz5xkxcclmah', 14 | }, 15 | }, 16 | { 17 | type: 'LITECOIN', 18 | name: 'LITECOIN', 19 | tokens: [ 20 | { 21 | symbol: 'LTC', 22 | }, 23 | ], 24 | transferDest: { 25 | address: 'LTDd2ZXZWgMVVW2hWcra1NTW1rZkAKd4aL', 26 | }, 27 | }, 28 | { 29 | type: 'TRON', 30 | name: 'TRON', 31 | tokens: [ 32 | { 33 | symbol: 'TRX', 34 | }, 35 | { 36 | address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', 37 | symbol: 'USDT', 38 | }, 39 | ], 40 | transferDest: { 41 | address: 'TMJ8vu3vm6eU5UndnEdUdaQmKgPJXLRwBQ', 42 | }, 43 | }, 44 | { 45 | type: 'XRP', 46 | name: 'RIPPLE', 47 | tokens: [ 48 | { 49 | symbol: 'XRP', 50 | }, 51 | ], 52 | transferDest: { 53 | memo: 2987311027, 54 | address: 'rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg', 55 | }, 56 | }, 57 | { 58 | type: 'TON', 59 | name: 'TON', 60 | tokens: [ 61 | { 62 | symbol: 'TON', 63 | }, 64 | { 65 | address: 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs', 66 | symbol: 'USDT', 67 | }, 68 | ], 69 | transferDest: { 70 | address: 'EQA2jnm1S6htWeWjNfY_3ZBmg_U_tF9KK-RstrySUepbJmEq', 71 | }, 72 | }, 73 | { 74 | type: 'CARDANO', 75 | name: 'CARDANO', 76 | tokens: [ 77 | { 78 | symbol: 'ADA', 79 | }, 80 | { 81 | // CIP-25 82 | address: 83 | 'd1fc2f1815468b948fead16244735a378c3e3c89be52ce85791a926755534443', // encoded name 84 | symbol: 'USDC', 85 | }, 86 | ], 87 | transferDest: { 88 | address: 'addr1v83jwzvhv4xfkfdwne2f0tgg64994kq929zql0y6frsqrhccnkyfx', 89 | }, 90 | }, 91 | { 92 | type: 'SOLANA', 93 | name: 'SOLANA', 94 | tokens: [ 95 | { 96 | symbol: 'SOL', 97 | }, 98 | { 99 | // SPL 100 | address: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', 101 | symbol: 'USDT', 102 | }, 103 | ], 104 | transferDest: { 105 | address: 'ANnz9oS3CRSgczVBZyGfJFiyYRKutgsxf5CCWToPFRBQ', 106 | }, 107 | }, 108 | { 109 | type: 'SUI', 110 | name: 'SUI', 111 | tokens: [ 112 | { 113 | symbol: 'SUI', 114 | }, 115 | { 116 | address: 117 | '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', 118 | symbol: 'USDC', 119 | }, 120 | ], 121 | transferDest: { 122 | address: 123 | '0x8a1183abd28ccbab33c44b513a582cf9eaee580f4d8fdac80e138add659dca59', 124 | }, 125 | }, 126 | { 127 | type: 'APTOS', 128 | name: 'APTOS', 129 | tokens: [ 130 | { 131 | symbol: 'APT', 132 | }, 133 | { 134 | address: '0x357b0b74bc833e95a115ad22604854d6b0fca151cecd94111770e5d6ffc9dc2b', 135 | symbol: 'USDT', 136 | } 137 | ], 138 | transferDest: { 139 | address: '0x66c9a7af53ee4fea18064c82b2cfae0201aade80043ff91590e515e303fe5b97' 140 | } 141 | }, 142 | // { 143 | // type: 'ETHEREUM', // EVM BASED 144 | // chainId: 1, 145 | // name: 'ETHEREUM', 146 | // tokens: [ 147 | // { 148 | // symbol: 'ETH', 149 | // }, 150 | // { // ERC20 151 | // address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', 152 | // symbol: 'USDT', 153 | // } 154 | // ], 155 | // transferDest: { 156 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 157 | // } 158 | // }, 159 | // { 160 | // type: 'ETHEREUM', 161 | // chainId: 56, 162 | // name: 'Binance SC', 163 | // tokens: [ 164 | // { 165 | // symbol: 'BNB', 166 | // }, 167 | // { 168 | // address: '0xef6d459fe81c3ed53d292c936b2df5a8084975de', 169 | // symbol: 'crUSDT', 170 | // } 171 | // ], 172 | // transferDest: { 173 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 174 | // }, 175 | // }, 176 | // { 177 | // type: 'ETHEREUM', 178 | // chainId: 43114, 179 | // name: 'Avalanche (C-Chain)', 180 | // tokens: [ 181 | // { 182 | // symbol: 'AVAXC', 183 | // }, 184 | // { 185 | // address: '0xde3A24028580884448a5397872046a019649b084', 186 | // symbol: 'USDT', 187 | // }, 188 | // ], 189 | // transferDest: { 190 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 191 | // }, 192 | // }, 193 | // { 194 | // type: 'ETHEREUM', 195 | // chainId: 137, 196 | // name: 'POLYGON', 197 | // tokens: [ 198 | // { 199 | // symbol: 'POL' 200 | // }, 201 | // { 202 | // address: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', 203 | // symbol: 'USDC' 204 | // }, 205 | // ], 206 | // transferDest: { 207 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 208 | // }, 209 | // }, 210 | // { 211 | // type: 'ETHEREUM', 212 | // chainId: 10, 213 | // name: 'OPTIMISM', 214 | // tokens: [ 215 | // { 216 | // symbol: 'OPT' 217 | // }, 218 | // { // ERC20 219 | // address: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', 220 | // symbol: 'USDT' 221 | // } 222 | // ], 223 | // transferDest: { 224 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 225 | // }, 226 | // }, 227 | { 228 | type: 'ETHEREUM', 229 | chainId: 42161, 230 | name: 'ARBITRUM', 231 | tokens: [ 232 | { 233 | symbol: 'ETH', 234 | }, 235 | { 236 | // ERC20 237 | address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', 238 | symbol: 'USDT', 239 | }, 240 | ], 241 | transferDest: { 242 | address: '0x6052a78f280474De3e7A4937702914cbFD9b2764', 243 | }, 244 | }, 245 | // { 246 | // type: 'ETHEREUM', 247 | // chainId: 8453, 248 | // name: 'BASE', 249 | // tokens: [ 250 | // { 251 | // symbol: 'ETH', 252 | // }, 253 | // { // ERC20 254 | // address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', 255 | // symbol: 'USDC', 256 | // } 257 | // ], 258 | // transferDest: { 259 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 260 | // }, 261 | // }, 262 | // { 263 | // type: 'ETHEREUM', 264 | // chainId: 34443, 265 | // name: 'MODE', 266 | // tokens: [ 267 | // { 268 | // symbol: 'ETH', 269 | // }, 270 | // { // ERC20 271 | // address: '0xf0F161fDA2712DB8b566946122a5af183995e2eD', 272 | // symbol: 'USDC', 273 | // } 274 | // ], 275 | // transferDest: { 276 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 277 | // }, 278 | // }, 279 | // { 280 | // type: 'ETHEREUM', 281 | // chainId: 5000, 282 | // name: 'MANTLE', 283 | // tokens: [ 284 | // { 285 | // symbol: 'ETH', 286 | // }, 287 | // { // ERC20 288 | // address: '0xf0F161fDA2712DB8b566946122a5af183995e2eD', 289 | // symbol: 'USDC', 290 | // } 291 | // ], 292 | // transferDest: { 293 | // address: '0x6052a78f280474De3e7A4937702914cbFD9b2764' 294 | // }, 295 | // }, 296 | ]; 297 | -------------------------------------------------------------------------------- /src/tools/get-tools.ts: -------------------------------------------------------------------------------- 1 | import type { CaishenSDK } from '../caishen'; 2 | import { 3 | CashGetBalanceSchema, 4 | DepositCashSchema, 5 | SendTransactionSchema, 6 | WithdrawCashSchema, 7 | } from '../cash/schema'; 8 | import { 9 | CryptoGetBalanceSchema, 10 | CryptoGetSwapRouteSchema, 11 | CryptoSendSchema, CryptoSignAndSendSchema, CryptoSignSchema, 12 | CryptoSwapSchema, 13 | } from '../schema/schema'; 14 | import { toolBase } from './tool-base'; 15 | import { ChainType } from '../constants'; 16 | import { Tools } from './interfaces'; 17 | 18 | export function getTools({ sdk }: { sdk: CaishenSDK }): Tools { 19 | const tools: Tools = { 20 | cash_get_balance: toolBase({ 21 | name: 'cash_get_balance', 22 | description: `Retrieve the cash balance of a specified account. 23 | 24 | Inputs (JSON string): 25 | - account: number (required) — the account number to fetch the balance for. 26 | `, 27 | parameters: CashGetBalanceSchema, 28 | execute: async (params) => { 29 | if (typeof params.account !== 'number') { 30 | throw new Error('account field must be a number'); 31 | } 32 | return await sdk.cash.getBalance(params); 33 | }, 34 | }), 35 | 36 | cash_deposit: toolBase({ 37 | name: 'cash_deposit', 38 | description: `Deposit cash into your account using Caishen. 39 | 40 | Inputs (JSON string): 41 | - amount: string (required) — the amount to deposit 42 | - tokenAddress: string (required)- the token address 43 | - account: number (required) - account number 44 | `, 45 | parameters: DepositCashSchema, 46 | execute: async (params) => { 47 | if (!params.amount || !params.account || !params.tokenAddress) { 48 | throw new Error( 49 | 'amount, account, and tokenAddress fields are required', 50 | ); 51 | } 52 | return await sdk.cash.deposit(params); 53 | }, 54 | }), 55 | 56 | cash_send: toolBase({ 57 | name: 'cash_send', 58 | description: `Send cash to another account or destination using Caishen. 59 | 60 | Inputs (JSON string): 61 | - amount: string (required) — amount to send 62 | - toAddress: string (required)- another account or destination address 63 | - account: number (required) - account number 64 | `, 65 | parameters: SendTransactionSchema, 66 | execute: async (params) => { 67 | if (!params.amount || !params.account || !params.toAddress) { 68 | throw new Error('amount, account, and toAddress are required fields'); 69 | } 70 | return await sdk.cash.send(params); 71 | }, 72 | }), 73 | 74 | cash_withdraw: toolBase({ 75 | name: 'cash_withdraw', 76 | description: `Withdraw cash from your Caishen account to a specified destination. 77 | 78 | Inputs (JSON string): 79 | - amount: string (required) — amount to withdraw 80 | - tokenAddress: string (required) — the token address 81 | - account: number (required) - account number 82 | `, 83 | parameters: WithdrawCashSchema, 84 | execute: async (params) => { 85 | if (!params.amount || !params.account || !params.tokenAddress) { 86 | throw new Error( 87 | 'amount, account, and tokenAddress are required fields', 88 | ); 89 | } 90 | return await sdk.cash.withdraw(params); 91 | }, 92 | }), 93 | 94 | crypto_get_balance: toolBase({ 95 | name: 'crypto_get_balance', 96 | description: `Get the crypto balance for a wallet address. 97 | 98 | Inputs (JSON string): 99 | - wallet: object 100 | - address: string (required) 101 | - chainType: string (required, e.g., "ETHEREUM", "SOLANA") 102 | - chainId: number (optional) 103 | - publicKey: string (optional) 104 | - account: number (optional) 105 | - payload: object 106 | - token: string (optional) — token address or symbol to check balance for (default is native token like ETH, SOL). 107 | 108 | Returns the balance as a string.`, 109 | parameters: CryptoGetBalanceSchema, 110 | execute: async (params) => { 111 | const wallet = { 112 | chainType: params.chainType, 113 | chainId: params.chainId, 114 | publicKey: params.publicKey, 115 | account: params.account, 116 | }; 117 | const payload = { 118 | token: params.token, 119 | }; 120 | 121 | if (!wallet || !wallet.chainType) { 122 | throw new Error('wallet.chainType are required'); 123 | } 124 | 125 | return await sdk.crypto.getBalance({ 126 | wallet, 127 | payload, 128 | }); 129 | }, 130 | }), 131 | 132 | send_crypto: toolBase({ 133 | name: 'send_crypto', 134 | description: `Send crypto from a wallet to another address. 135 | 136 | Inputs (JSON string): 137 | - wallet: object 138 | - address: string (required) 139 | - chainType: string (required, e.g., "ETHEREUM", "SOLANA") 140 | - chainId: number (optional) 141 | - publicKey: string (optional) 142 | - account: number (optional) 143 | - payload: object 144 | - toAddress: string (required) — recipient address 145 | - amount: string (required) — amount to send 146 | - token: string (optional) — token address or symbol (send gas token if not specified) 147 | - memo: number (optional) — transaction memo (for Solana, etc.) 148 | 149 | Returns the transaction signature as a string.`, 150 | parameters: CryptoSendSchema, 151 | execute: async (params) => { 152 | const wallet = { 153 | chainType: params.chainType, 154 | chainId: params.chainId, 155 | account: params.account, 156 | }; 157 | const payload = { 158 | toAddress: params.toAddress, 159 | amount: params.amount, 160 | token: params.token, 161 | memo: params.memo, 162 | }; 163 | 164 | if (!wallet || !wallet.chainType) { 165 | throw new Error('wallet.chainType are required'); 166 | } 167 | if (!payload || !payload.toAddress || !payload.amount) { 168 | throw new Error('payload.toAddress and payload.amount are required'); 169 | } 170 | 171 | return await sdk.crypto.send({ 172 | wallet, 173 | payload, 174 | }); 175 | }, 176 | }), 177 | 178 | sign_and_send: toolBase({ 179 | name: 'sign_and_send', 180 | description: `Signs and broadcasts crypto transaction to a network. 181 | 182 | Inputs (JSON string): 183 | - wallet: object 184 | - address: string (required) 185 | - chainType: string (required, e.g., "ETHEREUM", "SOLANA") 186 | - chainId: number (optional) 187 | - publicKey: string (optional) 188 | - account: number (optional) 189 | - payload: object 190 | - serializedTransaction: string (required) — Serialized transaction (e.g. with [serializeTransaction]{@link https://viem.sh/docs/utilities/serializeTransaction.html}) - Hex 191 | 192 | Returns the transaction signature as a string.`, 193 | parameters: CryptoSignAndSendSchema, 194 | execute: async (params) => { 195 | const wallet = { 196 | chainType: params.chainType, 197 | chainId: params.chainId, 198 | account: params.account, 199 | }; 200 | const payload = { 201 | serializedTransaction: params.serializedTransaction, 202 | }; 203 | 204 | if (!wallet || !wallet.chainType) { 205 | throw new Error('wallet.chainType are required'); 206 | } 207 | if (!payload || !payload.serializedTransaction) { 208 | throw new Error('payload.serializedTransaction is required'); 209 | } 210 | 211 | return await sdk.crypto.signAndSend({ 212 | wallet, 213 | payload, 214 | }); 215 | }, 216 | }), 217 | 218 | sign: toolBase({ 219 | name: 'signs', 220 | description: `Signs transaction without broadcasting to a network. 221 | 222 | Inputs (JSON string): 223 | - wallet: object 224 | - address: string (required) 225 | - chainType: string (required, e.g., "ETHEREUM", "SOLANA") 226 | - chainId: number (optional) 227 | - publicKey: string (optional) 228 | - account: number (optional) 229 | - payload: object 230 | - serializedTransaction: string (required) — Serialized transaction (e.g. with [serializeTransaction]{@link https://viem.sh/docs/utilities/serializeTransaction.html}) - Hex 231 | 232 | Returns the transaction signature as a string.`, 233 | parameters: CryptoSignSchema, 234 | execute: async (params) => { 235 | const wallet = { 236 | chainType: params.chainType, 237 | account: params.account, 238 | }; 239 | const payload = { 240 | transactionData: params.transactionData, 241 | }; 242 | 243 | if (!wallet || !wallet.chainType) { 244 | throw new Error('wallet.chainType are required'); 245 | } 246 | if (!payload || !payload.transactionData) { 247 | throw new Error('payload.serializedTransaction is required'); 248 | } 249 | 250 | return await sdk.crypto.sign({ 251 | wallet, 252 | payload, 253 | }); 254 | }, 255 | }), 256 | 257 | swap_crypto: toolBase({ 258 | name: 'swap_crypto', 259 | description: `Execute a crypto swap for a wallet after receiving a confirmation code. 260 | 261 | Inputs (JSON string): 262 | - wallet: object 263 | - account: number (required) 264 | - chainType: string (required, e.g., "ETHEREUM", "SOLANA") 265 | - payload: object 266 | - confirmationCode: string (required) — swap route confirmation code 267 | 268 | Returns the swap route output upon success.`, 269 | parameters: CryptoSwapSchema, 270 | execute: async (params) => { 271 | const wallet = { 272 | account: params.account, 273 | chainType: params.chainType, 274 | }; 275 | const payload = { 276 | confirmationCode: params.confirmationCode, 277 | }; 278 | 279 | if (!wallet || wallet.account === undefined || !wallet.chainType) { 280 | throw new Error('wallet.account and wallet.chainType are required'); 281 | } 282 | if (!payload || !payload.confirmationCode) { 283 | throw new Error('payload.confirmationCode is required'); 284 | } 285 | 286 | return await sdk.crypto.swap({ 287 | wallet, 288 | payload, 289 | }); 290 | }, 291 | }), 292 | 293 | crypto_get_swap_route: toolBase({ 294 | name: 'crypto_get_swap_route', 295 | description: `Get a swap route to exchange tokens between two chains or within the same chain. 296 | 297 | Inputs (JSON string): 298 | - wallet: object 299 | - account: number (required) 300 | - payload: object 301 | - amount: string (required) — amount to swap (in token units) 302 | - from: object (required) 303 | - tokenAddress: string (required) 304 | - chainType: string (required, e.g., "ETHEREUM", "SOLANA") 305 | - chainId: number (optional) 306 | - to: object (required) 307 | - tokenAddress: string (required) 308 | - chainType: string (required) 309 | - chainId: number (optional) 310 | 311 | Returns swap route data needed to later execute the swap.`, 312 | parameters: CryptoGetSwapRouteSchema, 313 | execute: async (params) => { 314 | const wallet = { 315 | account: params.account, 316 | }; 317 | const payload = { 318 | amount: params.amount, 319 | from: { 320 | tokenAddress: params.fromAddress, 321 | chainType: ChainType[params.fromChainType as keyof typeof ChainType], 322 | chainId: params.fromChainId, 323 | }, 324 | to: { 325 | tokenAddress: params.toAddress, 326 | chainType: ChainType[params.toChainType as keyof typeof ChainType], 327 | chainId: params.toChainId, 328 | }, 329 | }; 330 | 331 | if (!wallet || wallet.account === undefined) { 332 | throw new Error('wallet.account is required'); 333 | } 334 | if (!payload || !payload.amount || !payload.from || !payload.to) { 335 | throw new Error( 336 | 'payload.amount, payload.from, and payload.to are required', 337 | ); 338 | } 339 | 340 | return await sdk.crypto.getSwapRoute({ 341 | wallet, 342 | payload, 343 | }); 344 | }, 345 | }), 346 | }; 347 | 348 | return tools; 349 | } 350 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Caishen SDK 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![npm version](https://badge.fury.io/js/caishen-sdk.svg)](https://badge.fury.io/js/caishen-sdk) 5 | 6 | > The Caishen SDK provides developers with seamless access to unlimited multi-chain crypto wallets. It offers a unified interface for interacting with various blockchain networks and managing crypto assets. 7 | 8 | --- 9 | 10 | ## ✨ Features 11 | 12 | - 🔗 Multi-chain wallet support 13 | - 🌐 Supports major blockchains: 14 | - Ethereum (via `ethers.js`) 15 | - Bitcoin (via `bitcoinjs-lib`) 16 | - Solana (via `@solana/web3.js`) 17 | - Cardano (via `@emurgo/cardano-serialization-lib`) 18 | - Sui, NEAR, Ripple, Tron, TON, Aptos 19 | - 🔒 Secure wallet management 20 | - ⚙️ Type-safe TypeScript APIs 21 | - 💸 Token operations: Send, Balance, Swap, Deposit, Withdraw 22 | - Cash operations: Send, Deposit, Withdraw 23 | 24 | --- 25 | 26 | ## 📦 Installation 27 | 28 | ```bash 29 | npm install @caishen/sdk 30 | # or 31 | yarn add @caishen/sdk 32 | # or 33 | pnpm add @caishen/sdk 34 | ``` 35 | 36 | > ⚠️ Requires Node.js ≥ 14.x and TypeScript ≥ 4.x 37 | 38 | --- 39 | 40 | ## 🔗 Links 41 | 42 | - 🌐 [Website](https://caishen.tech) 43 | - 🛠️ [Developer Dashboard](https://dashboard.caishen.tech) 44 | - 📚 [Docs](https://docs.caishen.tech) 45 | 46 | --- 47 | 48 | ## 🚀 Quick Start 49 | 50 | ```ts 51 | import { CaishenSDK, createAgentTools } from "@caishen/sdk"; 52 | 53 | const sdk = new CaishenSDK({ projectKey: "your-project-key" }); 54 | const tools = createAgentTools(sdk); 55 | ``` 56 | 57 | --- 58 | 59 | ## 🔑 Authentication 60 | 61 | You can authenticate as either a **user** or an **agent**. 62 | 63 | ### Connect as User 64 | 65 | ```ts 66 | await sdk.connectAsUser({ 67 | token: 'USER TOKEN', 68 | provider: 'USER PROVIDER', 69 | }); 70 | ``` 71 | 72 | #### ✅ Supported Providers 73 | 74 | - `google`, `facebook`, `twitter`, `discord`, `github`, `linkedin` 75 | - `reddit`, `line`, `kakao`, `weibo`, `farcaster`, `custom` 76 | 77 | --- 78 | 79 | ### 🔐 Custom Authentication 80 | 81 | If you want to authenticate users **from your own backend**, you can use the `custom` provider. 82 | 83 | In this case: 84 | 85 | - You must **encrypt a JWT** on your backend using your `projectSecret` (found in your Caishen developer dashboard). 86 | - That encrypted token must contain an object like `{ id: string }`, where `id` is the user identifier in your system. 87 | - You then pass this encrypted token into `connectAsUser`. 88 | 89 | #### 💡 Example 90 | **Backend-side (Node.js):** 91 | 92 | ```ts 93 | import jwt from 'jsonwebtoken'; 94 | 95 | const payload = { id: 'user-123' }; 96 | const token = jwt.sign(payload, projectSecret); 97 | ``` 98 | 99 | **Frontend-side:** 100 | 101 | ```ts 102 | await sdk.connectAsUser({ 103 | provider: 'custom', 104 | token: 'ENCRYPTED_JWT_TOKEN', 105 | }); 106 | ``` 107 | 108 | On the Caishen backend, this token is decrypted with your `projectSecret` using: 109 | 110 | ```ts 111 | jwt.verify(token, projectSecret); // -> { id: string } 112 | ``` 113 | 114 | > ⚠️ Never share your `projectSecret` publicly. Only your server should have access to it. 115 | 116 | --- 117 | 118 | 119 | ### Issue authorization token 120 | 121 | Simple way to issue an authorization token for the Caishen API without storing it in the CaishenSDK instance. 122 | 123 | As because you cannot call `connectAsUser` or `connectAsAgent` twice, this method provides you an ability to get authorization token (of a user or agent) based on your credentials. 124 | 125 | Useful primarily for authorizing multiple users independently on your back-end side and managing it without. 126 | 127 | 128 | ##### Example: 129 | ```ts 130 | const authToken = await sdk.issueAuthToken({ 131 | connectAs: 'user', 132 | provider: 'custom', 133 | token: 'ENCRYPTED_JWT_TOKEN', 134 | }); 135 | 136 | const balance = await sdk.crypto.getBalance({ 137 | wallet: { 138 | account: 1, 139 | chainId: 1, 140 | chainType: 'ETHEREUM', 141 | }, 142 | authToken, 143 | }); 144 | 145 | console.log(`Balance ETH: ${balance}`) 146 | ``` 147 | 148 | Here is a basic real-world example of how you can use it: 149 | ```ts 150 | // Create a global SDK instance with project key provided 151 | const caishenSDK = new CaisenSDK({ projectKey }); 152 | 153 | @Injectable() 154 | export class AuthGuard implements CanActivate { 155 | constructor(private jwtService: JwtService) {} 156 | 157 | async canActivate(context: ExecutionContext): Promise { 158 | const request = context.switchToHttp().getRequest(); 159 | const token = this.extractTokenFromHeader(request); 160 | 161 | if (!token) { 162 | throw new UnauthorizedException('Missing JWT token'); 163 | } 164 | 165 | try { 166 | // Verify main JWT token 167 | const payload = await this.jwtService.verifyAsync(token, { 168 | secret: jwtConstants.secret, 169 | }); 170 | 171 | // Extract and verify the encrypted Caishen auth token from payload 172 | const encryptedCaishenToken = payload.caishenAuthTokenEncrypted; 173 | 174 | let decryptedCaishenToken = await this.jwtService.verifyAsync( 175 | encryptedCaishenToken, 176 | { 177 | secret: jwtConstants.caishenSecret, 178 | }, 179 | ); 180 | 181 | // Optional: validate token expiration or structure 182 | 183 | if (!decryptedCaishenToken) { 184 | // Fallback: generate a new token via SDK if decryption fails 185 | decryptedCaishenToken = await caishenSDK.issueAuthToken({ 186 | provider: 'custom', 187 | token: payload.userId, // Replace with actual user ID if available 188 | connectAs: 'user', 189 | }); 190 | } 191 | 192 | // Attach the decrypted token to the request for later use 193 | request.caishenAuthTokenDecrypted = decryptedCaishenToken; 194 | 195 | return true; 196 | } catch (error) { 197 | console.error('AuthGuard error:', error); 198 | throw new UnauthorizedException('Invalid token or authorization failed'); 199 | } 200 | } 201 | 202 | // Extracts JWT token from Authorization header 203 | private extractTokenFromHeader(request: Request): string | undefined { 204 | const [type, token] = request.headers.authorization?.split(' ') ?? []; 205 | return type === 'Bearer' ? token : undefined; 206 | } 207 | } 208 | 209 | @Controller('my-api') 210 | export class MyApiController { 211 | constructor(private readonly caishenSDK: CaisenSDK) {} 212 | 213 | @UseGuards(AuthGuard) 214 | @Get('balance') 215 | async getMyBalance(@Request() req) { 216 | const caishenUserAuthToken = req.caishenAuthTokenDecrypted; 217 | const balance = await this.caishenSDK.crypto.getBalance({ 218 | wallet: { account: 1, chainType: ChainType.SUI }, 219 | authToken: caishenUserAuthToken, 220 | }); 221 | 222 | return balance; 223 | } 224 | } 225 | ``` 226 | 227 | ### Connect as Agent 228 | 229 | ```ts 230 | await sdk.connectAsAgent({ 231 | agentId: 'AGENT ID', 232 | userId: 'USER ID', // NOTE: userId cannot be provided without an agentId 233 | }); 234 | ``` 235 | 236 | > Different values for `agentId` and `userId` will generate different wallet scopes. 237 | 238 | --- 239 | 240 | ## 👛 Wallets 241 | 242 | ### 🔍 Get Wallet Info 243 | 244 | > ⚠️ The `privateKey` is only returned if `allowPrivateKeyAccess` is enabled in your developer dashboard. 245 | > You do **not** need to send the private key back to the server. All you need is `{ account, chainType }`. 246 | 247 | #### 📥 Parameters 248 | 249 | | Name | Type | Required | Description | 250 | |-------------|----------|----------|-------------| 251 | | `chainType` | string | ✅ | Blockchain type (`ETHEREUM`, `SOLANA`, etc.) | 252 | | `account` | number | ✅ | Account index or identifier | 253 | 254 | 255 | #### ✅ Supported chainTypes 256 | 257 | - `BITCOIN`, `LITECOIN`, `DASHCOIN`, `DOGECOIN` 258 | - `ETHEREUM` (and other EVM-based, such as, `Arbitrum`, `Polygon`, `Optimism`, etc.) 259 | - `SUI`, `SOLANA`, `APTOS`, `TON`, `TRON`, `NEAR`, `XRP`, `CARDANO`, `COSMOS` 260 | 261 | --- 262 | 263 | #### 📘 Example 264 | ```ts 265 | const wallet = await sdk.crypto.getWallet({ 266 | chainType: 'ETHEREUM', 267 | account: 1, 268 | }); 269 | ``` 270 | 271 | #### 📚 Type: `IWalletAccount` 272 | ```ts 273 | interface IWalletAccount { 274 | address: string; 275 | chainType: string; 276 | account: number; 277 | publicKey: string; 278 | privateKey?: string; // Only returned if access is enabled in the dashboard 279 | } 280 | ``` 281 | 282 | ### MinimalWalletInput 283 | 284 | ```ts 285 | interface MinimalWalletInput { 286 | account: number; 287 | chainType: string; 288 | address: string; 289 | } 290 | ``` 291 | 292 | Used for all `cash` and `swap` functions to avoid sending sensitive data. 293 | 294 | --- 295 | 296 | ## 💸 Token Operations 297 | 298 | > 🚫 Use `MinimalWalletInput` when possible to reduce sensitive data exposure. 299 | 300 | ### ➕ Send Token 301 | ```ts 302 | const txHash = await sdk.crypto.send({ 303 | wallet: { 304 | account: 1, 305 | chainType: "ETHEREUM", 306 | /** 307 | * If not provided, our Caishen's rpc will be used. 308 | * NOTE: currently custom RPC feature is not supported for Bitcoin based blockchains 309 | * (such as Bitcoin, Litecoin, Dogecoin, Dashcoin) 310 | * 311 | * Specify ws rpc for Cardano & Ripple, 312 | */ 313 | rpc: 'your_rpc_url' 314 | }, 315 | payload: { 316 | token: '0xTokenAddress...', // omit for native 317 | amount: '1000000000000000000', // amount in base units 318 | toAddress: '0xRecipient...', 319 | }, 320 | }); 321 | ``` 322 | 323 | ### 📊 Get Balance 324 | ```ts 325 | const native = await sdk.crypto.getBalance({ wallet, payload: {} }); 326 | const dai = await sdk.crypto.getBalance({ 327 | wallet, 328 | payload: { token: '0x6B1754...' }, 329 | }); 330 | ``` 331 | 332 | ### ✍️ Sign and Send transaction 333 | 334 | ```ts 335 | import { serializeTransaction, parseGwei, parseEther } from 'viem' 336 | 337 | const serializedTransaction = serializeTransaction({ 338 | chainId: 1, 339 | gas: 21001n, 340 | maxFeePerGas: parseGwei('20'), 341 | maxPriorityFeePerGas: parseGwei('2'), 342 | nonce: 69, 343 | to: "0x1234512345123451234512345123451234512345", 344 | value: parseEther('0.01'), 345 | }) 346 | 347 | const transactionHash = await sdk.crypto.signAndSend({ 348 | wallet, 349 | payload: { 350 | serializedTransaction, 351 | } 352 | }); 353 | ``` 354 | 355 | > NOTE: You can provide your custom URL API endpoint to fetch UTXOs for BTC-based chains like BTC, LTC, etc. 356 | > Pass `utxoUrl` parameter as an option. The endpoint MUST return an array structure like 357 | > ``` 358 | > Array<{ 359 | > vout: number; 360 | > value: number; // satoshi 361 | > txId: string; 362 | > }> 363 | > ``` 364 | 365 | ### ✍️ Sign transaction 366 | 367 | ```ts 368 | import { serializeTransaction, parseGwei, parseEther } from 'viem' 369 | 370 | const serializedTransaction = serializeTransaction({ 371 | chainId: 1, 372 | gas: 21001n, 373 | maxFeePerGas: parseGwei('20'), 374 | maxPriorityFeePerGas: parseGwei('2'), 375 | nonce: 69, 376 | to: "0x1234512345123451234512345123451234512345", 377 | value: parseEther('0.01'), 378 | }) 379 | 380 | const transactionHash = await sdk.crypto.sign({ 381 | wallet, 382 | payload: { 383 | transactionData: serializedTransaction, 384 | } 385 | }); 386 | ``` 387 | 388 | --- 389 | 390 | ## 🔁 Token Swap 391 | 392 | > 🚫 Do not send the full wallet object. Use only `{ account, chainType }`. 393 | 394 | ### 🔍 Get Swap Route 395 | ```ts 396 | const route = await sdk.crypto.getSwapRoute({ 397 | wallet: { account: 0 }, 398 | payload: { 399 | amount: '1000000000000000000', 400 | from: { tokenAddress: '0x...', chainType: 'ETHEREUM' }, 401 | to: { tokenAddress: '0x...', chainType: 'ETHEREUM' }, 402 | }, 403 | }); 404 | ``` 405 | 406 | ### 🔄 Execute Swap 407 | ```ts 408 | const result = await sdk.crypto.swap({ 409 | wallet: { account: 0, chainType: 'ETHEREUM' }, 410 | payload: { confirmationCode: 'abc123' }, 411 | }); 412 | ``` 413 | 414 | --- 415 | 416 | ## 🏦 Cash Accounts 417 | 418 | > **Cash** is a chain-abstracted, gasless stablecoin system designed to make stablecoin transfers seamless, fast, and free. 419 | 420 | ### 🔍 What is Cash? 421 | 422 | **Cash** is an internal ERC-20-compatible asset that abstracts away the complexity of stablecoins across chains. It enables instant, gasless transfers between wallets without needing users to worry about: 423 | 424 | - Native gas tokens (e.g., ETH, MATIC) 425 | - Stablecoin formats (e.g., USDC vs USDT) 426 | - Blockchain networks (e.g., Arbitrum, Base, Solana) 427 | 428 | ### 🧪 How It Works 429 | 430 | - **Deposit**: Users deposit supported stablecoins (e.g., USDC, USDT) from chains like Arbitrum, Base, or Solana. 431 | - **Issue**: The system issues equivalent **Cash** tokens 1:1, held in an abstracted balance. 432 | - **Send**: These Cash tokens can be sent to any wallet address instantly with zero gas cost. 433 | - **Withdraw**: When users withdraw, their Cash tokens are burned and they receive the original stablecoin on the selected chain. 434 | 435 | > ⚠️ Different combinations of `agentId` and `userId` result in separate Cash balances. 436 | 437 | ### ✅ Benefits 438 | 439 | - 💸 Gasless transfers (no ETH/SOL required) 440 | - ⚡ Cross-chain abstraction 441 | - 🔄 Simple send/receive interface 442 | - 🔐 Fully backed, 1:1 redeemable 443 | 444 | --- 445 | 446 | ### 💱 Supported Stablecoins 447 | 448 | | Chain | Token | Symbol | Address | 449 | |-----------|--------|--------|---------| 450 | | Arbitrum | USDC | USDC | `0xaf88...5831` | 451 | | Arbitrum | USDT | USDT | `0xFd08...cbb9` | 452 | | Base | USDC | USDC | `0x8335...2913` | 453 | | Solana | USDC | USDC | `EPjFWd...TDt1v` | 454 | 455 | > See `CASH_SUPPORTED_TOKENS` for full details. 456 | 457 | ### 💰 Get Account Balance 458 | Get current balance of all tokens for a specific account. 459 | 460 | #### Parameters 461 | 462 | | Name | Type | Description | 463 | |----------|--------|--------------------------| 464 | | account | number | The account identifier | 465 | 466 | #### Returns 467 | 468 | ```ts 469 | Promise 470 | ``` 471 | 472 | #### 📘 Example 473 | 474 | ```ts 475 | const balance = await sdk.cash.getBalance({ account: 1 }); 476 | ``` 477 | 478 | ### 💵 Deposit 479 | Deposit a supported token into the account. 480 | 481 | #### Parameters 482 | 483 | | Name | Type | Description | 484 | |----------|---------------------|------------------------| 485 | | params | `DepositCashParams` | Token and amount info | 486 | 487 | #### Returns 488 | 489 | ```ts 490 | Promise 491 | ``` 492 | 493 | #### 📘 Example 494 | 495 | ```ts 496 | await sdk.cash.deposit({ 497 | account: 1, 498 | tokenAddress: '0x...', 499 | amount: '1000000000000000000', 500 | }); 501 | ``` 502 | 503 | ### 💸 Withdraw 504 | Withdraw a supported token from the account. 505 | 506 | #### Parameters 507 | 508 | | Name | Type | Description | 509 | |----------|----------------------|-----------------------| 510 | | params | `WithdrawCashParams` | Token and amount info | 511 | 512 | #### Returns 513 | 514 | ```ts 515 | Promise 516 | ``` 517 | 518 | #### 📘 Example 519 | 520 | ```ts 521 | await sdk.cash.withdraw({ 522 | account: 1, 523 | tokenAddress: '0x...', 524 | amount: '1000000000000000000', 525 | }); 526 | ``` 527 | 528 | ### 🔁 Send 529 | 530 | Send supported tokens between accounts. 531 | 532 | #### Parameters 533 | 534 | | Name | Type | Description | 535 | |----------|------------------------|-----------------------| 536 | | params | `SendTransactionParams`| Token, to/from, etc. | 537 | 538 | #### Returns 539 | 540 | ```ts 541 | Promise 542 | ``` 543 | 544 | #### 📘 Example 545 | 546 | ```ts 547 | await sdk.cash.send({ 548 | fromAccount: 1, 549 | toAccount: 2, 550 | tokenAddress: '0x...', 551 | amount: '1000000000000000000', 552 | }); 553 | ``` 554 | 555 | ### 🪙 Get Supported Tokens 556 | 557 | ```ts 558 | const tokens = await sdk.cash.getSupportedTokens(); 559 | ``` 560 | 561 | --- 562 | 563 | ## 🛠 Types 564 | 565 | ```ts 566 | type TokenWithPrice = Token & { 567 | priceUSD: string; 568 | }; 569 | ``` 570 | 571 | --- 572 | 573 | # Vercel AI, Langchain, and ElevenLabs Integration 574 | 575 | This project demonstrates the integration of three powerful AI tools: Vercel AI, Langchain, and ElevenLabs, to create intelligent and engaging applications. It showcases how these technologies can be combined to process natural language, orchestrate complex tasks, and generate realistic audio output. 576 | 577 | ## Overview 578 | 579 | This project provides examples of how to: 580 | 581 | - **Utilize Vercel AI:** Leverage Vercel AI's `generateText` function with custom tools to interact with external APIs or perform specific actions based on user input. 582 | - **Employ Langchain:** Use Langchain's agent capabilities and its integration with large language models (LLMs) to create sophisticated workflows involving multiple steps and tool usage. 583 | - **Integrate ElevenLabs:** Synthesize realistic speech from text using ElevenLabs' API, allowing for voice-based interactions and richer user experiences. 584 | 585 | The code snippets provided in this README illustrate fetching data using tools defined for each service and then logging the results. 586 | 587 | ## Prerequisites 588 | 589 | Before running this project, ensure you have the following: 590 | 591 | - **Node.js and npm (or yarn) installed:** This project is likely built using JavaScript/TypeScript. 592 | - **ElevenLabs API Key:** You'll need an API key from your ElevenLabs account to use their text-to-speech service. Set this as an environment variable (e.g., `ELEVENLABS_API_KEY`). 593 | - **Vercel AI SDK Installed:** Ensure you have the `@vercel/ai` package installed in your project. 594 | - **Langchain Installed:** Ensure you have the `langchain` and `@langchain/openai` packages installed. 595 | - **Zod Installed:** You're using `zod` for schema validation (`z`). 596 | - **`node-fetch` Installed:** If you're making direct API calls, you'll need `node-fetch`. 597 | 598 | ## Setup 599 | 600 | 1. **Clone the repository (if applicable):** 601 | ```bash 602 | git clone 603 | cd 604 | ``` 605 | 606 | 2. **Install dependencies:** 607 | ```bash 608 | npm install 609 | # or 610 | yarn install 611 | ``` 612 | 613 | 3. **Set up environment variables:** 614 | Create a `.env` file (or configure your environment variables through your hosting provider) and add your ElevenLabs API key: 615 | ``` 616 | ELEVENLABS_API_KEY=your_elevenlabs_api_key 617 | ``` 618 | 619 | ## Usage 620 | 621 | The provided code snippet demonstrates how to use each of the integrated services: 622 | 623 | ### ElevenLabs Integration 624 | 625 | ```javascript 626 | // /// ================ elevenLabsData ============= 627 | const elevenLabsData = await createElevenLabsTools({sdk}) 628 | const tools = castToToolRecord(elevenLabsData); 629 | const elevenLabs_input_text = "Hello, please give me the balance of account 15!"; 630 | const elevenLabsData_result = await generateText({ 631 | model: openai("gpt-4o-mini"), 632 | tools: tools, 633 | maxSteps: 10, 634 | prompt: elevenLabs_input_text, 635 | }); 636 | console.log("elevenLabs data result text: ", elevenLabsData_result.text); 637 | ``` 638 | 639 | // /// ================ vercelAIData ============= 640 | ```javascript 641 | const vercelAIData_text = "Hello, please give me the balance of account 15!"; 642 | const vercelAIData = await createVercelAITools({sdk}) 643 | const vercelAIData_result = await generateText({ 644 | model: openai("gpt-4o-mini"), 645 | tools: castToToolRecord(vercelAIData), 646 | maxSteps: 10, // Maximum number of tool invocations per request 647 | prompt: vercelAIData_text, 648 | }); 649 | console.log("vercelAIData Result text: ", vercelAIData_result.text); 650 | ## 🧱 Build from Source 651 | ``` 652 | 653 | // /// ================ langchainData ============= 654 | ```javascript 655 | const langhchain_tools = createAgentTools(sdk) 656 | const langchainData_text = "Fetch my cash balance account 12345"; 657 | const llm = new ChatOpenAI({ 658 | temperature: 0, 659 | modelName: "gpt-4o-mini", // or "gpt-3.5-turbo", whatever you're using 660 | }); 661 | const executor = await initializeAgentExecutorWithOptions( 662 | langhchain_tools, 663 | llm, // your model (OpenAI, Anthropic, etc) 664 | { 665 | agentType: "openai-functions",//"zero-shot-react-description", 666 | verbose: true, 667 | } 668 | ); 669 | // now you can run 670 | const res = await executor.call({ input: langchainData_text }); 671 | console.log("langchain result output: ", res.output); 672 | ``` 673 | 674 | ```bash 675 | npm install 676 | npm run dev 677 | npm run build 678 | ``` 679 | 680 | --- 681 | 682 | ## 🤝 Contributing 683 | 684 | Contributions welcome! Open an issue or PR. 685 | 686 | --- 687 | 688 | ## 📜 License 689 | 690 | MIT © [CaishenTech](https://github.com/CaishenTech) 691 | 692 | --- 693 | 694 | ## 💬 Support 695 | 696 | Open an issue on GitHub or contact the maintainers. 697 | 698 | --- 699 | 700 | Made with ❤️ by **Caishen** 701 | --------------------------------------------------------------------------------