# Multichain Protocol

> Turn any AI agent into a 19-chain crypto wallet via MeneseSDK on ICP. Send tokens, swap on DEXes (Raydium, Uniswap, ICPSwap, KongSwap, Cetus, Minswap), bridge cross-chain, manage DeFi positions (Aave, Lido, LP), automate trading (DCA, stop-loss, rebalancing), and process payments — all from a single ICP canister.

- Skill: `johnalbertini14-glitch/multichain-protocol` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add johnalbertini14-glitch/multichain-protocol`
- Raw SKILL.md: https://api.skillmd.com/api/skills/johnalbertini14-glitch/multichain-protocol/raw
- Safety review: pending (external: skill-scanner PASS, skillspector WARNING)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: johnalbertini14-glitch (https://skillmd.com/u/johnalbertini14-glitch)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/johnalbertini14-glitch/multichain-protocol

---


# Multichain Protocol — MeneseSDK Wallet Skill

Operate across **19 blockchains** from a single ICP canister or CLI: Solana, Ethereum, Bitcoin, Arbitrum, Base, Polygon, BSC, Optimism, ICP, XRP, SUI, TON, Cardano, Aptos, NEAR, Tron, Litecoin, CloakCoin, THORChain.

**Powered by Menese Protocol** | **Canister ID (mainnet):** `urs2a-ziaaa-aaaad-aembq-cai`

---

## Pricing

**First 5 transactions are FREE** — no signup, no credit card, just install and go.

After the free tier, transaction signing is charged per action via your DeveloperKey (`msk_*`). Read-only operations (balances, addresses, pool queries) are always free.

---

## Quickstart (2 minutes)

### Step 1: Install dfx (ICP SDK)

If you don't have `dfx` installed, run this single command:

```bash
sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
```

Verify it works:
```bash
dfx --version
```

That's it. No accounts needed, no wallets to set up — dfx handles everything.

### Step 2: Install the skill

```bash
clawhub install multichain-protocol
```

Or manually: copy `SKILL.md` + `wallet_commands.py` to your workspace.

### Step 3: Create an ICP identity (if you don't have one)

```bash
dfx identity new my-wallet
dfx identity use my-wallet
```

### Step 4: Try it — your first 5 sends are free

Ask your bot:
```
"show my wallet addresses"
"what's my SOL balance?"
"send 0.1 ETH to 0xABC..."
"swap 100 USDC to SOL on Raydium"
"set up a DCA: buy $50 of BTC every day"
```

### Step 5 (optional): Deploy your own canister for production

For multi-user, automation, and timers — deploy `WalletBot.mo` as your own ICP canister.

---

## Two Integration Approaches

| | Canister (Recommended) | CLI (Quick) |
|---|---|---|
| **Flow** | User → ClawdBot → Your Canister → MeneseSDK | User → ClawdBot → `dfx canister call` → MeneseSDK |
| **Setup** | Deploy `WalletBot.mo`, register with SDK | Copy `scripts/wallet_commands.py`, done |
| **Best for** | Multi-user, automation, timers, production | Single-user, prototyping, testing |
| **Automation** | ICP timers for DCA/rebalance/bots | None (manual only) |

---

## Best Practice: Cache Addresses

Addresses are **deterministic** — the same principal always gets the same addresses on every chain. Fetch once, cache forever.

```motoko
// Canister pattern — cache in stable var
stable var cachedAddresses : ?AddressBook = null;

public shared func getAddresses() : async AddressBook {
  switch (cachedAddresses) {
    case (?addrs) { addrs };  // Return cached — no inter-canister call
    case null {
      let sol = await menese.getMySolanaAddress();
      let evm = await menese.getMyEvmAddress();
      // ... fetch all chains once ...
      let addrs = { solana = sol.address; evm = evm.evmAddress; /* ... */ };
      cachedAddresses := ?addrs;
      addrs;
    };
  };
};
```

```python
# CLI pattern — fetch once, store in file
import json, os
CACHE_FILE = "addresses_cache.json"

def get_addresses():
    if os.path.exists(CACHE_FILE):
        return json.load(open(CACHE_FILE))
    addrs = fetch_all_addresses()  # dfx calls
    json.dump(addrs, open(CACHE_FILE, "w"))
    return addrs
```

**Why**: Saves inter-canister call latency + cycles. Addresses never change for a given principal.

---

## EVM Chains — Bring Your Own RPC

All EVM operations (ETH, Arbitrum, Base, Polygon, BSC, Optimism) require **your own RPC endpoint**. MeneseSDK does not manage EVM RPCs.

| Chain | Chain ID | Free Public RPC |
|-------|----------|----------------|
| Ethereum | 1 | `https://eth.llamarpc.com` |
| Arbitrum | 42161 | `https://arb1.arbitrum.io/rpc` |
| Base | 8453 | `https://mainnet.base.org` |
| Polygon | 137 | `https://polygon-rpc.com` |
| BSC | 56 | `https://bsc-dataseed1.binance.org` |
| Optimism | 10 | `https://mainnet.optimism.io` |

Use Alchemy/Infura for production reliability.

---

## Complete Tool Reference

Every operation available, organized by category. Each tool shows the function, parameters, return type, cost, and a usage example.

### Tool 1: Get Addresses (FREE)

Deterministic per-principal. **Cache after first call.**

| Chain | Function | Field to Extract |
|-------|----------|-----------------|
| Solana | `getMySolanaAddress` | `.address` |
| EVM (all 6) | `getMyEvmAddress` | `.evmAddress` (NOT `.address`) |
| Bitcoin | `getMyBitcoinAddress` | `.bech32Address` |
| Litecoin | `getMyLitecoinAddress` | `.bech32Address` |
| SUI | `getMySuiAddress` | `.suiAddress` (NOT `.address`) |
| XRP | `getMyXrpAddress` | `.classicAddress` |
| TON | `getMyTonAddress` | `.nonBounceable` (NOT `.address`) |
| Cardano | `getMyCardanoAddress` | `.bech32Address` |
| Aptos | `getMyAptosAddress` | `.address` |
| NEAR | `getMyNearAddress` | `.implicitAccountId` (NOT `.accountId`) |
| Tron | `getTronAddress` | `.base58Address` (NOT `.base58`) |
| CloakCoin | `getMyCloakAddress` | `.base58Address` |
| THORChain | `getMyThorAddress` | `.bech32Address` |

**Batch**: `getAllAddresses()` — all chains in one call.
**Solana ATA**: `getMySolanaAta(mintBase58)` — get associated token account for an SPL token.

```motoko
// Example: get SOL address
let info = await menese.getMySolanaAddress();
let myAddress = info.address;  // "5xK2abc..."
```

```bash
# CLI
dfx canister call urs2a-ziaaa-aaaad-aembq-cai getMySolanaAddress --network ic --query
```

### Tool 2: Check Balances (FREE)

| Chain | Function | Returns | Unit |
|-------|----------|---------|------|
| Solana | `getMySolanaBalance` | `Result<Nat64, Text>` | lamports (÷10^9) |
| ICP | `getICPBalance` | `Result<Nat64, Text>` | e8s (÷10^8) |
| ICP (for addr) | `getICPBalanceFor(principal)` | `Result<Nat64, Text>` | e8s (÷10^8) |
| Bitcoin | `getBitcoinBalance` | `Nat64` | satoshis (÷10^8) |
| Litecoin | `getLitecoinBalance` | `Nat64` | litoshis (÷10^8) |
| EVM | `getMyEvmBalance(rpcUrl)` | `Result<Nat, Text>` | wei (÷10^18) |
| XRP | `getMyXrpBalance` | `Result<Text, Text>` | drops as text |
| SUI | `getMySuiBalance` | `Nat64` | mist (÷10^9) |
| TON | `getMyTonBalance` | `Result<Nat64, Text>` | nanotons (÷10^9) |
| Cardano | `getCardanoBalance` | `Result<Nat64, Text>` | lovelace (÷10^6) |
| Aptos | `getAptosBalance` | `Result<Nat64, Text>` | octas (÷10^8) |
| NEAR | `getMyNearBalance` | `Nat` | yoctoNEAR (÷10^24) |
| THORChain | `getThorBalance` | `[{amount, denom}]` | units (÷10^8) |
| CloakCoin | `getCloakBalance` | `Result<{address, balance, utxoCount}, Text>` | units (÷10^6) |
| Tron | `getTrxBalance(address)` | `Result<Nat64, Text>` | sun (÷10^6) |
| ICRC-1 tokens | `getICRC1Balance(ledgerId)` | `Result<Nat, Text>` | smallest unit |
| ICRC-1 (for addr) | `getICRC1BalanceFor(principal, ledgerId)` | `Result<Nat, Text>` | smallest unit |
| ICRC-1 info | `getICRC1TokenInfo(ledgerId)` | `Result<TokenInfo, Text>` | name, symbol, decimals |
| ICP tokens list | `getSupportedICPTokens()` | `[{name,symbol,canisterId,type_,category}]` | query |
| TRC-20 tokens | `getMyTrc20Balance(contract)` | `Result<Nat, Text>` | smallest unit |

**Batch**: `getAllBalances()` — parallel fetch across all chains.

**Performance tip**: For high-frequency reads, query chain RPCs directly using cached addresses. MeneseSDK is best for signing; your own RPC is faster for reads.

```motoko
// Example: check SOL balance, convert to human-readable
switch (await menese.getMySolanaBalance()) {
  case (#ok(lamports)) { /* lamports / 1_000_000_000 = SOL */ };
  case (#err(e)) { /* handle error */ };
};
```

### Tool 3: Send Tokens ($0.05 client / $0.10 agent)

**Return types differ by chain** — getting this wrong causes runtime errors.

| Chain | Function | Params | Return |
|-------|----------|--------|--------|
| Solana | `sendSolTransaction` | `(to, lamports:Nat64)` | `Result<Text, Text>` |
| ICP | `sendICP` | `(to:Principal, e8s:Nat64)` | `Result<SendICPResult, Text>` |
| ICRC-1 | `sendICRC1` | `(to:Principal, amount:Nat, ledger:Text)` | `Result<SendICRC1Result, Text>` |
| Bitcoin | `sendBitcoin` | `(to, sats:Nat64)` | `Result<SendResultBtcLtc, Text>` |
| Litecoin | `sendLitecoin` | `(to, litoshis:Nat64)` | `Result<SendResult, Text>` (NOT BtcLtc!) |
| EVM | `sendEvmNativeTokenAutonomous` | `(to, wei:Nat, rpc, chainId:Nat, ?quoteId)` | `Result<SendResultEvm, Text>` |
| XRP | `sendXrpAutonomous` | `(to, amountXrp:Text, ?destTag:Nat32)` | **FLAT** `SendResultXrp` |
| SUI | `sendSui` | `(to, mist:Nat64)` | `Result<SendResult, Text>` |
| TON | `sendTonSimple` | `(to, nanotons:Nat64)` | **FLAT** `SendResultTon` |
| Aptos | `sendAptos` | `(to, octas:Nat64)` | `Result<SendResult, Text>` |
| NEAR | `sendNearTransfer` | `(to, yocto:Nat)` | `Result<Text, Text>` |
| Tron | `sendTrx` | `(to, sun:Nat64)` | `Result<Text, Text>` |
| Cardano | `sendCardanoTransaction` | `(to, lovelace:Nat64)` | `Result<Text, Text>` |
| CloakCoin | `sendCloak` | `(to, amount:Nat64)` | `Result<SendResultCloak, Text>` |
| THORChain | `sendThor` | `(to, amount:Nat64, memo:Text)` | `Result<Text, Text>` |
| SPL Token | `transferSplToken` | `(amount:Nat64, srcAta, dstAta)` | `TransferAndSendResult` |
| XRP IOU | `sendXrpIOU` | `(dest, currency, issuer, amount, ?tag)` | `SendResultXrp` |
| TRC-20 | `sendTrc20` | `(contract, to, amount:Nat, feeLimit:Nat64)` | `Result<Text, Text>` |

**Variant extras**: `sendBitcoinDynamicFee`, `sendBitcoinWithFee`, `sendLitecoinWithFee`, `sendSuiMax`, `sendTon` (with bounce/comment), `sendTonWithComment`.

```motoko
// Example: send 0.5 SOL
switch (await menese.sendSolTransaction("5xK2abc...", 500_000_000)) {
  case (#ok(txHash)) { /* success — txHash is the Solana TX signature */ };
  case (#err(e)) { /* handle error */ };
};

// Example: send XRP (FLAT return — check .success, not #ok)
let r = await menese.sendXrpAutonomous("rDestAddr...", "10.5", null);
if (r.success) { /* r.txHash, r.explorerUrl */ }
else { /* r.message has error */ };
```

### Tool 3b: ICRC-2 Approve & TransferFrom ($0.05 client / $0.10 agent)

ICRC-2 adds ERC-20-style `approve` + `transferFrom` to ICP tokens. Use when building escrow, payment splitters, or any pattern where a canister needs to spend tokens on behalf of users.

| Operation | Function | Params | Return |
|-----------|----------|--------|--------|
| Approve spender | `approveICRC2` | `(spender:Principal, amount:Nat, expiresAt:?Nat64, ledgerId:Text)` | `Result<ApproveResult, Text>` |
| Check allowance | `getICRC2Allowance` | `(owner:Principal, spender:Principal, ledgerId:Text)` | `Result<Allowance, Text>` — FREE |
| TransferFrom | `transferFromICRC2` | `(from:Principal, to:Principal, amount:Nat, ledgerId:Text)` | `Result<TransferFromResult, Text>` |

```motoko
// Approve MeneseSDK canister to spend 100 ckUSDC on your behalf
let ckUSDC = "xevnm-gaaaa-aaaar-qafnq-cai";
let sdk = Principal.fromText("urs2a-ziaaa-aaaad-aembq-cai");
let r = await menese.approveICRC2(sdk, 100_000_000, null, ckUSDC);  // 100 ckUSDC (6 dec)

// Check remaining allowance (FREE)
let allowance = await menese.getICRC2Allowance(myPrincipal, sdk, ckUSDC);

// Transfer from (requires prior approval)
let t = await menese.transferFromICRC2(userPrincipal, treasuryPrincipal, 50_000_000, ckUSDC);
```

### Tool 4: Swap on DEXes ($0.075 client / $0.15 agent)

| DEX | Chain | Function | Key Details |
|-----|-------|----------|-------------|
| Raydium | Solana | `swapRaydiumApiUser` | 8 params, FLAT return |
| Uniswap V3 | EVM | `swapTokens`, `swapTokensMultiHop` | Pass quoteId or rpc+chainId |
| Uniswap shortcuts | EVM | `swapETHForUSDC`, `swapUSDCForETH` | Quick ETH↔USDC |
| ICPSwap/KongSwap | ICP | `executeICPDexSwap(SwapRequest)` | Auto-routes best price |
| Cetus | SUI | `executeSuiSwap(network, from, to, amountIn, minOut)` | Network: `#mainnet` |
| Minswap | Cardano | `executeMinswapSwap(tokenIn, tokenOut, amount, slippage)` | Float slippage % |
| XRP DEX | XRP | `xrpSwap(destAmount, sendMax, paths, slipBps)` | Use xrpFindPaths first |

**Always get a quote first (FREE)**:
- Raydium: `getRaydiumQuote(inputMint, outputMint, amount, slipBps)`
- Uniswap: `getTokenQuote(from, to, amountIn, rpc)`
- ICP: `getICPDexQuote(tokenIn, tokenOut, amountIn, slipPct)` → `AggregatedQuote` (compares ICPSwap vs KongSwap)
- SUI: `getSuiSwapQuote(network, from, to, amountIn, slipBps)`
- Cardano: `getMinswapQuote(tokenIn, tokenOut, amountIn, slipPct)`
- XRP: `xrpFindPaths(destAmount, sourceCurrencies)`

```motoko
// Example: swap 1 SOL → USDC on Raydium
let SOL = "So11111111111111111111111111111111111111112";
let USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

let result = await menese.swapRaydiumApiUser(
  SOL, USDC,
  1_000_000_000,  // 1 SOL in lamports
  150,            // 1.5% slippage
  true,           // wrapSol: input is native SOL
  false,          // unwrapSol: output is USDC not SOL
  null, null      // auto-detect ATAs
);
// FLAT record — access directly:
// result.txSignature, result.outputAmount, result.priceImpactPct
```

```motoko
// Example: swap on ICP DEX (auto-routes to ICPSwap or KongSwap)
let swapReq : Menese.SwapRequest = {
  tokenIn = "ryjl3-tyaaa-aaaaa-aaaba-cai";  // ICP ledger
  tokenOut = "mxzaz-hqaaa-aaaar-qaada-cai";  // ckUSDC
  amountIn = 100_000_000;  // 1 ICP
  minAmountOut = 0;
  slippagePct = 1.0;
  preferredDex = null;  // auto-pick best price
};
let result = await menese.executeICPDexSwap(swapReq);
```

### Tool 5: Bridge ETH↔SOL ($0.10 client / $0.20 agent)

| Direction | Function | Params |
|-----------|----------|--------|
| ETH→SOL | `quickUltrafastEthToSol` | `(ethWei:Nat)` |
| USDC→SOL | `quickUltrafastUsdcToSol` | `(usdc:Nat)` |
| ETH→Token | `quickUltrafastEthToToken` | `(ethWei:Nat, outputMint, slipBps:Nat)` |
| SOL→ETH | `quickSolToEth` | `(solLamports:Nat64, slipBps:Nat)` |
| USDC SOL→ETH | `quickUsdcBridgeSolToEth` | `(usdc:Nat64)` |
| CCTP (any) | `quickCctpBridge` | `(srcChainId, usdc, outputToken, fast, slipBps, ethRpc)` |

```motoko
// Example: bridge 0.1 ETH to Solana
let result = await menese.quickUltrafastEthToSol(100_000_000_000_000_000);  // 0.1 ETH in wei
// Result<Text, Text> — ok = status text
```

### Tool 6: DeFi — Aave V3 ($0.10 agent)

| Operation | Function | Params |
|-----------|----------|--------|
| Supply ETH | `aaveSupplyEth` | `(wei:Nat, rpc, ?quoteId)` → `Result<SupplyEthResult, Text>` |
| Withdraw ETH | `aaveWithdrawEth` | `(wei:Nat, rpc, ?quoteId)` → `Result<WithdrawEthResult, Text>` |
| Supply ERC-20 | `aaveSupplyToken` | `(tokenAddr, amount:Nat, rpc, ?quoteId)` |
| Withdraw ERC-20 | `aaveWithdrawToken` | `(tokenAddr, amount:Nat, rpc, ?quoteId)` |
| Read aWETH bal | `getAWethBalance` | `(user, rpc)` → FREE |
| Read aToken bal | `getATokenBalance` | `(aTokenAddr, user, rpc)` → FREE |

```motoko
// Supply 0.5 ETH to Aave → receive aWETH (~2-3% APY)
let r = await menese.aaveSupplyEth(500_000_000_000_000_000, ethRpc, null);
switch (r) {
  case (#ok(res)) { /* res.txHash, res.aTokenAddress */ };
  case (#err(e)) { /* error */ };
};
```

### Tool 7: DeFi — Lido Staking ($0.10 agent)

| Operation | Function | Return |
|-----------|----------|--------|
| Stake ETH→stETH | `stakeEthForStEth(wei, rpc, ?quoteId)` | `Result<StakeResult, Text>` |
| Wrap stETH→wstETH | `wrapStEth(amount, rpc, ?quoteId)` | `Result<WrapResult, Text>` |
| Unwrap wstETH→stETH | `unwrapWstEth(amount, rpc, ?quoteId)` | `Result<UnwrapResult, Text>` |
| Read stETH bal | `getStEthBalance(user, rpc)` | FREE |
| Read wstETH bal | `getWstEthBalance(user, rpc)` | FREE |

```motoko
// Stake 1 ETH with Lido (~3-4% APY), then wrap for DeFi composability
ignore await menese.stakeEthForStEth(1_000_000_000_000_000_000, ethRpc, null);
ignore await menese.wrapStEth(1_000_000_000_000_000_000, ethRpc, null);
```

### Tool 8: DeFi — Uniswap V3 Liquidity ($0.10 agent)

| Operation | Function |
|-----------|----------|
| Add ETH+Token LP | `addLiquidityETH(tokenSymbol, tokenAmt, ethAmt, slipBps, rpc, ?quoteId)` |
| Add Token+Token LP | `addLiquidity(tokenA, tokenB, amtA, amtB, slipBps, rpc, ?quoteId)` |
| Remove ETH LP | `removeLiquidityETH(tokenSymbol, lpAmt, slipBps, feeOnTransfer, rpc, ?quoteId)` |
| Remove Token LP | `removeLiquidity(tokenA, tokenB, lpAmt, slipBps, rpc, ?quoteId)` |
| Read reserves | `getPoolReserves(tokenA, tokenB, rpc)` — FREE |
| Get pair addr | `getPairAddress(tokenA, tokenB, rpc)` — FREE |

### Tool 9: Custom EVM Contract Calls

| Operation | Function | Cost |
|-----------|----------|------|
| Read (view) | `callEvmContractRead(contract, selector4byte, argsHexes, rpc)` | FREE |
| Write (tx) | `callEvmContractWrite(contract, selector, args, rpc, chainId, value, ?quoteId)` | $0.10 |

Selector = first 4 bytes of `keccak256("functionName(type1,type2)")`, hex-encoded, no `0x` prefix.

```motoko
// Read Chainlink ETH/USD price (FREE)
let result = await menese.callEvmContractRead(
  "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419",  // ETH/USD feed
  "feaf968c",  // latestRoundData()
  [], ethRpc
);
```

### Tool 10: Strategy Engine (rule creation FREE, execution per-action pricing)

| Operation | Function | Cost |
|-----------|----------|------|
| Create rule | `addStrategyRule(Rule)` | FREE |
| List rules | `getMyStrategyRules()` | FREE |
| Update status | `updateStrategyRuleStatus(ruleId, status)` | FREE |
| Delete rule | `deleteStrategyRule(ruleId)` | FREE |
| View logs | `getStrategyLogs()` | FREE |
| Init automation | `initAutomation()` | FREE |

Rule types: `#DCA`, `#StopLoss`, `#TakeProfit`, `#Rebalance`, `#Scheduled`, `#APYMigration`, `#LiquidityProvision`, `#VolatilityTrigger`.

Rule statuses: `#Active`, `#Paused`, `#Cancelled`, `#Executed`, `#Executing`, `#Failed`, `#Draft`, `#Confirmed`, `#Ready`.

### Tool 11: Solana ATA / XRP Trustlines (setup)

| Operation | Function | Cost |
|-----------|----------|------|
| Create Solana ATA | `createMySolanaAtaForMint(mint, ata)` | Send pricing |
| Create ATA (custom program) | `createMySolanaAtaForMintWithProgram(mint, ata, programId)` | Send pricing |
| Set XRP trustline | `xrpSetTrustline(currency, issuer, limit)` | Send pricing |
| Read XRP trustlines | `xrpGetAccountLines()` | FREE |
| Get Solana ATA | `getMySolanaAta(mint)` | FREE |

### Tool 12: Developer/Billing

| Operation | Function | Cost |
|-----------|----------|------|
| Register canister | `registerDeveloperCanister(Principal, appName)` | FREE |
| Get dev key | `getMyDeveloperKey()` | FREE |
| Regenerate key | `regenerateDeveloperKey()` | FREE |
| Validate key | `validateDeveloperKey(key)` | FREE |
| Check account | `getMyGatewayAccount()` → `UserAccount` | FREE |
| Check dev account | `getMyDeveloperAccount()` → `?DeveloperAccountV3` | FREE |
| Deposit credits | `depositGatewayCredits(currency, amount)` | ICP cost |

### Tool 13: Utility

| Operation | Function | Cost |
|-----------|----------|------|
| BTC max send | `getBitcoinMaxSendAmount(?feeRate)` → `{maxAmount, fee, utxoCount}` | FREE |
| LTC max send | `getLitecoinMaxSendAmount(?feeRate)` → `{maxAmount, fee, utxoCount}` | FREE |
| Health check | `health()` | FREE |
| Version | `version()` | FREE |

### Tool 14: ICP DEX LP Management ($0.10 agent)

Manage liquidity positions on ICPSwap and KongSwap. The SDK aggregates both DEXes.

| Operation | Function | Cost |
|-----------|----------|------|
| List pools | `getICPDexPools()` → `[PoolInfo]` | FREE |
| List tokens | `getICPDexTokens()` → `[DexToken]` | FREE |
| View positions | `getICPLPPositions()` → `[LPPosition]` | FREE |
| Add liquidity | `addICPLiquidity(AddLiquidityRequest)` → `Result<AddLiquidityResult, Text>` | $0.10 |
| Remove liquidity | `removeICPLiquidity(RemoveLiquidityRequest)` → `Result<RemoveLiquidityResult, Text>` | $0.10 |

**Types:**

```
AddLiquidityRequest = { poolId:Text, dex:{#ICPSwap|#KongSwap}, token0:Text, token1:Text, token0Amount:Nat, token1Amount:Nat, slippagePct:Float }
RemoveLiquidityRequest = { poolId:Text, dex:{#ICPSwap|#KongSwap}, lpTokens:Nat, slippagePct:Float }
LPPosition = { poolId, dex, token0, token1, token0Symbol, token1Symbol, liquidity:Nat, token0Amount, token1Amount, unclaimedFees:?(Nat,Nat), valueUsd:?Nat }
PoolInfo = { poolId, dex, token0, token1, token0Symbol, token1Symbol, reserve0, reserve1, fee, tvl:?Nat, apr:?Float, volume24h:?Nat }
DexToken = { canisterId, symbol, name, decimals:Nat8, fee:Nat, standard:{#ICRC1|#ICRC2|#DIP20}, logo:?Text, category:?Text, availableOn:[DexId] }
```

**Well-known pools:** ICP/ckUSDC, ckBTC/ICP, ICP/ckETH, ckUSDT/ckUSDC, CHAT/ICP (on both ICPSwap and KongSwap).

```motoko
// Discover pools, then add liquidity
let pools = await menese.getICPDexPools();
// Find ICP/ckUSDC pool
let pool = Array.find<DexTypes.PoolInfo>(pools, func(p) { p.token0Symbol == "ICP" and p.token1Symbol == "ckUSDC" });

switch (pool) {
  case (?p) {
    let req : DexTypes.AddLiquidityRequest = {
      poolId = p.poolId;
      dex = p.dex;
      token0 = "ryjl3-tyaaa-aaaaa-aaaba-cai";  // ICP ledger
      token1 = "xevnm-gaaaa-aaaar-qafnq-cai";  // ckUSDC
      token0Amount = 100_000_000;  // 1 ICP
      token1Amount = 10_000_000;   // 10 ckUSDC
      slippagePct = 1.0;
    };
    let result = await menese.addICPLiquidity(req);
  };
  case null { /* pool not found */ };
};

// View positions
let positions = await menese.getICPLPPositions();
// Remove liquidity
let removeReq : DexTypes.RemoveLiquidityRequest = {
  poolId = positions[0].poolId;
  dex = positions[0].dex;
  lpTokens = positions[0].liquidity;  // Remove all
  slippagePct = 1.0;
};
let removed = await menese.removeICPLiquidity(removeReq);
```

### Tool 15: ICP AI Rebalancer (FREE)

AI-powered portfolio rebalancing recommendations using Herfindahl-Hirschman Index diversification scoring, impermanent loss estimation, and risk-adjusted APY analysis.

| Operation | Function | Cost |
|-----------|----------|------|
| Get recommendations | `getICPRebalanceRecommendations(preferences, tokenBalances, pools?)` → `[RebalanceRecommendation]` | FREE |

**Types:**

```
RebalancePreferences = { targetCategories:[Text], riskTolerance:Text, minApy:?Float, maxImpermanentLoss:?Float, autoCompound:Bool }
  targetCategories: ["stablecoin", "defi", "lst", "yield", "wrapped", "meme", "ecosystem"]
  riskTolerance: "conservative" | "moderate" | "aggressive"

RebalanceRecommendation = { id, action:{#Swap|#AddLiquidity|#RemoveLiquidity|#Compound}, fromToken, toToken, fromSymbol, toSymbol, amount:Nat, reason:Text, estimatedApy:?Float, currentApy:?Float, impermanentLossRisk:{#Low|#Medium|#High}, confidence:Float, estimatedGasUsd:?Float }
```

```motoko
// Get rebalancing recommendations for your ICP portfolio
let prefs : DexTypes.RebalancePreferences = {
  targetCategories = ["stablecoin", "defi", "lst"];
  riskTolerance = "moderate";
  minApy = ?5.0;        // Only suggest >5% APY
  maxImpermanentLoss = ?10.0;  // Max 10% IL risk
  autoCompound = true;
};

// Pass current balances: [(canisterId, amount)]
let balances = [
  ("ryjl3-tyaaa-aaaaa-aaaba-cai", 500_000_000),  // 5 ICP
  ("xevnm-gaaaa-aaaar-qafnq-cai", 100_000_000),  // 100 ckUSDC
  ("mxzaz-hqaaa-aaaar-qaada-cai", 50_000),        // 0.0005 ckBTC
];

let recommendations = await menese.getICPRebalanceRecommendations(prefs, balances, null);
for (rec in recommendations.vals()) {
  Debug.print(rec.reason # " | Confidence: " # Float.toText(rec.confidence));
  // e.g., "Swap 2 ICP → ckUSDC and add to ICP/ckUSDC pool for 12.5% APY | Confidence: 0.85"
};
```

---

## Combining Tools — Practical Automation Examples

The real power is combining these tools. Below are complete patterns showing how tools work together.

### Example 1: DCA Bot (Timer + Balance + Swap)

Buy USDC with SOL every hour if balance exceeds threshold.

```motoko
// Tools used: getMySolanaBalance (FREE) + swapRaydiumApiUser ($0.075)
func dcaCycle() : async () {
  let balance = switch (await menese.getMySolanaBalance()) {
    case (#ok(v)) v; case (#err(_)) return;
  };
  if (balance < 500_000_000) return;  // < 0.5 SOL, skip

  let swapAmt = balance - 50_000_000;  // Keep 0.05 SOL for rent
  let _ = await menese.swapRaydiumApiUser(
    "So11111111111111111111111111111111111111112",  // SOL
    "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",  // USDC
    swapAmt, 150, true, false, null, null
  );
};

// Run every hour
let timerId = Timer.recurringTimer<system>(#seconds(3600), dcaCycle);
```

### Example 2: Stop-Loss via Strategy Engine

Set a stop-loss rule that auto-sells when price drops. No timer needed — MeneseSDK evaluates.

```motoko
// Tool used: addStrategyRule (FREE to create, execution costs per action)
let rule : Menese.Rule = {
  id = 0;
  ruleType = #StopLoss;
  status = #Active;
  chainType = #Solana;
  triggerPrice = 120_000_000;  // Trigger at this price level
  sizePct = 100;  // Sell 100% of position
  positionId = 0;
  createdAt = Time.now();
  dcaConfig = null; lpConfig = null; scheduledConfig = null;
  apyMigrationConfig = null; volatilityConfig = null;
  swapAmountLamports = ?1_000_000_000;  // 1 SOL
  swapAmountWei = null;
};
let ruleId = await menese.addStrategyRule(rule);
```

### Example 3: Take-Profit + Stop-Loss Combo

Set both on the same position — whichever triggers first wins.

```motoko
// Tools: addStrategyRule × 2
// Take-profit at 200
let tp : Menese.Rule = { /* ... */ ruleType = #TakeProfit; triggerPrice = 200_000_000; sizePct = 50; /* sell half */ /* ... */ };
let tpId = await menese.addStrategyRule(tp);

// Stop-loss at 100
let sl : Menese.Rule = { /* ... */ ruleType = #StopLoss; triggerPrice = 100_000_000; sizePct = 100; /* sell all */ /* ... */ };
let slId = await menese.addStrategyRule(sl);

// When one triggers, cancel the other
// Check via getMyStrategyRules() or getStrategyLogs() in your timer
```

### Example 4: DCA via Strategy Engine (no custom timer)

Let MeneseSDK handle the scheduling internally.

```motoko
// Tool: addStrategyRule with DCA config
let dca : Menese.Rule = {
  id = 0;
  ruleType = #DCA;
  status = #Active;
  chainType = #Solana;
  triggerPrice = 0; sizePct = 100; positionId = 0;
  createdAt = Time.now();
  dcaConfig = ?{
    amountPerInterval = 100_000_000;  // 0.1 SOL per buy
    currentInterval = 0;
    intervalSeconds = 3600;  // Every hour
    lastExecutedAt = 0;
    maxIntervals = 168;  // Run for 1 week (168 hours)
    targetToken = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";  // Buy USDC
    totalSpent = 0;
  };
  lpConfig = null; scheduledConfig = null;
  apyMigrationConfig = null; volatilityConfig = null;
  swapAmountLamports = ?100_000_000;
  swapAmountWei = null;
};
ignore await menese.addStrategyRule(dca);
```

### Example 5: Multi-Chain Sweep (Balance + Send across chains)

Check all balances, sweep any above threshold to treasury.

```motoko
// Tools: getAllBalances (FREE) + sendSolTransaction + sendICP + sendEvmNativeTokenAutonomous
func sweepCycle() : async () {
  let bals = await menese.getAllBalances();

  // Sweep SOL if > 1 SOL
  switch (bals.solana) {
    case (#ok(lamports)) {
      if (lamports > 1_000_000_000) {
        ignore await menese.sendSolTransaction(solTreasury, lamports - 50_000_000);
      };
    };
    case (#err(_)) {};
  };

  // Sweep ICP if > 1 ICP
  switch (bals.icp) {
    case (#ok(e8s)) {
      if (e8s > 100_000_000) {
        ignore await menese.sendICP(Principal.fromText(icpTreasury), e8s - 100_000);
      };
    };
    case (#err(_)) {};
  };

  // Sweep ETH if > 0.1 ETH
  switch (await menese.getMyEvmBalance(ethRpc)) {
    case (#ok(wei)) {
      if (wei > 100_000_000_000_000_000) {
        ignore await menese.sendEvmNativeTokenAutonomous(
          ethTreasury, wei - 50_000_000_000_000_000, ethRpc, 1, null
        );
      };
    };
    case (#err(_)) {};
  };
};
```

### Example 6: DeFi Yield Rebalancer (Aave + Lido + LP)

Allocate idle ETH across DeFi protocols on a timer.

```motoko
// Tools: getMyEvmBalance + getAWethBalance + getStEthBalance (all FREE)
//        + aaveSupplyEth + stakeEthForStEth + wrapStEth ($0.10 each)

func rebalanceCycle() : async () {
  let evmAddr = (await menese.getMyEvmAddress()).evmAddress;  // Cached ideally
  let ethBal = switch (await menese.getMyEvmBalance(ethRpc)) { case (#ok(v)) v; case _ 0 };
  let aaveBal = switch (await menese.getAWethBalance(evmAddr, ethRpc)) { case (#ok(v)) v; case _ 0 };
  let lidoBal = switch (await menese.getStEthBalance(evmAddr, ethRpc)) { case (#ok(v)) v; case _ 0 };

  let reserve = 50_000_000_000_000_000;  // 0.05 ETH for gas
  if (ethBal <= reserve) return;
  let deployable = ethBal - reserve;

  // 50% Aave, 50% Lido
  let aaveTarget = deployable / 2;
  let lidoTarget = deployable / 2;

  if (aaveTarget > aaveBal and aaveTarget - aaveBal > 10_000_000_000_000_000) {
    ignore await menese.aaveSupplyEth(aaveTarget - aaveBal, ethRpc, null);
  };
  if (lidoTarget > lidoBal and lidoTarget - lidoBal > 10_000_000_000_000_000) {
    ignore await menese.stakeEthForStEth(lidoTarget - lidoBal, ethRpc, null);
    ignore await menese.wrapStEth(lidoTarget - lidoBal, ethRpc, null);
  };
};

// Run every 6 hours
let timerId = Timer.recurringTimer<system>(#seconds(21600), rebalanceCycle);
```

### Example 7: Cross-Chain Arbitrage (Bridge + Swap)

Move funds between Ethereum and Solana to capture price differences.

```motoko
// Tools: getTokenQuote (FREE) + getRaydiumQuote (FREE)
//        + quickUltrafastEthToSol ($0.10) + swapRaydiumApiUser ($0.075)

// 1. Check ETH USDC price on Uniswap
let ethQuote = await menese.getTokenQuote("USDC", "WETH", 1000_000_000, ethRpc);

// 2. Check SOL USDC price on Raydium
let solQuote = await menese.getRaydiumQuote(USDC_MINT, SOL_MINT, 1000_000_000, 100);

// 3. If profitable, bridge and swap
// Bridge ETH → SOL: quickUltrafastEthToSol
// Swap on Raydium: swapRaydiumApiUser
// Bridge back: quickSolToEth
```

### Example 8: Merchant Payment Flow (Address + Balance + Sweep)

Accept payments and auto-sweep to treasury.

```motoko
// Tools: getMySolanaAddress (FREE, cached) + getMySolanaBalance (FREE)
//        + sendSolTransaction ($0.05)

// 1. Show payment address to customer (from cache)
let payAddr = cachedAddresses.solana;

// 2. Periodically check if payment arrived (FREE)
let bal = switch (await menese.getMySolanaBalance()) { case (#ok(v)) v; case _ 0 };
if (bal >= invoiceAmount) {
  // 3. Mark paid, sweep to treasury
  ignore await menese.sendSolTransaction(treasury, bal - 50_000_000);
};
```

### Example 9: Scheduled Weekly Swap (Strategy Engine)

Use `#Scheduled` rule type for time-based operations without custom timers.

```motoko
let weekly : Menese.Rule = {
  id = 0;
  ruleType = #Scheduled;
  status = #Active;
  chainType = #Solana;
  triggerPrice = 0; sizePct = 100; positionId = 0;
  createdAt = Time.now();
  dcaConfig = null;
  scheduledConfig = ?{};  // SDK handles scheduling details
  lpConfig = null; apyMigrationConfig = null; volatilityConfig = null;
  swapAmountLamports = ?500_000_000;  // 0.5 SOL
  swapAmountWei = null;
};
ignore await menese.addStrategyRule(weekly);
```

### Example 10: Monitor + React to Volatility

Use `#VolatilityTrigger` or custom timer with price feeds.

```motoko
// Strategy engine approach:
let volRule : Menese.Rule = {
  id = 0;
  ruleType = #VolatilityTrigger;
  status = #Active;
  chainType = #EVM;
  triggerPrice = 0; sizePct = 50; positionId = 0;
  createdAt = Time.now();
  dcaConfig = null; lpConfig = null; scheduledConfig = null;
  apyMigrationConfig = null;
  volatilityConfig = ?{};  // SDK evaluates volatility conditions
  swapAmountLamports = null;
  swapAmountWei = ?500_000_000_000_000_000;  // 0.5 ETH
};

// Custom approach: read Chainlink price feed + react
func checkVolatility() : async () {
  let price = await menese.callEvmContractRead(
    "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419",  // ETH/USD Chainlink
    "feaf968c", [], ethRpc
  );
  // Parse price, compare to threshold, execute swap if needed
};
```

---

## Unit Conversion Quick Reference

| Chain | Unit | Decimals | 1 Token = |
|-------|------|----------|-----------|
| Solana | lamports | 9 | 1,000,000,000 |
| ICP | e8s | 8 | 100,000,000 |
| Bitcoin | satoshis | 8 | 100,000,000 |
| Litecoin | litoshis | 8 | 100,000,000 |
| EVM | wei | 18 | 10^18 |
| XRP | drops (Text) | 6 | "1.0" |
| SUI | mist | 9 | 1,000,000,000 |
| TON | nanotons | 9 | 1,000,000,000 |
| Cardano | lovelace | 6 | 1,000,000 |
| Aptos | octas | 8 | 100,000,000 |
| NEAR | yoctoNEAR | 24 | 10^24 |
| Tron | sun | 6 | 1,000,000 |
| CloakCoin | units | 6 | 1,000,000 |
| THORChain | units | 8 | 100,000,000 |

---

## Common Pitfalls

1. **Wrong field names** — `evmAddress` not `address`, `suiAddress` not `address`, `nonBounceable` not `address`, `implicitAccountId` not `accountId`, `base58Address` not `base58`
2. **Flat vs variant returns** — XRP and TON send return FLAT records (check `.success`). Raydium swap also returns FLAT. Everything else uses `Result<T, Text>` with `#ok/#err`.
3. **Litecoin ≠ Bitcoin return type** — Litecoin = `SendResult` (`.txHash`), Bitcoin = `SendResultBtcLtc` (`.txid` + `.fee`)
4. **CloakCoin = 6 decimals**, never 8
5. **EVM needs your RPC** — configure endpoints before any EVM operation
6. **XRP amount is Text** — pass `"1.5"` not `1500000`
7. **Cache addresses** — deterministic per principal, fetch once and store
8. **Always keep a reserve** — leave min balance for rent/fees (0.05 SOL, 0.001 ICP, 0.05 ETH)
9. **Get quotes before swaps** — all quote functions are FREE
10. **Strategy rules are FREE to create** — you only pay when execution happens

---

## Pricing Summary

| Operation | Client Mode | Agent Mode |
|-----------|------------|------------|
| Addresses/Balances/Quotes | FREE | FREE |
| Strategy rule CRUD | FREE | FREE |
| Send/Transfer | $0.05 | $0.10 |
| DEX Swap | $0.075 | $0.15 |
| Bridge | $0.10 | $0.20 |
| DeFi (Aave/Lido/LP/Custom) | — | $0.10 |

| Tier | Price | Actions/Month |
|------|-------|---------------|
| Free | $0 | 5 (lifetime) |
| Developer | $35/mo | 1,000 |
| Pro | $99/mo | 5,000 |
| Enterprise | $249/mo | Unlimited |

---

## Files in This Skill

| File | Purpose |
|------|---------|
| `SKILL.md` | This guide — all tools, examples, best practices |
| `WalletBot.mo` | ICP canister wrapping MeneseSDK (production use) |
| `scripts/wallet_commands.py` | Python CLI for dfx calls (prototyping/testing) |
| `references/api-surface.md` | Full API — every type definition and function signature |
| `references/automation.md` | Deep dive — timer bots, DeFi yield, strategy patterns, custom contracts |

