npm package: @osiris-ai/web3-evm-sdk
Description: Osiris Web3 EVM SDK
Latest version: 0.1.1

# @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.