langchain-near-account 0.1.0
LangChain tools for NEAR Protocol account management
Requires Python: >=3.9
Keywords: langchain near blockchain account management web3 cryptocurrency

# LangChain NEAR Account Manager

A comprehensive LangChain toolkit for NEAR Protocol account management operations. This package provides async-first tools for creating accounts, managing access keys, transferring NEAR tokens, and querying account information.

## Features

- **🔑 Account Creation** - Create new NEAR accounts with initial funding
- **💸 NEAR Transfer** - Send NEAR tokens to any account
- **🔐 Access Key Management** - Add/remove full access and function call keys
- **📊 Account Viewing** - Query account balances and metadata
- **🗝️ Key Listing** - List all access keys with permission details
- **⚡ Async Support** - Full async/await support for all operations
- **🤖 LangChain Native** - Proper BaseTool implementation with Pydantic schemas

## Installation

```bash
pip install langchain-near-account
```

Or install from source:

```bash
git clone https://github.com/near/langchain-near-account
cd langchain-near-account
pip install -e ".[dev]"
```

## Quick Start

### Basic Usage

```python
import asyncio
from langchain_near_account import NearAccountToolkit

async def main():
    # Initialize toolkit
    toolkit = NearAccountToolkit(
        account_id="your-account.testnet",
        private_key="ed25519:YOUR_PRIVATE_KEY",
        network="testnet"  # or "mainnet"
    )
    
    # Connect to NEAR
    await toolkit.connect()
    
    try:
        # Get all tools
        tools = toolkit.get_tools()
        
        # View account info
        view_tool = toolkit.get_tool("view_near_account")
        result = await view_tool.ainvoke({"account_id": "alice.testnet"})
        print(result)
        
    finally:
        await toolkit.disconnect()

asyncio.run(main())
```

### Using Context Manager

```python
async with NearAccountToolkit(
    account_id="your-account.testnet",
    private_key="ed25519:...",
) as toolkit:
    tools = toolkit.get_tools()
    # Use tools...
```

### With LangChain Agent

```python
from langchain_near_account import NearAccountToolkit
from langchain_openai import ChatOpenAI
from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate

async def create_near_agent():
    # Setup toolkit
    toolkit = NearAccountToolkit(
        account_id="your-account.testnet",
        private_key="ed25519:...",
    )
    await toolkit.connect()
    
    # Get tools
    tools = toolkit.get_tools()
    
    # Create prompt
    prompt = ChatPromptTemplate.from_messages([
        ("system", "You are a NEAR Protocol assistant. Help users manage their accounts."),
        ("human", "{input}"),
        ("placeholder", "{agent_scratchpad}"),
    ])
    
    # Create agent
    llm = ChatOpenAI(model="gpt-4", temperature=0)
    agent = create_openai_tools_agent(llm, tools, prompt)
    executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
    
    return executor, toolkit

# Use the agent
async def main():
    executor, toolkit = await create_near_agent()
    
    try:
        result = await executor.ainvoke({
            "input": "What's the balance of alice.testnet?"
        })
        print(result["output"])
    finally:
        await toolkit.disconnect()
```

## Available Tools

### create_near_account

Create a new NEAR account.

```python
result = await tool.ainvoke({
    "new_account_id": "myapp.your-account.testnet",
    "public_key": "ed25519:ABC123...",
    "initial_balance": 1.0  # NEAR
})
```

### fund_near_account

Transfer NEAR tokens to another account.

```python
result = await tool.ainvoke({
    "receiver_id": "recipient.testnet",
    "amount": 5.0  # NEAR
})
```

### add_near_access_key

Add an access key to your account.

```python
# Full access key
result = await tool.ainvoke({
    "public_key": "ed25519:...",
    "permission": "full_access"
})

# Function call key (restricted)
result = await tool.ainvoke({
    "public_key": "ed25519:...",
    "permission": "function_call",
    "contract_id": "contract.testnet",
    "method_names": ["deposit", "withdraw"],
    "allowance": 0.25  # NEAR for gas
})
```

### delete_near_access_key

Remove an access key from your account.

```python
result = await tool.ainvoke({
    "public_key": "ed25519:..."
})
```

⚠️ **Warning**: Removing all full access keys will permanently lock your account!

### view_near_account

Get account information.

```python
result = await tool.ainvoke({
    "account_id": "alice.testnet"  # Optional, defaults to connected account
})
```

Returns:
```json
{
    "success": true,
    "account_id": "alice.testnet",
    "amount": "1000000000000000000000000",
    "balance_near": 1.0,
    "locked": "0",
    "storage_usage": 100,
    "code_hash": "11111111111111111111111111111111"
}
```

### list_near_access_keys

List all access keys for an account.

```python
result = await tool.ainvoke({
    "account_id": "alice.testnet"  # Optional
})
```

Returns:
```json
{
    "success": true,
    "account_id": "alice.testnet",
    "total_keys": 2,
    "keys": [
        {
            "public_key": "ed25519:ABC...",
            "is_full_access": true,
            "nonce": 1
        },
        {
            "public_key": "ed25519:DEF...",
            "is_full_access": false,
            "nonce": 5
        }
    ]
}
```

## Using the Client Directly

For lower-level access, use `NearAccountClient`:

```python
from langchain_near_account import NearAccountClient

async with NearAccountClient(
    account_id="your-account.testnet",
    private_key="ed25519:...",
    network="testnet"
) as client:
    # View account
    info = await client.view_account("alice.testnet")
    print(f"Balance: {info.balance_near} NEAR")
    
    # List keys
    keys = await client.list_keys()
    for key in keys:
        print(f"{key.public_key}: {'Full' if key.is_full_access else 'Limited'}")
    
    # Transfer NEAR
    result = await client.fund_account("recipient.testnet", 1.0)
    print(f"Tx: {result.transaction_hash}")
```

## Configuration

### Networks

| Network | Description |
|---------|-------------|
| `testnet` | NEAR testnet (for development) |
| `mainnet` | NEAR mainnet (production) |
| Custom URL | Any NEAR RPC endpoint |

```python
# Testnet (default)
toolkit = NearAccountToolkit(account_id="...", private_key="...", network="testnet")

# Mainnet
toolkit = NearAccountToolkit(account_id="...", private_key="...", network="mainnet")

# Custom RPC
toolkit = NearAccountToolkit(
    account_id="...",
    private_key="...",
    network="https://custom-rpc.example.com"
)
```

### Key Formats

All keys use the `ed25519:` prefix format:

```
ed25519:4XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

To get your private key from NEAR CLI:
```bash
cat ~/.near-credentials/testnet/your-account.testnet.json
```

## Development

### Setup

```bash
# Clone repository
git clone https://github.com/near/langchain-near-account
cd langchain-near-account

# Install with dev dependencies
pip install -e ".[dev]"
```

### Running Tests

```bash
# Unit tests
pytest tests/test_tools.py -v

# Integration tests (requires NEAR credentials)
export NEAR_ACCOUNT_ID="your-account.testnet"
export NEAR_PRIVATE_KEY="ed25519:..."
pytest tests/test_integration.py -v -m integration

# All tests with coverage
pytest --cov=langchain_near_account --cov-report=html
```

### Code Quality

```bash
# Format code
black src tests
isort src tests

# Type checking
mypy src
```

## Error Handling

All tools return JSON with a `success` field:

```python
result = await tool.ainvoke({"account_id": "nonexistent.testnet"})
data = json.loads(result)

if data["success"]:
    print(f"Balance: {data['balance_near']} NEAR")
else:
    print(f"Error: {data['error']}")
```

Common errors:
- `Account does not exist` - The specified account doesn't exist
- `Insufficient balance` - Not enough NEAR for the operation
- `Access key not found` - The key being deleted doesn't exist
- `Client not connected` - Forgot to call `connect()` or use context manager

## Security Considerations

1. **Never commit private keys** - Use environment variables or secure vaults
2. **Full access keys are dangerous** - Prefer function call keys when possible
3. **Don't remove all full access keys** - You'll permanently lose account access
4. **Test on testnet first** - Always validate operations before mainnet

## License

MIT License - see [LICENSE](LICENSE) for details.

## Contributing

Contributions welcome! Please read our contributing guidelines and submit PRs.

## Links

- [NEAR Protocol Documentation](https://docs.near.org)
- [LangChain Documentation](https://python.langchain.com)
- [py-near Library](https://github.com/pvolnov/py-near)