@osiris-ai/web3-evm-sdk
v0.1.1
Published
Osiris Web3 EVM SDK
Readme
@osiris-ai/web3-evm-sdk
EVM wallet client for building Web3 MCPs with secure blockchain operations and policy enforcement.
Overview
The EVM SDK provides secure blockchain wallet operations for the Osiris ecosystem. Build powerful Web3 MCPs that can interact with Ethereum and EVM-compatible chains with enterprise-grade security, policy enforcement, and zero-configuration wallet management.
Key Features:
- 🔐 Policy Enforcement - User-defined transaction policies automatically validated
- 💼 Embedded Wallets - Turnkey-powered enterprise wallet infrastructure
- ⛓️ Multi-Chain Support - Ethereum, Polygon, BSC, and other EVM chains
- 📝 Viem Integration - Full compatibility with viem for Web3 operations
- 🛡️ Enterprise Security - Hardware-backed signing with HSM support
- 📝 Full TypeScript - Complete type safety and IDE support
Installation
npm install @osiris-ai/web3-evm-sdk @osiris-ai/sdk viemQuick Start
Wallet Operations
import { createMcpServer, getAuthContext } from '@osiris-ai/sdk';
import { EVMWalletClient } from '@osiris-ai/web3-evm-sdk';
import { createSuccessResponse, createErrorResponse } from '../utils/types.js';
import { z } from 'zod';
await createMcpServer({
name: 'web3-mcp',
version: '1.0.0',
auth: {
useHub: true,
hubConfig: {
baseUrl: process.env.HUB_BASE_URL!,
clientId: process.env.OAUTH_CLIENT_ID!,
clientSecret: process.env.OAUTH_CLIENT_SECRET!,
}
},
configure: (server) => {
// Get user wallet addresses
server.tool(
'get_wallet_addresses',
'Get available wallet addresses',
{},
async () => {
try {
const { token, context } = getAuthContext("osiris");
if (!token || !context) {
return createErrorResponse("User not authenticated");
}
const walletClient = new EVMWalletClient(
process.env.HUB_BASE_URL!,
token.access_token,
context.deploymentId
);
const walletRecords = await walletClient.getWalletRecords();
const addresses = walletRecords.map(record =>
record.accounts.addresses.map(addr => ({
address: addr.address,
chains: addr.chains
}))
).flat();
return createSuccessResponse('Wallet addresses retrieved', { addresses });
} catch (error) {
return createErrorResponse(error);
}
}
);
// Sign message
server.tool(
'sign_message',
'Sign a message with user wallet',
{
message: z.string(),
address: z.string(),
chainId: z.string().default('evm:eip155:1')
},
async ({ message, address, chainId }) => {
try {
const { token, context } = getAuthContext("osiris");
if (!token || !context) {
return createErrorResponse("User not authenticated");
}
const walletClient = new EVMWalletClient(
process.env.HUB_BASE_URL!,
token.access_token,
context.deploymentId
);
const signature = await walletClient.signMessage(message, chainId, address);
return createSuccessResponse('Message signed successfully', { signature });
} catch (error) {
return createErrorResponse(error);
}
}
);
}
});API Reference
EVMWalletClient
Main wallet client for EVM blockchain operations.
class EVMWalletClientConstructor
new EVMWalletClient(hubBaseUrl: string, accessToken: string, deploymentId: string)Methods
getWalletRecords(): Promise<Wallet[]>
Get user's available wallet records with addresses and supported chains.
signMessage(message: string, chainId: string, walletAddress: string): Promise<string>
Sign a message with the specified wallet address.
signTransaction(abi: any, transaction: any, chainId: string, walletAddress: string): Promise<string>
Sign a transaction with automatic policy validation.
signTypedData(typedData: any, chainId: string, walletAddress: string, metadata?: any): Promise<string>
Sign typed data (EIP-712) for smart contract interactions.
getViemAccount(address: string, chainId: string): Promise<Account>
Get a viem-compatible account for use with viem client operations.
Usage Examples
Token Transfer
server.tool(
'transfer_tokens',
'Transfer tokens to another address',
{
to: z.string(),
amount: z.string(),
tokenAddress: z.string().optional(),
walletAddress: z.string()
},
async ({ to, amount, tokenAddress, walletAddress }) => {
const { token, context } = getAuthContext("osiris");
if (!token || !context) {
return createErrorResponse("User not authenticated");
}
const walletClient = new EVMWalletClient(
process.env.HUB_BASE_URL!,
token.access_token,
context.deploymentId
);
try {
// Get viem account for transaction
const account = await walletClient.getViemAccount(walletAddress, 'evm:eip155:1');
// Build transaction (simplified)
const transaction = {
to: to as `0x${string}`,
value: BigInt(amount),
// Add gas estimation and other transaction fields
};
// Sign transaction (policy validation happens automatically)
const signedTx = await walletClient.signTransaction(
[], // ERC20 ABI needed
transaction,
'evm:eip155:1',
walletAddress
);
return createSuccessResponse('Transaction signed', { signedTransaction: signedTx });
} catch (error) {
if (error.message.includes('policy')) {
return createErrorResponse(`Transaction blocked by wallet policy: ${error.message}`);
}
return createErrorResponse(`Transfer failed: ${error.message}`);
}
}
);Smart Contract Interaction
server.tool(
'interact_with_contract',
'Interact with a smart contract',
{
contractAddress: z.string(),
functionName: z.string(),
args: z.array(z.any()),
walletAddress: z.string()
},
async ({ contractAddress, functionName, args, walletAddress }) => {
const { token, context } = getAuthContext("osiris");
if (!token || !context) {
return createErrorResponse("User not authenticated");
}
const walletClient = new EVMWalletClient(
process.env.HUB_BASE_URL!,
token.access_token,
context.deploymentId
);
try {
// Example: ERC-20 transfer
const typedData = {
domain: {
name: 'Token Contract',
version: '1',
chainId: 1,
verifyingContract: contractAddress
},
types: {
Transfer: [
{ name: 'to', type: 'address' },
{ name: 'amount', type: 'uint256' }
]
},
message: {
to: args[0],
amount: args[1]
}
};
const signature = await walletClient.signTypedData(
typedData,
'evm:eip155:1',
walletAddress
);
return createSuccessResponse('Contract interaction signed', { signature });
} catch (error) {
return createErrorResponse(`Contract interaction failed: ${error.message}`);
}
}
);Policy Enforcement
All wallet operations are automatically validated against user-defined policies:
// Users set policies in their wallet settings:
// - Maximum transaction amount
// - Allowed recipient addresses
// - Smart contract interaction rules
// - Time-based restrictions
// - Multi-signature requirements
// Example policy validation scenarios:
server.tool('policy_aware_transfer', 'Transfer with policy validation', schema, async (params) => {
try {
// Transaction is automatically validated against:
// 1. Amount limits (e.g., max $1000 per transaction)
// 2. Recipient whitelist (only approved addresses)
// 3. Time restrictions (e.g., no transfers on weekends)
// 4. Velocity limits (e.g., max $5000 per day)
const result = await walletClient.signTransaction(/* transaction */);
return createSuccessResponse('Transaction approved by policies', result);
} catch (error) {
if (error.message.includes('amount exceeds limit')) {
return createErrorResponse('🚫 Transaction amount exceeds your daily limit');
}
if (error.message.includes('recipient not approved')) {
return createErrorResponse('🚫 Recipient address not in your approved list');
}
return createErrorResponse(`Policy violation: ${error.message}`);
}
});Error Handling
server.tool('robust_wallet_tool', 'Wallet tool with error handling', schema, async (params) => {
try {
const { token, context } = getAuthContext("osiris");
if (!token || !context) {
return createErrorResponse("🔐 Please connect your wallet first");
}
const walletClient = new EVMWalletClient(
process.env.HUB_BASE_URL!,
token.access_token,
context.deploymentId
);
const walletRecords = await walletClient.getWalletRecords();
return createSuccessResponse('Wallet data retrieved', walletRecords);
} catch (error: any) {
if (error.message.includes('No wallet record found')) {
return createErrorResponse("❌ No wallet found. Please create a wallet first.");
}
if (error.message.includes('policy')) {
return createErrorResponse(`🚫 Operation blocked: ${error.message}`);
}
if (error.message.includes('insufficient funds')) {
return createErrorResponse("💰 Insufficient funds for this transaction.");
}
return createErrorResponse(`Wallet error: ${error.message}`);
}
});Getting Started
Install the Osiris CLI:
npm install -g @osiris-ai/cliSet up authentication:
npx @osiris-ai/cli register npx @osiris-ai/cli create-client npx @osiris-ai/cli connect-authCreate your Web3 MCP:
npx @osiris-ai/cli create-mcp my-web3-mcpAdd Web3 integration:
npm install @osiris-ai/web3-evm-sdk viem
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Support
- Documentation: https://docs.osirislabs.xyz
- GitHub Issues: https://github.com/fetcchx/osiris-ai/issues
- Discord Community: Join our Discord
License
MIT License - see LICENSE file for details.
Built with ❤️ by the Osiris Labs team.
