UNPKG

@osiris-ai/web3-evm-sdk

Version:
375 lines (305 loc) 11.2 kB
# @osiris-ai/web3-evm-sdk EVM wallet client for building Web3 MCPs with secure blockchain operations and policy enforcement. [![npm version](https://badge.fury.io/js/@osiris-ai%2Fweb3-evm-sdk.svg)](https://badge.fury.io/js/@osiris-ai%2Fweb3-evm-sdk) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ## Overview The EVM SDK provides secure blockchain wallet operations for the [Osiris](https://docs.osirislabs.xyz) 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 ```bash npm install @osiris-ai/web3-evm-sdk @osiris-ai/sdk viem ``` ## Quick Start ### Wallet Operations ```typescript 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. ```typescript class EVMWalletClient ``` #### Constructor ```typescript 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 ```typescript 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 ```typescript 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: ```typescript // 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 ```typescript 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 1. **Install the Osiris CLI:** ```bash npm install -g @osiris-ai/cli ``` 2. **Set up authentication:** ```bash npx @osiris-ai/cli register npx @osiris-ai/cli create-client npx @osiris-ai/cli connect-auth ``` 3. **Create your Web3 MCP:** ```bash npx @osiris-ai/cli create-mcp my-web3-mcp ``` 4. **Add Web3 integration:** ```bash npm install @osiris-ai/web3-evm-sdk viem ``` ## Contributing We welcome contributions! Please see our [Contributing Guide](https://github.com/osiris-labs/osiris/blob/main/CONTRIBUTING.md) for details. ## Support - **Documentation:** [https://docs.osirislabs.xyz](https://docs.osirislabs.xyz) - **GitHub Issues:** [https://github.com/fetcchx/osiris-ai/issues](https://github.com/fetcchx/osiris-ai/issues) - **Discord Community:** [Join our Discord](https://discord.osirislabs.xyz) ## License MIT License - see [LICENSE](LICENSE) file for details. --- Built with ❤️ by the [Osiris Labs](https://osirislabs.xyz) team.