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.
- 🔗 Multi-chain wallet support
- 🌐 Supports major blockchains:
- Ethereum (via
ethers.js
) - Bitcoin (via
bitcoinjs-lib
) - Solana (via
@solana/web3.js
) - Cardano (via
@emurgo/cardano-serialization-lib
) - Sui, NEAR, Ripple, Tron, TON, Aptos
- Ethereum (via
- 🔒 Secure wallet management
- ⚙️ Type-safe TypeScript APIs
- 💸 Token operations: Send, Balance, Swap, Deposit, Withdraw
- Cash operations: Send, Deposit, Withdraw
npm install @caishen/sdk
# or
yarn add @caishen/sdk
# or
pnpm add @caishen/sdk
⚠️ Requires Node.js ≥ 14.x and TypeScript ≥ 4.x
- 🌐 Website
- 🛠️ Developer Dashboard
- 📚 Docs
import { CaishenSDK, createAgentTools } from "@caishen/sdk";
const sdk = new CaishenSDK({ projectKey: "your-project-key" });
const tools = createAgentTools(sdk);
You can authenticate as either a user or an agent.
await sdk.connectAsUser({
token: 'USER TOKEN',
provider: 'USER PROVIDER',
});
-
google
,facebook
,twitter
,discord
,github
,linkedin
-
reddit
,line
,kakao
,weibo
,farcaster
,custom
If you want to authenticate users from your own backend, you can use the custom
provider.
In this case:
- You must encrypt a JWT on your backend using your
projectSecret
(found in your Caishen developer dashboard). - That encrypted token must contain an object like
{ id: string }
, whereid
is the user identifier in your system. - You then pass this encrypted token into
connectAsUser
.
Backend-side (Node.js):
import jwt from 'jsonwebtoken';
const payload = { id: 'user-123' };
const token = jwt.sign(payload, projectSecret);
Frontend-side:
await sdk.connectAsUser({
provider: 'custom',
token: 'ENCRYPTED_JWT_TOKEN',
});
On the Caishen backend, this token is decrypted with your projectSecret
using:
jwt.verify(token, projectSecret); // -> { id: string }
⚠️ Never share yourprojectSecret
publicly. Only your server should have access to it.
Simple way to issue an authorization token for the Caishen API without storing it in the CaishenSDK instance.
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.
Useful primarily for authorizing multiple users independently on your back-end side and managing it without.
const authToken = await sdk.issueAuthToken({
connectAs: 'user',
provider: 'custom',
token: 'ENCRYPTED_JWT_TOKEN',
});
const balance = await sdk.crypto.getBalance({
wallet: {
account: 1,
chainId: 1,
chainType: 'ETHEREUM',
},
authToken,
});
console.log(`Balance ETH: ${balance}`)
Here is a basic real-world example of how you can use it:
// Create a global SDK instance with project key provided
const caishenSDK = new CaisenSDK({ projectKey });
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException('Missing JWT token');
}
try {
// Verify main JWT token
const payload = await this.jwtService.verifyAsync(token, {
secret: jwtConstants.secret,
});
// Extract and verify the encrypted Caishen auth token from payload
const encryptedCaishenToken = payload.caishenAuthTokenEncrypted;
let decryptedCaishenToken = await this.jwtService.verifyAsync(
encryptedCaishenToken,
{
secret: jwtConstants.caishenSecret,
},
);
// Optional: validate token expiration or structure
if (!decryptedCaishenToken) {
// Fallback: generate a new token via SDK if decryption fails
decryptedCaishenToken = await caishenSDK.issueAuthToken({
provider: 'custom',
token: payload.userId, // Replace with actual user ID if available
connectAs: 'user',
});
}
// Attach the decrypted token to the request for later use
request.caishenAuthTokenDecrypted = decryptedCaishenToken;
return true;
} catch (error) {
console.error('AuthGuard error:', error);
throw new UnauthorizedException('Invalid token or authorization failed');
}
}
// Extracts JWT token from Authorization header
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
@Controller('my-api')
export class MyApiController {
constructor(private readonly caishenSDK: CaisenSDK) {}
@UseGuards(AuthGuard)
@Get('balance')
async getMyBalance(@Request() req) {
const caishenUserAuthToken = req.caishenAuthTokenDecrypted;
const balance = await this.caishenSDK.crypto.getBalance({
wallet: { account: 1, chainType: ChainType.SUI },
authToken: caishenUserAuthToken,
});
return balance;
}
}
await sdk.connectAsAgent({
agentId: 'AGENT ID',
userId: 'USER ID', // NOTE: userId cannot be provided without an agentId
});
Different values for
agentId
anduserId
will generate different wallet scopes.
⚠️ TheprivateKey
is only returned ifallowPrivateKeyAccess
is enabled in your developer dashboard.
You do not need to send the private key back to the server. All you need is{ account, chainType }
.
Name | Type | Required | Description |
---|---|---|---|
chainType |
string | ✅ | Blockchain type (ETHEREUM , SOLANA , etc.) |
account |
number | ✅ | Account index or identifier |
-
BITCOIN
,LITECOIN
,DASHCOIN
,DOGECOIN
-
ETHEREUM
(and other EVM-based, such as,Arbitrum
,Polygon
,Optimism
, etc.) -
SUI
,SOLANA
,APTOS
,TON
,TRON
,NEAR
,XRP
,CARDANO
,COSMOS
const wallet = await sdk.crypto.getWallet({
chainType: 'ETHEREUM',
account: 1,
});
interface IWalletAccount {
address: string;
chainType: string;
account: number;
publicKey: string;
privateKey?: string; // Only returned if access is enabled in the dashboard
}
interface MinimalWalletInput {
account: number;
chainType: string;
address: string;
}
Used for all cash
and swap
functions to avoid sending sensitive data.
🚫 Use
MinimalWalletInput
when possible to reduce sensitive data exposure.
const txHash = await sdk.crypto.send({
wallet: {
account: 1,
chainType: "ETHEREUM",
/**
* If not provided, our Caishen's rpc will be used.
* NOTE: currently custom RPC feature is not supported for Bitcoin based blockchains
* (such as Bitcoin, Litecoin, Dogecoin, Dashcoin)
*
* Specify ws rpc for Cardano & Ripple,
*/
rpc: 'your_rpc_url'
},
payload: {
token: '0xTokenAddress...', // omit for native
amount: '1000000000000000000', // amount in base units
toAddress: '0xRecipient...',
},
});
const native = await sdk.crypto.getBalance({ wallet, payload: {} });
const dai = await sdk.crypto.getBalance({
wallet,
payload: { token: '0x6B1754...' },
});
import { serializeTransaction, parseGwei, parseEther } from 'viem'
const serializedTransaction = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: "0x1234512345123451234512345123451234512345",
value: parseEther('0.01'),
})
const transactionHash = await sdk.crypto.signAndSend({
wallet,
payload: {
serializedTransaction,
}
});
NOTE: You can provide your custom URL API endpoint to fetch UTXOs for BTC-based chains like BTC, LTC, etc. Pass
utxoUrl
parameter as an option. The endpoint MUST return an array structure likeArray<{ vout: number; value: number; // satoshi txId: string; }>
import { serializeTransaction, parseGwei, parseEther } from 'viem'
const serializedTransaction = serializeTransaction({
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('2'),
nonce: 69,
to: "0x1234512345123451234512345123451234512345",
value: parseEther('0.01'),
})
const transactionHash = await sdk.crypto.sign({
wallet,
payload: {
transactionData: serializedTransaction,
}
});
🚫 Do not send the full wallet object. Use only
{ account, chainType }
.
const route = await sdk.crypto.getSwapRoute({
wallet: { account: 0 },
payload: {
amount: '1000000000000000000',
from: { tokenAddress: '0x...', chainType: 'ETHEREUM' },
to: { tokenAddress: '0x...', chainType: 'ETHEREUM' },
},
});
const result = await sdk.crypto.swap({
wallet: { account: 0, chainType: 'ETHEREUM' },
payload: { confirmationCode: 'abc123' },
});
Cash is a chain-abstracted, gasless stablecoin system designed to make stablecoin transfers seamless, fast, and free.
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:
- Native gas tokens (e.g., ETH, MATIC)
- Stablecoin formats (e.g., USDC vs USDT)
- Blockchain networks (e.g., Arbitrum, Base, Solana)
- Deposit: Users deposit supported stablecoins (e.g., USDC, USDT) from chains like Arbitrum, Base, or Solana.
- Issue: The system issues equivalent Cash tokens 1:1, held in an abstracted balance.
- Send: These Cash tokens can be sent to any wallet address instantly with zero gas cost.
- Withdraw: When users withdraw, their Cash tokens are burned and they receive the original stablecoin on the selected chain.
⚠️ Different combinations ofagentId
anduserId
result in separate Cash balances.
- 💸 Gasless transfers (no ETH/SOL required)
- ⚡ Cross-chain abstraction
- 🔄 Simple send/receive interface
- 🔐 Fully backed, 1:1 redeemable
Chain | Token | Symbol | Address |
---|---|---|---|
Arbitrum | USDC | USDC | 0xaf88...5831 |
Arbitrum | USDT | USDT | 0xFd08...cbb9 |
Base | USDC | USDC | 0x8335...2913 |
Solana | USDC | USDC | EPjFWd...TDt1v |
See
CASH_SUPPORTED_TOKENS
for full details.
Get current balance of all tokens for a specific account.
Name | Type | Description |
---|---|---|
account | number | The account identifier |
Promise<BalanceResponse>
const balance = await sdk.cash.getBalance({ account: 1 });
Deposit a supported token into the account.
Name | Type | Description |
---|---|---|
params | DepositCashParams |
Token and amount info |
Promise<TransactionResponse>
await sdk.cash.deposit({
account: 1,
tokenAddress: '0x...',
amount: '1000000000000000000',
});
Withdraw a supported token from the account.
Name | Type | Description |
---|---|---|
params | WithdrawCashParams |
Token and amount info |
Promise<TransactionResponse>
await sdk.cash.withdraw({
account: 1,
tokenAddress: '0x...',
amount: '1000000000000000000',
});
Send supported tokens between accounts.
Name | Type | Description |
---|---|---|
params | SendTransactionParams |
Token, to/from, etc. |
Promise<TransactionResponse>
await sdk.cash.send({
fromAccount: 1,
toAccount: 2,
tokenAddress: '0x...',
amount: '1000000000000000000',
});
const tokens = await sdk.cash.getSupportedTokens();
type TokenWithPrice = Token & {
priceUSD: string;
};
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.
This project provides examples of how to:
-
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. - 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.
- Integrate ElevenLabs: Synthesize realistic speech from text using ElevenLabs' API, allowing for voice-based interactions and richer user experiences.
The code snippets provided in this README illustrate fetching data using tools defined for each service and then logging the results.
Before running this project, ensure you have the following:
- Node.js and npm (or yarn) installed: This project is likely built using JavaScript/TypeScript.
-
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
). -
Vercel AI SDK Installed: Ensure you have the
@vercel/ai
package installed in your project. -
Langchain Installed: Ensure you have the
langchain
and@langchain/openai
packages installed. -
Zod Installed: You're using
zod
for schema validation (z
). -
node-fetch
Installed: If you're making direct API calls, you'll neednode-fetch
.
-
Clone the repository (if applicable):
git clone <your-repository-url> cd <your-project-directory>
-
Install dependencies:
npm install # or yarn install
-
Set up environment variables: Create a
.env
file (or configure your environment variables through your hosting provider) and add your ElevenLabs API key:ELEVENLABS_API_KEY=your_elevenlabs_api_key
The provided code snippet demonstrates how to use each of the integrated services:
// /// ================ elevenLabsData =============
const elevenLabsData = await createElevenLabsTools({sdk})
const tools = castToToolRecord(elevenLabsData);
const elevenLabs_input_text = "Hello, please give me the balance of account 15!";
const elevenLabsData_result = await generateText({
model: openai("gpt-4o-mini"),
tools: tools,
maxSteps: 10,
prompt: elevenLabs_input_text,
});
console.log("elevenLabs data result text: ", elevenLabsData_result.text);
// /// ================ vercelAIData =============
const vercelAIData_text = "Hello, please give me the balance of account 15!";
const vercelAIData = await createVercelAITools({sdk})
const vercelAIData_result = await generateText({
model: openai("gpt-4o-mini"),
tools: castToToolRecord(vercelAIData),
maxSteps: 10, // Maximum number of tool invocations per request
prompt: vercelAIData_text,
});
console.log("vercelAIData Result text: ", vercelAIData_result.text);
## 🧱 Build from Source
// /// ================ langchainData =============
const langhchain_tools = createAgentTools(sdk)
const langchainData_text = "Fetch my cash balance account 12345";
const llm = new ChatOpenAI({
temperature: 0,
modelName: "gpt-4o-mini", // or "gpt-3.5-turbo", whatever you're using
});
const executor = await initializeAgentExecutorWithOptions(
langhchain_tools,
llm, // your model (OpenAI, Anthropic, etc)
{
agentType: "openai-functions",//"zero-shot-react-description",
verbose: true,
}
);
// now you can run
const res = await executor.call({ input: langchainData_text });
console.log("langchain result output: ", res.output);
npm install
npm run dev
npm run build
Contributions welcome! Open an issue or PR.
MIT © CaishenTech
Open an issue on GitHub or contact the maintainers.
Made with ❤️ by Caishen