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:
sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
Verify it works:
dfx --version
That's it. No accounts needed, no wallets to set up — dfx handles everything.
Step 2: Install the skill
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)
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.
// 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;
};
};
};
# 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.
// Example: get SOL address
let info = await menese.getMySolanaAddress();
let myAddress = info.address; // "5xK2abc..."
# 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.
// 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.
// 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> |
// 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)
// 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
// 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) |
// 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 |
// 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 |
// 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.
// 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).
// 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 }
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
// 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.
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.
// 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
- Wrong field names —
evmAddress not address, suiAddress not address, nonBounceable not address, implicitAccountId not accountId, base58Address not base58
- 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.
- Litecoin ≠ Bitcoin return type — Litecoin =
SendResult (.txHash), Bitcoin = SendResultBtcLtc (.txid + .fee)
- CloakCoin = 6 decimals, never 8
- EVM needs your RPC — configure endpoints before any EVM operation
- XRP amount is Text — pass
"1.5" not 1500000
- Cache addresses — deterministic per principal, fetch once and store
- Always keep a reserve — leave min balance for rent/fees (0.05 SOL, 0.001 ICP, 0.05 ETH)
- Get quotes before swaps — all quote functions are FREE
- 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 |
1---2name: multichain-protocol3description: 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.4---56# Multichain Protocol — MeneseSDK Wallet Skill78Operate 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.910**Powered by Menese Protocol** | **Canister ID (mainnet):** `urs2a-ziaaa-aaaad-aembq-cai`1112---1314## Pricing1516**First 5 transactions are FREE** — no signup, no credit card, just install and go.1718After the free tier, transaction signing is charged per action via your DeveloperKey (`msk_*`). Read-only operations (balances, addresses, pool queries) are always free.1920---2122## Quickstart (2 minutes)2324### Step 1: Install dfx (ICP SDK)2526If you don't have `dfx` installed, run this single command:2728```bash29sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"30```3132Verify it works:33```bash34dfx --version35```3637That's it. No accounts needed, no wallets to set up — dfx handles everything.3839### Step 2: Install the skill4041```bash42clawhub install multichain-protocol43```4445Or manually: copy `SKILL.md` + `wallet_commands.py` to your workspace.4647### Step 3: Create an ICP identity (if you don't have one)4849```bash50dfx identity new my-wallet51dfx identity use my-wallet52```5354### Step 4: Try it — your first 5 sends are free5556Ask your bot:57```58"show my wallet addresses"59"what's my SOL balance?"60"send 0.1 ETH to 0xABC..."61"swap 100 USDC to SOL on Raydium"62"set up a DCA: buy $50 of BTC every day"63```6465### Step 5 (optional): Deploy your own canister for production6667For multi-user, automation, and timers — deploy `WalletBot.mo` as your own ICP canister.6869---7071## Two Integration Approaches7273| | Canister (Recommended) | CLI (Quick) |74|---|---|---|75| **Flow** | User → ClawdBot → Your Canister → MeneseSDK | User → ClawdBot → `dfx canister call` → MeneseSDK |76| **Setup** | Deploy `WalletBot.mo`, register with SDK | Copy `scripts/wallet_commands.py`, done |77| **Best for** | Multi-user, automation, timers, production | Single-user, prototyping, testing |78| **Automation** | ICP timers for DCA/rebalance/bots | None (manual only) |7980---8182## Best Practice: Cache Addresses8384Addresses are **deterministic** — the same principal always gets the same addresses on every chain. Fetch once, cache forever.8586```motoko87// Canister pattern — cache in stable var88stable var cachedAddresses : ?AddressBook = null;8990public shared func getAddresses() : async AddressBook {91 switch (cachedAddresses) {92 case (?addrs) { addrs }; // Return cached — no inter-canister call93 case null {94 let sol = await menese.getMySolanaAddress();95 let evm = await menese.getMyEvmAddress();96 // ... fetch all chains once ...97 let addrs = { solana = sol.address; evm = evm.evmAddress; /* ... */ };98 cachedAddresses := ?addrs;99 addrs;100 };101 };102};103```104105```python106# CLI pattern — fetch once, store in file107import json, os108CACHE_FILE = "addresses_cache.json"109110def get_addresses():111 if os.path.exists(CACHE_FILE):112 return json.load(open(CACHE_FILE))113 addrs = fetch_all_addresses() # dfx calls114 json.dump(addrs, open(CACHE_FILE, "w"))115 return addrs116```117118**Why**: Saves inter-canister call latency + cycles. Addresses never change for a given principal.119120---121122## EVM Chains — Bring Your Own RPC123124All EVM operations (ETH, Arbitrum, Base, Polygon, BSC, Optimism) require **your own RPC endpoint**. MeneseSDK does not manage EVM RPCs.125126| Chain | Chain ID | Free Public RPC |127|-------|----------|----------------|128| Ethereum | 1 | `https://eth.llamarpc.com` |129| Arbitrum | 42161 | `https://arb1.arbitrum.io/rpc` |130| Base | 8453 | `https://mainnet.base.org` |131| Polygon | 137 | `https://polygon-rpc.com` |132| BSC | 56 | `https://bsc-dataseed1.binance.org` |133| Optimism | 10 | `https://mainnet.optimism.io` |134135Use Alchemy/Infura for production reliability.136137---138139## Complete Tool Reference140141Every operation available, organized by category. Each tool shows the function, parameters, return type, cost, and a usage example.142143### Tool 1: Get Addresses (FREE)144145Deterministic per-principal. **Cache after first call.**146147| Chain | Function | Field to Extract |148|-------|----------|-----------------|149| Solana | `getMySolanaAddress` | `.address` |150| EVM (all 6) | `getMyEvmAddress` | `.evmAddress` (NOT `.address`) |151| Bitcoin | `getMyBitcoinAddress` | `.bech32Address` |152| Litecoin | `getMyLitecoinAddress` | `.bech32Address` |153| SUI | `getMySuiAddress` | `.suiAddress` (NOT `.address`) |154| XRP | `getMyXrpAddress` | `.classicAddress` |155| TON | `getMyTonAddress` | `.nonBounceable` (NOT `.address`) |156| Cardano | `getMyCardanoAddress` | `.bech32Address` |157| Aptos | `getMyAptosAddress` | `.address` |158| NEAR | `getMyNearAddress` | `.implicitAccountId` (NOT `.accountId`) |159| Tron | `getTronAddress` | `.base58Address` (NOT `.base58`) |160| CloakCoin | `getMyCloakAddress` | `.base58Address` |161| THORChain | `getMyThorAddress` | `.bech32Address` |162163**Batch**: `getAllAddresses()` — all chains in one call.164**Solana ATA**: `getMySolanaAta(mintBase58)` — get associated token account for an SPL token.165166```motoko167// Example: get SOL address168let info = await menese.getMySolanaAddress();169let myAddress = info.address; // "5xK2abc..."170```171172```bash173# CLI174dfx canister call urs2a-ziaaa-aaaad-aembq-cai getMySolanaAddress --network ic --query175```176177### Tool 2: Check Balances (FREE)178179| Chain | Function | Returns | Unit |180|-------|----------|---------|------|181| Solana | `getMySolanaBalance` | `Result<Nat64, Text>` | lamports (÷10^9) |182| ICP | `getICPBalance` | `Result<Nat64, Text>` | e8s (÷10^8) |183| ICP (for addr) | `getICPBalanceFor(principal)` | `Result<Nat64, Text>` | e8s (÷10^8) |184| Bitcoin | `getBitcoinBalance` | `Nat64` | satoshis (÷10^8) |185| Litecoin | `getLitecoinBalance` | `Nat64` | litoshis (÷10^8) |186| EVM | `getMyEvmBalance(rpcUrl)` | `Result<Nat, Text>` | wei (÷10^18) |187| XRP | `getMyXrpBalance` | `Result<Text, Text>` | drops as text |188| SUI | `getMySuiBalance` | `Nat64` | mist (÷10^9) |189| TON | `getMyTonBalance` | `Result<Nat64, Text>` | nanotons (÷10^9) |190| Cardano | `getCardanoBalance` | `Result<Nat64, Text>` | lovelace (÷10^6) |191| Aptos | `getAptosBalance` | `Result<Nat64, Text>` | octas (÷10^8) |192| NEAR | `getMyNearBalance` | `Nat` | yoctoNEAR (÷10^24) |193| THORChain | `getThorBalance` | `[{amount, denom}]` | units (÷10^8) |194| CloakCoin | `getCloakBalance` | `Result<{address, balance, utxoCount}, Text>` | units (÷10^6) |195| Tron | `getTrxBalance(address)` | `Result<Nat64, Text>` | sun (÷10^6) |196| ICRC-1 tokens | `getICRC1Balance(ledgerId)` | `Result<Nat, Text>` | smallest unit |197| ICRC-1 (for addr) | `getICRC1BalanceFor(principal, ledgerId)` | `Result<Nat, Text>` | smallest unit |198| ICRC-1 info | `getICRC1TokenInfo(ledgerId)` | `Result<TokenInfo, Text>` | name, symbol, decimals |199| ICP tokens list | `getSupportedICPTokens()` | `[{name,symbol,canisterId,type_,category}]` | query |200| TRC-20 tokens | `getMyTrc20Balance(contract)` | `Result<Nat, Text>` | smallest unit |201202**Batch**: `getAllBalances()` — parallel fetch across all chains.203204**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.205206```motoko207// Example: check SOL balance, convert to human-readable208switch (await menese.getMySolanaBalance()) {209 case (#ok(lamports)) { /* lamports / 1_000_000_000 = SOL */ };210 case (#err(e)) { /* handle error */ };211};212```213214### Tool 3: Send Tokens ($0.05 client / $0.10 agent)215216**Return types differ by chain** — getting this wrong causes runtime errors.217218| Chain | Function | Params | Return |219|-------|----------|--------|--------|220| Solana | `sendSolTransaction` | `(to, lamports:Nat64)` | `Result<Text, Text>` |221| ICP | `sendICP` | `(to:Principal, e8s:Nat64)` | `Result<SendICPResult, Text>` |222| ICRC-1 | `sendICRC1` | `(to:Principal, amount:Nat, ledger:Text)` | `Result<SendICRC1Result, Text>` |223| Bitcoin | `sendBitcoin` | `(to, sats:Nat64)` | `Result<SendResultBtcLtc, Text>` |224| Litecoin | `sendLitecoin` | `(to, litoshis:Nat64)` | `Result<SendResult, Text>` (NOT BtcLtc!) |225| EVM | `sendEvmNativeTokenAutonomous` | `(to, wei:Nat, rpc, chainId:Nat, ?quoteId)` | `Result<SendResultEvm, Text>` |226| XRP | `sendXrpAutonomous` | `(to, amountXrp:Text, ?destTag:Nat32)` | **FLAT** `SendResultXrp` |227| SUI | `sendSui` | `(to, mist:Nat64)` | `Result<SendResult, Text>` |228| TON | `sendTonSimple` | `(to, nanotons:Nat64)` | **FLAT** `SendResultTon` |229| Aptos | `sendAptos` | `(to, octas:Nat64)` | `Result<SendResult, Text>` |230| NEAR | `sendNearTransfer` | `(to, yocto:Nat)` | `Result<Text, Text>` |231| Tron | `sendTrx` | `(to, sun:Nat64)` | `Result<Text, Text>` |232| Cardano | `sendCardanoTransaction` | `(to, lovelace:Nat64)` | `Result<Text, Text>` |233| CloakCoin | `sendCloak` | `(to, amount:Nat64)` | `Result<SendResultCloak, Text>` |234| THORChain | `sendThor` | `(to, amount:Nat64, memo:Text)` | `Result<Text, Text>` |235| SPL Token | `transferSplToken` | `(amount:Nat64, srcAta, dstAta)` | `TransferAndSendResult` |236| XRP IOU | `sendXrpIOU` | `(dest, currency, issuer, amount, ?tag)` | `SendResultXrp` |237| TRC-20 | `sendTrc20` | `(contract, to, amount:Nat, feeLimit:Nat64)` | `Result<Text, Text>` |238239**Variant extras**: `sendBitcoinDynamicFee`, `sendBitcoinWithFee`, `sendLitecoinWithFee`, `sendSuiMax`, `sendTon` (with bounce/comment), `sendTonWithComment`.240241```motoko242// Example: send 0.5 SOL243switch (await menese.sendSolTransaction("5xK2abc...", 500_000_000)) {244 case (#ok(txHash)) { /* success — txHash is the Solana TX signature */ };245 case (#err(e)) { /* handle error */ };246};247248// Example: send XRP (FLAT return — check .success, not #ok)249let r = await menese.sendXrpAutonomous("rDestAddr...", "10.5", null);250if (r.success) { /* r.txHash, r.explorerUrl */ }251else { /* r.message has error */ };252```253254### Tool 3b: ICRC-2 Approve & TransferFrom ($0.05 client / $0.10 agent)255256ICRC-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.257258| Operation | Function | Params | Return |259|-----------|----------|--------|--------|260| Approve spender | `approveICRC2` | `(spender:Principal, amount:Nat, expiresAt:?Nat64, ledgerId:Text)` | `Result<ApproveResult, Text>` |261| Check allowance | `getICRC2Allowance` | `(owner:Principal, spender:Principal, ledgerId:Text)` | `Result<Allowance, Text>` — FREE |262| TransferFrom | `transferFromICRC2` | `(from:Principal, to:Principal, amount:Nat, ledgerId:Text)` | `Result<TransferFromResult, Text>` |263264```motoko265// Approve MeneseSDK canister to spend 100 ckUSDC on your behalf266let ckUSDC = "xevnm-gaaaa-aaaar-qafnq-cai";267let sdk = Principal.fromText("urs2a-ziaaa-aaaad-aembq-cai");268let r = await menese.approveICRC2(sdk, 100_000_000, null, ckUSDC); // 100 ckUSDC (6 dec)269270// Check remaining allowance (FREE)271let allowance = await menese.getICRC2Allowance(myPrincipal, sdk, ckUSDC);272273// Transfer from (requires prior approval)274let t = await menese.transferFromICRC2(userPrincipal, treasuryPrincipal, 50_000_000, ckUSDC);275```276277### Tool 4: Swap on DEXes ($0.075 client / $0.15 agent)278279| DEX | Chain | Function | Key Details |280|-----|-------|----------|-------------|281| Raydium | Solana | `swapRaydiumApiUser` | 8 params, FLAT return |282| Uniswap V3 | EVM | `swapTokens`, `swapTokensMultiHop` | Pass quoteId or rpc+chainId |283| Uniswap shortcuts | EVM | `swapETHForUSDC`, `swapUSDCForETH` | Quick ETH↔USDC |284| ICPSwap/KongSwap | ICP | `executeICPDexSwap(SwapRequest)` | Auto-routes best price |285| Cetus | SUI | `executeSuiSwap(network, from, to, amountIn, minOut)` | Network: `#mainnet` |286| Minswap | Cardano | `executeMinswapSwap(tokenIn, tokenOut, amount, slippage)` | Float slippage % |287| XRP DEX | XRP | `xrpSwap(destAmount, sendMax, paths, slipBps)` | Use xrpFindPaths first |288289**Always get a quote first (FREE)**:290- Raydium: `getRaydiumQuote(inputMint, outputMint, amount, slipBps)`291- Uniswap: `getTokenQuote(from, to, amountIn, rpc)`292- ICP: `getICPDexQuote(tokenIn, tokenOut, amountIn, slipPct)` → `AggregatedQuote` (compares ICPSwap vs KongSwap)293- SUI: `getSuiSwapQuote(network, from, to, amountIn, slipBps)`294- Cardano: `getMinswapQuote(tokenIn, tokenOut, amountIn, slipPct)`295- XRP: `xrpFindPaths(destAmount, sourceCurrencies)`296297```motoko298// Example: swap 1 SOL → USDC on Raydium299let SOL = "So11111111111111111111111111111111111111112";300let USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";301302let result = await menese.swapRaydiumApiUser(303 SOL, USDC,304 1_000_000_000, // 1 SOL in lamports305 150, // 1.5% slippage306 true, // wrapSol: input is native SOL307 false, // unwrapSol: output is USDC not SOL308 null, null // auto-detect ATAs309);310// FLAT record — access directly:311// result.txSignature, result.outputAmount, result.priceImpactPct312```313314```motoko315// Example: swap on ICP DEX (auto-routes to ICPSwap or KongSwap)316let swapReq : Menese.SwapRequest = {317 tokenIn = "ryjl3-tyaaa-aaaaa-aaaba-cai"; // ICP ledger318 tokenOut = "mxzaz-hqaaa-aaaar-qaada-cai"; // ckUSDC319 amountIn = 100_000_000; // 1 ICP320 minAmountOut = 0;321 slippagePct = 1.0;322 preferredDex = null; // auto-pick best price323};324let result = await menese.executeICPDexSwap(swapReq);325```326327### Tool 5: Bridge ETH↔SOL ($0.10 client / $0.20 agent)328329| Direction | Function | Params |330|-----------|----------|--------|331| ETH→SOL | `quickUltrafastEthToSol` | `(ethWei:Nat)` |332| USDC→SOL | `quickUltrafastUsdcToSol` | `(usdc:Nat)` |333| ETH→Token | `quickUltrafastEthToToken` | `(ethWei:Nat, outputMint, slipBps:Nat)` |334| SOL→ETH | `quickSolToEth` | `(solLamports:Nat64, slipBps:Nat)` |335| USDC SOL→ETH | `quickUsdcBridgeSolToEth` | `(usdc:Nat64)` |336| CCTP (any) | `quickCctpBridge` | `(srcChainId, usdc, outputToken, fast, slipBps, ethRpc)` |337338```motoko339// Example: bridge 0.1 ETH to Solana340let result = await menese.quickUltrafastEthToSol(100_000_000_000_000_000); // 0.1 ETH in wei341// Result<Text, Text> — ok = status text342```343344### Tool 6: DeFi — Aave V3 ($0.10 agent)345346| Operation | Function | Params |347|-----------|----------|--------|348| Supply ETH | `aaveSupplyEth` | `(wei:Nat, rpc, ?quoteId)` → `Result<SupplyEthResult, Text>` |349| Withdraw ETH | `aaveWithdrawEth` | `(wei:Nat, rpc, ?quoteId)` → `Result<WithdrawEthResult, Text>` |350| Supply ERC-20 | `aaveSupplyToken` | `(tokenAddr, amount:Nat, rpc, ?quoteId)` |351| Withdraw ERC-20 | `aaveWithdrawToken` | `(tokenAddr, amount:Nat, rpc, ?quoteId)` |352| Read aWETH bal | `getAWethBalance` | `(user, rpc)` → FREE |353| Read aToken bal | `getATokenBalance` | `(aTokenAddr, user, rpc)` → FREE |354355```motoko356// Supply 0.5 ETH to Aave → receive aWETH (~2-3% APY)357let r = await menese.aaveSupplyEth(500_000_000_000_000_000, ethRpc, null);358switch (r) {359 case (#ok(res)) { /* res.txHash, res.aTokenAddress */ };360 case (#err(e)) { /* error */ };361};362```363364### Tool 7: DeFi — Lido Staking ($0.10 agent)365366| Operation | Function | Return |367|-----------|----------|--------|368| Stake ETH→stETH | `stakeEthForStEth(wei, rpc, ?quoteId)` | `Result<StakeResult, Text>` |369| Wrap stETH→wstETH | `wrapStEth(amount, rpc, ?quoteId)` | `Result<WrapResult, Text>` |370| Unwrap wstETH→stETH | `unwrapWstEth(amount, rpc, ?quoteId)` | `Result<UnwrapResult, Text>` |371| Read stETH bal | `getStEthBalance(user, rpc)` | FREE |372| Read wstETH bal | `getWstEthBalance(user, rpc)` | FREE |373374```motoko375// Stake 1 ETH with Lido (~3-4% APY), then wrap for DeFi composability376ignore await menese.stakeEthForStEth(1_000_000_000_000_000_000, ethRpc, null);377ignore await menese.wrapStEth(1_000_000_000_000_000_000, ethRpc, null);378```379380### Tool 8: DeFi — Uniswap V3 Liquidity ($0.10 agent)381382| Operation | Function |383|-----------|----------|384| Add ETH+Token LP | `addLiquidityETH(tokenSymbol, tokenAmt, ethAmt, slipBps, rpc, ?quoteId)` |385| Add Token+Token LP | `addLiquidity(tokenA, tokenB, amtA, amtB, slipBps, rpc, ?quoteId)` |386| Remove ETH LP | `removeLiquidityETH(tokenSymbol, lpAmt, slipBps, feeOnTransfer, rpc, ?quoteId)` |387| Remove Token LP | `removeLiquidity(tokenA, tokenB, lpAmt, slipBps, rpc, ?quoteId)` |388| Read reserves | `getPoolReserves(tokenA, tokenB, rpc)` — FREE |389| Get pair addr | `getPairAddress(tokenA, tokenB, rpc)` — FREE |390391### Tool 9: Custom EVM Contract Calls392393| Operation | Function | Cost |394|-----------|----------|------|395| Read (view) | `callEvmContractRead(contract, selector4byte, argsHexes, rpc)` | FREE |396| Write (tx) | `callEvmContractWrite(contract, selector, args, rpc, chainId, value, ?quoteId)` | $0.10 |397398Selector = first 4 bytes of `keccak256("functionName(type1,type2)")`, hex-encoded, no `0x` prefix.399400```motoko401// Read Chainlink ETH/USD price (FREE)402let result = await menese.callEvmContractRead(403 "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", // ETH/USD feed404 "feaf968c", // latestRoundData()405 [], ethRpc406);407```408409### Tool 10: Strategy Engine (rule creation FREE, execution per-action pricing)410411| Operation | Function | Cost |412|-----------|----------|------|413| Create rule | `addStrategyRule(Rule)` | FREE |414| List rules | `getMyStrategyRules()` | FREE |415| Update status | `updateStrategyRuleStatus(ruleId, status)` | FREE |416| Delete rule | `deleteStrategyRule(ruleId)` | FREE |417| View logs | `getStrategyLogs()` | FREE |418| Init automation | `initAutomation()` | FREE |419420Rule types: `#DCA`, `#StopLoss`, `#TakeProfit`, `#Rebalance`, `#Scheduled`, `#APYMigration`, `#LiquidityProvision`, `#VolatilityTrigger`.421422Rule statuses: `#Active`, `#Paused`, `#Cancelled`, `#Executed`, `#Executing`, `#Failed`, `#Draft`, `#Confirmed`, `#Ready`.423424### Tool 11: Solana ATA / XRP Trustlines (setup)425426| Operation | Function | Cost |427|-----------|----------|------|428| Create Solana ATA | `createMySolanaAtaForMint(mint, ata)` | Send pricing |429| Create ATA (custom program) | `createMySolanaAtaForMintWithProgram(mint, ata, programId)` | Send pricing |430| Set XRP trustline | `xrpSetTrustline(currency, issuer, limit)` | Send pricing |431| Read XRP trustlines | `xrpGetAccountLines()` | FREE |432| Get Solana ATA | `getMySolanaAta(mint)` | FREE |433434### Tool 12: Developer/Billing435436| Operation | Function | Cost |437|-----------|----------|------|438| Register canister | `registerDeveloperCanister(Principal, appName)` | FREE |439| Get dev key | `getMyDeveloperKey()` | FREE |440| Regenerate key | `regenerateDeveloperKey()` | FREE |441| Validate key | `validateDeveloperKey(key)` | FREE |442| Check account | `getMyGatewayAccount()` → `UserAccount` | FREE |443| Check dev account | `getMyDeveloperAccount()` → `?DeveloperAccountV3` | FREE |444| Deposit credits | `depositGatewayCredits(currency, amount)` | ICP cost |445446### Tool 13: Utility447448| Operation | Function | Cost |449|-----------|----------|------|450| BTC max send | `getBitcoinMaxSendAmount(?feeRate)` → `{maxAmount, fee, utxoCount}` | FREE |451| LTC max send | `getLitecoinMaxSendAmount(?feeRate)` → `{maxAmount, fee, utxoCount}` | FREE |452| Health check | `health()` | FREE |453| Version | `version()` | FREE |454455### Tool 14: ICP DEX LP Management ($0.10 agent)456457Manage liquidity positions on ICPSwap and KongSwap. The SDK aggregates both DEXes.458459| Operation | Function | Cost |460|-----------|----------|------|461| List pools | `getICPDexPools()` → `[PoolInfo]` | FREE |462| List tokens | `getICPDexTokens()` → `[DexToken]` | FREE |463| View positions | `getICPLPPositions()` → `[LPPosition]` | FREE |464| Add liquidity | `addICPLiquidity(AddLiquidityRequest)` → `Result<AddLiquidityResult, Text>` | $0.10 |465| Remove liquidity | `removeICPLiquidity(RemoveLiquidityRequest)` → `Result<RemoveLiquidityResult, Text>` | $0.10 |466467**Types:**468469```470AddLiquidityRequest = { poolId:Text, dex:{#ICPSwap|#KongSwap}, token0:Text, token1:Text, token0Amount:Nat, token1Amount:Nat, slippagePct:Float }471RemoveLiquidityRequest = { poolId:Text, dex:{#ICPSwap|#KongSwap}, lpTokens:Nat, slippagePct:Float }472LPPosition = { poolId, dex, token0, token1, token0Symbol, token1Symbol, liquidity:Nat, token0Amount, token1Amount, unclaimedFees:?(Nat,Nat), valueUsd:?Nat }473PoolInfo = { poolId, dex, token0, token1, token0Symbol, token1Symbol, reserve0, reserve1, fee, tvl:?Nat, apr:?Float, volume24h:?Nat }474DexToken = { canisterId, symbol, name, decimals:Nat8, fee:Nat, standard:{#ICRC1|#ICRC2|#DIP20}, logo:?Text, category:?Text, availableOn:[DexId] }475```476477**Well-known pools:** ICP/ckUSDC, ckBTC/ICP, ICP/ckETH, ckUSDT/ckUSDC, CHAT/ICP (on both ICPSwap and KongSwap).478479```motoko480// Discover pools, then add liquidity481let pools = await menese.getICPDexPools();482// Find ICP/ckUSDC pool483let pool = Array.find<DexTypes.PoolInfo>(pools, func(p) { p.token0Symbol == "ICP" and p.token1Symbol == "ckUSDC" });484485switch (pool) {486 case (?p) {487 let req : DexTypes.AddLiquidityRequest = {488 poolId = p.poolId;489 dex = p.dex;490 token0 = "ryjl3-tyaaa-aaaaa-aaaba-cai"; // ICP ledger491 token1 = "xevnm-gaaaa-aaaar-qafnq-cai"; // ckUSDC492 token0Amount = 100_000_000; // 1 ICP493 token1Amount = 10_000_000; // 10 ckUSDC494 slippagePct = 1.0;495 };496 let result = await menese.addICPLiquidity(req);497 };498 case null { /* pool not found */ };499};500501// View positions502let positions = await menese.getICPLPPositions();503// Remove liquidity504let removeReq : DexTypes.RemoveLiquidityRequest = {505 poolId = positions[0].poolId;506 dex = positions[0].dex;507 lpTokens = positions[0].liquidity; // Remove all508 slippagePct = 1.0;509};510let removed = await menese.removeICPLiquidity(removeReq);511```512513### Tool 15: ICP AI Rebalancer (FREE)514515AI-powered portfolio rebalancing recommendations using Herfindahl-Hirschman Index diversification scoring, impermanent loss estimation, and risk-adjusted APY analysis.516517| Operation | Function | Cost |518|-----------|----------|------|519| Get recommendations | `getICPRebalanceRecommendations(preferences, tokenBalances, pools?)` → `[RebalanceRecommendation]` | FREE |520521**Types:**522523```524RebalancePreferences = { targetCategories:[Text], riskTolerance:Text, minApy:?Float, maxImpermanentLoss:?Float, autoCompound:Bool }525 targetCategories: ["stablecoin", "defi", "lst", "yield", "wrapped", "meme", "ecosystem"]526 riskTolerance: "conservative" | "moderate" | "aggressive"527528RebalanceRecommendation = { 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 }529```530531```motoko532// Get rebalancing recommendations for your ICP portfolio533let prefs : DexTypes.RebalancePreferences = {534 targetCategories = ["stablecoin", "defi", "lst"];535 riskTolerance = "moderate";536 minApy = ?5.0; // Only suggest >5% APY537 maxImpermanentLoss = ?10.0; // Max 10% IL risk538 autoCompound = true;539};540541// Pass current balances: [(canisterId, amount)]542let balances = [543 ("ryjl3-tyaaa-aaaaa-aaaba-cai", 500_000_000), // 5 ICP544 ("xevnm-gaaaa-aaaar-qafnq-cai", 100_000_000), // 100 ckUSDC545 ("mxzaz-hqaaa-aaaar-qaada-cai", 50_000), // 0.0005 ckBTC546];547548let recommendations = await menese.getICPRebalanceRecommendations(prefs, balances, null);549for (rec in recommendations.vals()) {550 Debug.print(rec.reason # " | Confidence: " # Float.toText(rec.confidence));551 // e.g., "Swap 2 ICP → ckUSDC and add to ICP/ckUSDC pool for 12.5% APY | Confidence: 0.85"552};553```554555---556557## Combining Tools — Practical Automation Examples558559The real power is combining these tools. Below are complete patterns showing how tools work together.560561### Example 1: DCA Bot (Timer + Balance + Swap)562563Buy USDC with SOL every hour if balance exceeds threshold.564565```motoko566// Tools used: getMySolanaBalance (FREE) + swapRaydiumApiUser ($0.075)567func dcaCycle() : async () {568 let balance = switch (await menese.getMySolanaBalance()) {569 case (#ok(v)) v; case (#err(_)) return;570 };571 if (balance < 500_000_000) return; // < 0.5 SOL, skip572573 let swapAmt = balance - 50_000_000; // Keep 0.05 SOL for rent574 let _ = await menese.swapRaydiumApiUser(575 "So11111111111111111111111111111111111111112", // SOL576 "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC577 swapAmt, 150, true, false, null, null578 );579};580581// Run every hour582let timerId = Timer.recurringTimer<system>(#seconds(3600), dcaCycle);583```584585### Example 2: Stop-Loss via Strategy Engine586587Set a stop-loss rule that auto-sells when price drops. No timer needed — MeneseSDK evaluates.588589```motoko590// Tool used: addStrategyRule (FREE to create, execution costs per action)591let rule : Menese.Rule = {592 id = 0;593 ruleType = #StopLoss;594 status = #Active;595 chainType = #Solana;596 triggerPrice = 120_000_000; // Trigger at this price level597 sizePct = 100; // Sell 100% of position598 positionId = 0;599 createdAt = Time.now();600 dcaConfig = null; lpConfig = null; scheduledConfig = null;601 apyMigrationConfig = null; volatilityConfig = null;602 swapAmountLamports = ?1_000_000_000; // 1 SOL603 swapAmountWei = null;604};605let ruleId = await menese.addStrategyRule(rule);606```607608### Example 3: Take-Profit + Stop-Loss Combo609610Set both on the same position — whichever triggers first wins.611612```motoko613// Tools: addStrategyRule × 2614// Take-profit at 200615let tp : Menese.Rule = { /* ... */ ruleType = #TakeProfit; triggerPrice = 200_000_000; sizePct = 50; /* sell half */ /* ... */ };616let tpId = await menese.addStrategyRule(tp);617618// Stop-loss at 100619let sl : Menese.Rule = { /* ... */ ruleType = #StopLoss; triggerPrice = 100_000_000; sizePct = 100; /* sell all */ /* ... */ };620let slId = await menese.addStrategyRule(sl);621622// When one triggers, cancel the other623// Check via getMyStrategyRules() or getStrategyLogs() in your timer624```625626### Example 4: DCA via Strategy Engine (no custom timer)627628Let MeneseSDK handle the scheduling internally.629630```motoko631// Tool: addStrategyRule with DCA config632let dca : Menese.Rule = {633 id = 0;634 ruleType = #DCA;635 status = #Active;636 chainType = #Solana;637 triggerPrice = 0; sizePct = 100; positionId = 0;638 createdAt = Time.now();639 dcaConfig = ?{640 amountPerInterval = 100_000_000; // 0.1 SOL per buy641 currentInterval = 0;642 intervalSeconds = 3600; // Every hour643 lastExecutedAt = 0;644 maxIntervals = 168; // Run for 1 week (168 hours)645 targetToken = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; // Buy USDC646 totalSpent = 0;647 };648 lpConfig = null; scheduledConfig = null;649 apyMigrationConfig = null; volatilityConfig = null;650 swapAmountLamports = ?100_000_000;651 swapAmountWei = null;652};653ignore await menese.addStrategyRule(dca);654```655656### Example 5: Multi-Chain Sweep (Balance + Send across chains)657658Check all balances, sweep any above threshold to treasury.659660```motoko661// Tools: getAllBalances (FREE) + sendSolTransaction + sendICP + sendEvmNativeTokenAutonomous662func sweepCycle() : async () {663 let bals = await menese.getAllBalances();664665 // Sweep SOL if > 1 SOL666 switch (bals.solana) {667 case (#ok(lamports)) {668 if (lamports > 1_000_000_000) {669 ignore await menese.sendSolTransaction(solTreasury, lamports - 50_000_000);670 };671 };672 case (#err(_)) {};673 };674675 // Sweep ICP if > 1 ICP676 switch (bals.icp) {677 case (#ok(e8s)) {678 if (e8s > 100_000_000) {679 ignore await menese.sendICP(Principal.fromText(icpTreasury), e8s - 100_000);680 };681 };682 case (#err(_)) {};683 };684685 // Sweep ETH if > 0.1 ETH686 switch (await menese.getMyEvmBalance(ethRpc)) {687 case (#ok(wei)) {688 if (wei > 100_000_000_000_000_000) {689 ignore await menese.sendEvmNativeTokenAutonomous(690 ethTreasury, wei - 50_000_000_000_000_000, ethRpc, 1, null691 );692 };693 };694 case (#err(_)) {};695 };696};697```698699### Example 6: DeFi Yield Rebalancer (Aave + Lido + LP)700701Allocate idle ETH across DeFi protocols on a timer.702703```motoko704// Tools: getMyEvmBalance + getAWethBalance + getStEthBalance (all FREE)705// + aaveSupplyEth + stakeEthForStEth + wrapStEth ($0.10 each)706707func rebalanceCycle() : async () {708 let evmAddr = (await menese.getMyEvmAddress()).evmAddress; // Cached ideally709 let ethBal = switch (await menese.getMyEvmBalance(ethRpc)) { case (#ok(v)) v; case _ 0 };710 let aaveBal = switch (await menese.getAWethBalance(evmAddr, ethRpc)) { case (#ok(v)) v; case _ 0 };711 let lidoBal = switch (await menese.getStEthBalance(evmAddr, ethRpc)) { case (#ok(v)) v; case _ 0 };712713 let reserve = 50_000_000_000_000_000; // 0.05 ETH for gas714 if (ethBal <= reserve) return;715 let deployable = ethBal - reserve;716717 // 50% Aave, 50% Lido718 let aaveTarget = deployable / 2;719 let lidoTarget = deployable / 2;720721 if (aaveTarget > aaveBal and aaveTarget - aaveBal > 10_000_000_000_000_000) {722 ignore await menese.aaveSupplyEth(aaveTarget - aaveBal, ethRpc, null);723 };724 if (lidoTarget > lidoBal and lidoTarget - lidoBal > 10_000_000_000_000_000) {725 ignore await menese.stakeEthForStEth(lidoTarget - lidoBal, ethRpc, null);726 ignore await menese.wrapStEth(lidoTarget - lidoBal, ethRpc, null);727 };728};729730// Run every 6 hours731let timerId = Timer.recurringTimer<system>(#seconds(21600), rebalanceCycle);732```733734### Example 7: Cross-Chain Arbitrage (Bridge + Swap)735736Move funds between Ethereum and Solana to capture price differences.737738```motoko739// Tools: getTokenQuote (FREE) + getRaydiumQuote (FREE)740// + quickUltrafastEthToSol ($0.10) + swapRaydiumApiUser ($0.075)741742// 1. Check ETH USDC price on Uniswap743let ethQuote = await menese.getTokenQuote("USDC", "WETH", 1000_000_000, ethRpc);744745// 2. Check SOL USDC price on Raydium746let solQuote = await menese.getRaydiumQuote(USDC_MINT, SOL_MINT, 1000_000_000, 100);747748// 3. If profitable, bridge and swap749// Bridge ETH → SOL: quickUltrafastEthToSol750// Swap on Raydium: swapRaydiumApiUser751// Bridge back: quickSolToEth752```753754### Example 8: Merchant Payment Flow (Address + Balance + Sweep)755756Accept payments and auto-sweep to treasury.757758```motoko759// Tools: getMySolanaAddress (FREE, cached) + getMySolanaBalance (FREE)760// + sendSolTransaction ($0.05)761762// 1. Show payment address to customer (from cache)763let payAddr = cachedAddresses.solana;764765// 2. Periodically check if payment arrived (FREE)766let bal = switch (await menese.getMySolanaBalance()) { case (#ok(v)) v; case _ 0 };767if (bal >= invoiceAmount) {768 // 3. Mark paid, sweep to treasury769 ignore await menese.sendSolTransaction(treasury, bal - 50_000_000);770};771```772773### Example 9: Scheduled Weekly Swap (Strategy Engine)774775Use `#Scheduled` rule type for time-based operations without custom timers.776777```motoko778let weekly : Menese.Rule = {779 id = 0;780 ruleType = #Scheduled;781 status = #Active;782 chainType = #Solana;783 triggerPrice = 0; sizePct = 100; positionId = 0;784 createdAt = Time.now();785 dcaConfig = null;786 scheduledConfig = ?{}; // SDK handles scheduling details787 lpConfig = null; apyMigrationConfig = null; volatilityConfig = null;788 swapAmountLamports = ?500_000_000; // 0.5 SOL789 swapAmountWei = null;790};791ignore await menese.addStrategyRule(weekly);792```793794### Example 10: Monitor + React to Volatility795796Use `#VolatilityTrigger` or custom timer with price feeds.797798```motoko799// Strategy engine approach:800let volRule : Menese.Rule = {801 id = 0;802 ruleType = #VolatilityTrigger;803 status = #Active;804 chainType = #EVM;805 triggerPrice = 0; sizePct = 50; positionId = 0;806 createdAt = Time.now();807 dcaConfig = null; lpConfig = null; scheduledConfig = null;808 apyMigrationConfig = null;809 volatilityConfig = ?{}; // SDK evaluates volatility conditions810 swapAmountLamports = null;811 swapAmountWei = ?500_000_000_000_000_000; // 0.5 ETH812};813814// Custom approach: read Chainlink price feed + react815func checkVolatility() : async () {816 let price = await menese.callEvmContractRead(817 "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", // ETH/USD Chainlink818 "feaf968c", [], ethRpc819 );820 // Parse price, compare to threshold, execute swap if needed821};822```823824---825826## Unit Conversion Quick Reference827828| Chain | Unit | Decimals | 1 Token = |829|-------|------|----------|-----------|830| Solana | lamports | 9 | 1,000,000,000 |831| ICP | e8s | 8 | 100,000,000 |832| Bitcoin | satoshis | 8 | 100,000,000 |833| Litecoin | litoshis | 8 | 100,000,000 |834| EVM | wei | 18 | 10^18 |835| XRP | drops (Text) | 6 | "1.0" |836| SUI | mist | 9 | 1,000,000,000 |837| TON | nanotons | 9 | 1,000,000,000 |838| Cardano | lovelace | 6 | 1,000,000 |839| Aptos | octas | 8 | 100,000,000 |840| NEAR | yoctoNEAR | 24 | 10^24 |841| Tron | sun | 6 | 1,000,000 |842| CloakCoin | units | 6 | 1,000,000 |843| THORChain | units | 8 | 100,000,000 |844845---846847## Common Pitfalls8488491. **Wrong field names** — `evmAddress` not `address`, `suiAddress` not `address`, `nonBounceable` not `address`, `implicitAccountId` not `accountId`, `base58Address` not `base58`8502. **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`.8513. **Litecoin ≠ Bitcoin return type** — Litecoin = `SendResult` (`.txHash`), Bitcoin = `SendResultBtcLtc` (`.txid` + `.fee`)8524. **CloakCoin = 6 decimals**, never 88535. **EVM needs your RPC** — configure endpoints before any EVM operation8546. **XRP amount is Text** — pass `"1.5"` not `1500000`8557. **Cache addresses** — deterministic per principal, fetch once and store8568. **Always keep a reserve** — leave min balance for rent/fees (0.05 SOL, 0.001 ICP, 0.05 ETH)8579. **Get quotes before swaps** — all quote functions are FREE85810. **Strategy rules are FREE to create** — you only pay when execution happens859860---861862## Pricing Summary863864| Operation | Client Mode | Agent Mode |865|-----------|------------|------------|866| Addresses/Balances/Quotes | FREE | FREE |867| Strategy rule CRUD | FREE | FREE |868| Send/Transfer | $0.05 | $0.10 |869| DEX Swap | $0.075 | $0.15 |870| Bridge | $0.10 | $0.20 |871| DeFi (Aave/Lido/LP/Custom) | — | $0.10 |872873| Tier | Price | Actions/Month |874|------|-------|---------------|875| Free | $0 | 5 (lifetime) |876| Developer | $35/mo | 1,000 |877| Pro | $99/mo | 5,000 |878| Enterprise | $249/mo | Unlimited |879880---881882## Files in This Skill883884| File | Purpose |885|------|---------|886| `SKILL.md` | This guide — all tools, examples, best practices |887| `WalletBot.mo` | ICP canister wrapping MeneseSDK (production use) |888| `scripts/wallet_commands.py` | Python CLI for dfx calls (prototyping/testing) |889| `references/api-surface.md` | Full API — every type definition and function signature |890| `references/automation.md` | Deep dive — timer bots, DeFi yield, strategy patterns, custom contracts |