# Ca Agent Skills

> Portkey CA wallet skill for registration, recovery, guardian flows, transfers, and contract calls on aelf.

- **Type:** MCP server
- **Install:** `agentstack add mcp-portkey-wallet-ca-agent-skills`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Portkey-Wallet](https://agentstack.voostack.com/s/portkey-wallet)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Portkey-Wallet](https://github.com/Portkey-Wallet)
- **Source:** https://github.com/Portkey-Wallet/ca-agent-skills

## Install

```sh
agentstack add mcp-portkey-wallet-ca-agent-skills
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Portkey CA Agent Skills

> AI Agent toolkit for [Portkey Wallet](https://portkey.finance) on the [aelf](https://aelf.com) blockchain — Email registration, login, transfers, guardian management, and generic contract calls.

[中文文档](./README.zh-CN.md)
[](https://github.com/Portkey-Wallet/ca-agent-skills/actions/workflows/test.yml)
[](https://Portkey-Wallet.github.io/ca-agent-skills/coverage.json)

## Architecture

```
ca-agent-skills/
├── index.ts                    # SDK entry — direct import for LangChain / LlamaIndex
├── src/
│   ├── core/                   # Pure business logic (no I/O side effects)
│   │   ├── account.ts          # checkAccount, getGuardianList, getHolderInfo, getChainInfo
│   │   ├── auth.ts             # sendVerificationCode, verifyCode, registerWallet, recoverWallet
│   │   ├── assets.ts           # getTokenBalance, getTokenList, getNftCollections, getNftItems, getTokenPrice
│   │   ├── transfer.ts         # sameChainTransfer, crossChainTransfer, recoverStuckTransfer
│   │   ├── guardian.ts         # addGuardian, removeGuardian
│   │   ├── contract.ts         # managerForwardCall, callContractViewMethod
│   │   └── keystore.ts         # Encrypted wallet persistence (save, unlock, lock)
│   └── mcp/
│       └── server.ts           # MCP adapter — for Claude Desktop, Cursor, GPT, etc.
├── portkey_query_skill.ts      # CLI adapter — query commands
├── portkey_auth_skill.ts       # CLI adapter — registration & login commands
├── portkey_tx_skill.ts         # CLI adapter — transfer & guardian commands
├── cli-helpers.ts              # CLI output helpers
├── bin/
│   └── setup.ts                # One-command setup for AI platforms
├── lib/
│   ├── config.ts               # Network config, env overrides
│   ├── types.ts                # TypeScript interfaces & enums
│   ├── aelf-client.ts          # aelf-sdk wrapper (wallet, contract, signing)
│   └── http.ts                 # HTTP client for Portkey backend API
└── __tests__/                  # Unit / Integration / E2E tests
```

**Core + Adapters pattern:** Three adapters (MCP, CLI, SDK) call the same Core functions — zero duplicated logic.

## Features

| # | Category | Capability | MCP Tool | CLI Command | SDK Function |
|---|----------|-----------|----------|-------------|--------------|
| 1 | Account | Check email registration | `portkey_check_account` | `check-account` | `checkAccount` |
| 2 | Account | Get guardian list | `portkey_get_guardian_list` | `guardian-list` | `getGuardianList` |
| 3 | Account | Get CA holder info | `portkey_get_holder_info` | `holder-info` | `getHolderInfo` |
| 4 | Account | Get chain info | `portkey_get_chain_info` | `chain-info` | `getChainInfo` |
| 5 | Auth | Get verifier server | `portkey_get_verifier` | `get-verifier` | `getVerifierServer` |
| 6 | Auth | Send verification code | `portkey_send_code` | `send-code` | `sendVerificationCode` |
| 7 | Auth | Verify code | `portkey_verify_code` | `verify-code` | `verifyCode` |
| 8 | Auth | Register wallet | `portkey_register` | `register` | `registerWallet` |
| 9 | Auth | Recover wallet (login) | `portkey_recover` | `recover` | `recoverWallet` |
| 10 | Auth | Check status | `portkey_check_status` | `check-status` | `checkRegisterOrRecoveryStatus` |
| 11 | Assets | Token balance | `portkey_balance` | `balance` | `getTokenBalance` |
| 12 | Assets | Token list | `portkey_token_list` | `token-list` | `getTokenList` |
| 13 | Assets | NFT collections | `portkey_nft_collections` | `nft-collections` | `getNftCollections` |
| 14 | Assets | NFT items | `portkey_nft_items` | `nft-items` | `getNftItems` |
| 15 | Assets | Token price | `portkey_token_price` | `token-price` | `getTokenPrice` |
| 16 | Transfer | Same-chain transfer | `portkey_transfer` | `transfer` | `sameChainTransfer` |
| 17 | Transfer | Cross-chain transfer | `portkey_cross_chain_transfer` | `cross-chain-transfer` | `crossChainTransfer` |
| 18 | Transfer | Transaction result | `portkey_tx_result` | `tx-result` | `getTransactionResult` |
| 19 | Transfer | Recover stuck transfer | `portkey_recover_stuck_transfer` | `recover-stuck-transfer` | `recoverStuckTransfer` |
| 20 | Guardian | Add guardian | `portkey_add_guardian` | `add-guardian` | `addGuardian` |
| 21 | Guardian | Remove guardian | `portkey_remove_guardian` | `remove-guardian` | `removeGuardian` |
| 22 | Contract | ManagerForwardCall | `portkey_forward_call` | `forward-call` | `managerForwardCall` |
| 23 | Contract | View method call | `portkey_view_call` | `view-call` | `callContractViewMethod` |
| 24 | Wallet | Create wallet | `portkey_create_wallet` | `create-wallet` | `createWallet` |
| 25 | Wallet | Save keystore | `portkey_save_keystore` | `save-keystore` | `saveKeystore` |
| 26 | Wallet | Unlock wallet | `portkey_unlock` | `unlock` | `unlockWallet` |
| 27 | Wallet | Lock wallet | `portkey_lock` | `lock` | `lockWallet` |
| 28 | Wallet | Wallet status | `portkey_wallet_status` | `wallet-status` | `getWalletStatus` |
| 29 | Wallet | Get active wallet context | `portkey_get_active_wallet` | — | `getActiveWallet` |
| 30 | Wallet | Set active wallet context | `portkey_set_active_wallet` | — | `setActiveWallet` |
| 31 | Wallet | Manager sync status | `portkey_manager_sync_status` | `manager-sync-status` | `checkManagerSyncState` |

## Contract Call Routing

Choose the contract tool by method type, not just by wallet type.

- `forward-call` / `managerForwardCall` are for state-changing methods only.
- `view-call` / `callContractViewMethod` are for `Get*` and other read-only methods.
- For `Empty`-input view methods such as `GetConfig`, omit `--params` entirely so the tool performs `.call()` with no arguments.
- If a read-only method is routed through `forward-call`, the result is a `CA.ManagerForwardCall` receipt, not the inner method's decoded view return payload.
- `VirtualTransactionCreated` is expected on successful forwarded writes. It proves that the CA contract created the inner call, but it is not the decoded return value and not a standalone proof of final business success.

Resonance examples:

```bash
# Read-only queue status lookup
bun run portkey_query_skill.ts view-call \
  --rpc-url https://tdvv-public-node.aelf.io \
  --contract-address 28Lot71VrWm1WxrEjuDqaepywi7gYyZwHysUcztjkHGFsPPrZy \
  --method-name GetPairQueueStatus \
  --params '""'

# State-changing queue join
bun run portkey_tx_skill.ts forward-call \
  --login-email "user@example.com" \
  --password "your-password" \
  --ca-hash "" \
  --contract-address 28Lot71VrWm1WxrEjuDqaepywi7gYyZwHysUcztjkHGFsPPrZy \
  --method-name JoinPairQueue \
  --args '{}' \
  --chain-id tDVV
```

## Wallet Persistence (Keystore)

Manager private keys are encrypted and stored locally using aelf-sdk's keystore scheme (scrypt + AES-128-CTR).

**Storage location:** `~/.portkey/ca/{network}.keystore.json`

### First-time setup (after registration/recovery)

```bash
# AI flow: create_wallet → register → check_status → save_keystore(password)
# The wallet is auto-unlocked after saving.
```

### New conversation

```bash
# AI calls portkey_wallet_status to check the active or targeted keystore
# For profile keystores, pass --login-email (or use the active CA profile from a prior save/recover)
# If locked, ask for password → portkey_unlock(password)
# If the password was forgotten, switch to recover-and-save with fresh guardian verification codes
# Write operations in the same process now work automatically
```

### Manual CLI usage

```bash
# Save keystore
bun run portkey_auth_skill.ts save-keystore \
  --password "your-password" \
  --private-key "hex-key" \
  --mnemonic "word1 word2 ..." \
  --ca-hash "xxx" --ca-address "ELF_xxx_tDVV" \
  --origin-chain-id "tDVV"

# Unlock
bun run portkey_auth_skill.ts unlock --password "your-password"

# Or target a specific profile/keystore file
bun run portkey_auth_skill.ts unlock --password "your-password" --login-email "user@example.com"

# If the password was forgotten, re-login / recover and save a new reusable keystore
bun run portkey_auth_skill.ts recover-and-save \
  --email "user@example.com" \
  --guardians-approved '[...]' \
  --chain-id AELF \
  --password "new-password"

# Check status
bun run portkey_auth_skill.ts wallet-status

# Lock
bun run portkey_auth_skill.ts lock
```

### How it works

1. **Save** — encrypts the Manager private key + mnemonic with a user-provided password, writes to `~/.portkey/ca/`
2. **Unlock** — decrypts the keystore, loads the wallet into memory for the current process
3. **Lock** — clears the private key from memory
4. **Write operations** — automatically use the unlocked wallet for the current process; falls back to `PORTKEY_PRIVATE_KEY` env var if no keystore is unlocked

### Recommended CA transfer path

```bash
# 1. recover -> save reusable keystore
bun run portkey_auth_skill.ts recover-and-save \
  --email "user@example.com" \
  --guardians-approved '[...]' \
  --chain-id AELF \
  --password "your-password"

# 2. poll manager sync on the target chain
bun run portkey_query_skill.ts manager-sync-status \
  --ca-hash "" \
  --chain-id tDVV \
  --manager-address ""

# 3. collect fresh transferApprove proofs
# 4. transfer using the saved keystore directly in the tx command
bun run portkey_tx_skill.ts transfer \
  --login-email "user@example.com" \
  --password "your-password" \
  --ca-hash "" \
  --token-contract "" \
  --symbol ELF \
  --to "" \
  --amount 101000000 \
  --chain-id tDVV \
  --guardians-approved '[...]'
```

Notes:

- CA write commands can now resolve signer directly from `--login-email` + `--password`, so they no longer depend on a previous `unlock` from another CLI process.
- Same-chain and cross-chain transfers now check whether the current manager is already synced to the target chain before sending any transaction.
- Generic `forward-call` now performs the same manager sync precheck before fee preview or transaction send.
- `wallet-status` returns `recommendedAction` and `userHint` when a local keystore exists but is still locked. `recommendedAction` is the machine-routable next step (`unlock`), while `userHint` carries the fallback guidance for wrong profile selection or forgotten passwords.
- Transfer results include a fee preview when the chain can calculate it, including `chargingAddress` and whether the CA appears to be paying the fee.

## Cross-skill signing

- `portkey_save_keystore` and `portkey_unlock` automatically update shared active wallet context.
- Other write-capable skills can resolve signer by `explicit -> active context -> env` (auto mode).
- Shared context stores pointers only (no plaintext private key).

## Prerequisites

- [Bun](https://bun.sh) >= 1.0
- An aelf wallet private key or an unlocked keystore (for write operations only)

## Quick Start

### 1. Install

```bash
bun add @portkey/ca-agent-skills

# Or clone locally
git clone https://github.com/AwakenFinance/ca-agent-skills.git
cd ca-agent-skills
bun install
```

### 2. Configure

```bash
cp .env.example .env
# Edit .env — add your PORTKEY_PRIVATE_KEY (only for write operations)
```

### 3. One-Command Setup

```bash
# Claude Desktop
bun run bin/setup.ts claude

# Cursor (project-level)
bun run bin/setup.ts cursor

# Cursor (global)
bun run bin/setup.ts cursor --global

# OpenClaw — output config to stdout
bun run bin/setup.ts openclaw

# OpenClaw — merge into existing config
bun run bin/setup.ts openclaw --config-path ./my-openclaw.json

# IronClaw — install trusted skill + stdio MCP server
bun run bin/setup.ts ironclaw

# Check status (Claude, Cursor, OpenClaw, IronClaw)
bun run bin/setup.ts list

# Remove
bun run bin/setup.ts uninstall claude
bun run bin/setup.ts uninstall cursor
bun run bin/setup.ts uninstall openclaw --config-path ./my-openclaw.json
bun run bin/setup.ts uninstall ironclaw
```

### IronClaw

```bash
# Install trusted skill + stdio MCP server
bun run bin/setup.ts ironclaw

# Remove IronClaw integration
bun run bin/setup.ts uninstall ironclaw
```

The IronClaw setup does two things by default:

- Writes a stdio MCP server entry to `~/.ironclaw/mcp-servers.json`
- Copies this repo's `SKILL.md` to `~/.ironclaw/skills/portkey-ca-agent-skills/SKILL.md`

Important trust model note:

- Use the trusted skill path above for write-capable CA wallet operations.
- Do **not** rely on `~/.ironclaw/installed_skills/` for this package if you need registration, recovery, transfer, guardian management, or other write actions.
- IronClaw attenuates installed skills to read-only tools, which can make the agent appear to "query only" even though the MCP server is available.

The MCP server exposes destructive annotations for CA write operations so IronClaw can request approval before registration, recovery, transfer, guardian, and contract calls.
For compatibility, the MCP server currently emits both standard MCP camelCase annotations and IronClaw-compatible snake_case annotations because the current IronClaw source parses snake_case fields for MCP approval hints.

Remote activation contract:

- GitHub repo/tree URLs are discovery sources only, not the final IronClaw install payload.
- Preferred IronClaw activation from npm: `bunx -p @portkey/ca-agent-skills portkey-ca-setup ironclaw`
- Prefer ClawHub / managed install for OpenClaw when available; otherwise use `bunx -p @portkey/ca-agent-skills portkey-ca-setup openclaw`
- Local repo checkout remains a development smoke-test path only.
- Migration note: `portkey-setup` was removed in `2.0.0`; switch npm-based activation to `portkey-ca-setup`.

## Usage

### MCP (Claude Desktop / Cursor)

Add to your MCP config (`mcp-config.example.json`):

```json
{
  "mcpServers": {
    "ca-agent-skills": {
      "command": "bun",
      "args": ["run", "/path/to/ca-agent-skills/src/mcp/server.ts"],
      "env": {
        "PORTKEY_PRIVATE_KEY": "your_private_key_here",
        "PORTKEY_NETWORK": "mainnet"
      }
    }
  }
}
```

### OpenClaw

The `openclaw.json` in the project root defines 13 CLI-based tools for OpenClaw. Use `bun run bin/setup.ts openclaw` to generate or merge the config.

### CLI

```bash
# Check if email is registered
bun run portkey_query_skill.ts check-account --email user@example.com

# Get chain info
bun run portkey_query_skill.ts chain-info

# Create wallet
bun run portkey_auth_skill.ts create-wallet

# Resolve the correct flow + chain first
bun run portkey_query_skill.ts prepare-auth-flow --email user@example.com

# Low-level auth tools require explicit chainId from prepare-auth-flow.resolvedChainId
bun run portkey_auth_skill.ts get-verifier --chain-id 
bun run portkey_auth_skill.ts send-code --email user@example.com --verifier-id  --operation recovery --chain-id 
bun run portkey_auth_skill.ts verify-code --email user@example.com --code 123456 --verifier-id  --session-id  --operation recovery --chain-id 

# Token list strategy: aa | auto | eoa (default: auto)
bun run portkey_query_skill.ts token-list --ca-address-infos '[{"chainId":"tDVV","caAddress":"xxx"}]' --strategy auto

# Transfer tokens (requires PORTKEY_PRIVATE_KEY env)
bun run portkey_tx_skill.ts transfer --ca-hash xxx --token-contract xxx --symbol ELF --to xxx --amount 100000000 --chain-id tDVV
```

Recovery proof validation:
- `recover` now validates each guardian proof locally before submitting.
- Guardian `verificationDoc` must come from `verify-code` with `--operation recovery`; register proofs are rejected.

### SDK

```typescript
import { getConfig, checkAccount, createWallet, getTokenBalance } from '@portkey/ca-agent-skills';

const config = getConfig({ network: 'mainnet' });

// Check account
const account = await checkAccount(config, { email: 'user@example.com' });

// Create wallet
const wallet = createWallet();

// Get balance
const balance = await getTokenBalance(config, {
  caAddress: 'xxx',
  chainId: 'tDVV',
  symbol: 'ELF',
});
```

## Network

| Network | Chain IDs | AA API URL | EOA API URL |
|---------|-----------|------------|-------------|
| mainnet (default) | AELF,

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Portkey-Wallet](https://github.com/Portkey-Wallet)
- **Source:** [Portkey-Wallet/ca-agent-skills](https://github.com/Portkey-Wallet/ca-agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-portkey-wallet-ca-agent-skills
- Seller: https://agentstack.voostack.com/s/portkey-wallet
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
