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---5
6# Multichain Protocol — MeneseSDK Wallet Skill
7
8Operate 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.
9
10**Powered by Menese Protocol** | **Canister ID (mainnet):** `urs2a-ziaaa-aaaad-aembq-cai`
11
12---
13
14## Pricing
15
16**First 5 transactions are FREE** — no signup, no credit card, just install and go.
17
18After the free tier, transaction signing is charged per action via your DeveloperKey (`msk_*`). Read-only operations (balances, addresses, pool queries) are always free.
19
20---
21
22## Quickstart (2 minutes)
23
24### Step 1: Install dfx (ICP SDK)
25
26If you don't have `dfx` installed, run this single command:
27
28```bash
29sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
30```
31
32Verify it works:
33```bash
34dfx --version
35```
36
37That's it. No accounts needed, no wallets to set up — dfx handles everything.
38
39### Step 2: Install the skill
40
41```bash
42clawhub install multichain-protocol
43```
44
45Or manually: copy `SKILL.md` + `wallet_commands.py` to your workspace.
46
47### Step 3: Create an ICP identity (if you don't have one)
48
49```bash
50dfx identity new my-wallet
51dfx identity use my-wallet
52```
53
54### Step 4: Try it — your first 5 sends are free
55
56Ask 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```
64
65### Step 5 (optional): Deploy your own canister for production
66
67For multi-user, automation, and timers — deploy `WalletBot.mo` as your own ICP canister.
68
69---
70
71## Two Integration Approaches
72
73| | 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) |
79
80---
81
82## Best Practice: Cache Addresses
83
84Addresses are **deterministic** — the same principal always gets the same addresses on every chain. Fetch once, cache forever.
85
86```motoko
87// Canister pattern — cache in stable var
88stable var cachedAddresses : ?AddressBook = null;
89
90public shared func getAddresses() : async AddressBook {
91 switch (cachedAddresses) {
92 case (?addrs) { addrs }; // Return cached — no inter-canister call
93 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```
104
105```python
106# CLI pattern — fetch once, store in file
107import json, os
108CACHE_FILE = "addresses_cache.json"
109
110def get_addresses():
111 if os.path.exists(CACHE_FILE):
112 return json.load(open(CACHE_FILE))
113 addrs = fetch_all_addresses() # dfx calls
114 json.dump(addrs, open(CACHE_FILE, "w"))
115 return addrs
116```
117
118**Why**: Saves inter-canister call latency + cycles. Addresses never change for a given principal.
119
120---
121
122## EVM Chains — Bring Your Own RPC
123
124All EVM operations (ETH, Arbitrum, Base, Polygon, BSC, Optimism) require **your own RPC endpoint**. MeneseSDK does not manage EVM RPCs.
125
126| 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` |
134
135Use Alchemy/Infura for production reliability.
136
137---
138
139## Complete Tool Reference
140
141Every operation available, organized by category. Each tool shows the function, parameters, return type, cost, and a usage example.
142
143### Tool 1: Get Addresses (FREE)
144
145Deterministic per-principal. **Cache after first call.**
146
147| 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` |
162
163**Batch**: `getAllAddresses()` — all chains in one call.
164**Solana ATA**: `getMySolanaAta(mintBase58)` — get associated token account for an SPL token.
165
166```motoko
167// Example: get SOL address
168let info = await menese.getMySolanaAddress();
169let myAddress = info.address; // "5xK2abc..."
170```
171
172```bash
173# CLI
174dfx canister call urs2a-ziaaa-aaaad-aembq-cai getMySolanaAddress --network ic --query
175```
176
177### Tool 2: Check Balances (FREE)
178
179| 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 |
201
202**Batch**: `getAllBalances()` — parallel fetch across all chains.
203
204**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.
205
206```motoko
207// Example: check SOL balance, convert to human-readable
208switch (await menese.getMySolanaBalance()) {
209 case (#ok(lamports)) { /* lamports / 1_000_000_000 = SOL */ };
210 case (#err(e)) { /* handle error */ };
211};
212```
213
214### Tool 3: Send Tokens ($0.05 client / $0.10 agent)
215
216**Return types differ by chain** — getting this wrong causes runtime errors.
217
218| 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>` |
238
239**Variant extras**: `sendBitcoinDynamicFee`, `sendBitcoinWithFee`, `sendLitecoinWithFee`, `sendSuiMax`, `sendTon` (with bounce/comment), `sendTonWithComment`.
240
241```motoko
242// Example: send 0.5 SOL
243switch (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};
247
248// 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```
253
254### Tool 3b: ICRC-2 Approve & TransferFrom ($0.05 client / $0.10 agent)
255
256ICRC-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.
257
258| 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>` |
263
264```motoko
265// Approve MeneseSDK canister to spend 100 ckUSDC on your behalf
266let 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)
269
270// Check remaining allowance (FREE)
271let allowance = await menese.getICRC2Allowance(myPrincipal, sdk, ckUSDC);
272
273// Transfer from (requires prior approval)
274let t = await menese.transferFromICRC2(userPrincipal, treasuryPrincipal, 50_000_000, ckUSDC);
275```
276
277### Tool 4: Swap on DEXes ($0.075 client / $0.15 agent)
278
279| 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 |
288
289**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)`
296
297```motoko
298// Example: swap 1 SOL → USDC on Raydium
299let SOL = "So11111111111111111111111111111111111111112";
300let USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
301
302let result = await menese.swapRaydiumApiUser(
303 SOL, USDC,
304 1_000_000_000, // 1 SOL in lamports
305 150, // 1.5% slippage
306 true, // wrapSol: input is native SOL
307 false, // unwrapSol: output is USDC not SOL
308 null, null // auto-detect ATAs
309);
310// FLAT record — access directly:
311// result.txSignature, result.outputAmount, result.priceImpactPct
312```
313
314```motoko
315// Example: swap on ICP DEX (auto-routes to ICPSwap or KongSwap)
316let swapReq : Menese.SwapRequest = {
317 tokenIn = "ryjl3-tyaaa-aaaaa-aaaba-cai"; // ICP ledger
318 tokenOut = "mxzaz-hqaaa-aaaar-qaada-cai"; // ckUSDC
319 amountIn = 100_000_000; // 1 ICP
320 minAmountOut = 0;
321 slippagePct = 1.0;
322 preferredDex = null; // auto-pick best price
323};
324let result = await menese.executeICPDexSwap(swapReq);
325```
326
327### Tool 5: Bridge ETH↔SOL ($0.10 client / $0.20 agent)
328
329| 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)` |
337
338```motoko
339// Example: bridge 0.1 ETH to Solana
340let result = await menese.quickUltrafastEthToSol(100_000_000_000_000_000); // 0.1 ETH in wei
341// Result<Text, Text> — ok = status text
342```
343
344### Tool 6: DeFi — Aave V3 ($0.10 agent)
345
346| 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 |
354
355```motoko
356// 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```
363
364### Tool 7: DeFi — Lido Staking ($0.10 agent)
365
366| 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 |
373
374```motoko
375// Stake 1 ETH with Lido (~3-4% APY), then wrap for DeFi composability
376ignore 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```
379
380### Tool 8: DeFi — Uniswap V3 Liquidity ($0.10 agent)
381
382| 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 |
390
391### Tool 9: Custom EVM Contract Calls
392
393| 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 |
397
398Selector = first 4 bytes of `keccak256("functionName(type1,type2)")`, hex-encoded, no `0x` prefix.
399
400```motoko
401// Read Chainlink ETH/USD price (FREE)
402let result = await menese.callEvmContractRead(
403 "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", // ETH/USD feed
404 "feaf968c", // latestRoundData()
405 [], ethRpc
406);
407```
408
409### Tool 10: Strategy Engine (rule creation FREE, execution per-action pricing)
410
411| 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 |
419
420Rule types: `#DCA`, `#StopLoss`, `#TakeProfit`, `#Rebalance`, `#Scheduled`, `#APYMigration`, `#LiquidityProvision`, `#VolatilityTrigger`.
421
422Rule statuses: `#Active`, `#Paused`, `#Cancelled`, `#Executed`, `#Executing`, `#Failed`, `#Draft`, `#Confirmed`, `#Ready`.
423
424### Tool 11: Solana ATA / XRP Trustlines (setup)
425
426| 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 |
433
434### Tool 12: Developer/Billing
435
436| 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 |
445
446### Tool 13: Utility
447
448| 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 |
454
455### Tool 14: ICP DEX LP Management ($0.10 agent)
456
457Manage liquidity positions on ICPSwap and KongSwap. The SDK aggregates both DEXes.
458
459| 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 |
466
467**Types:**
468
469```
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```
476
477**Well-known pools:** ICP/ckUSDC, ckBTC/ICP, ICP/ckETH, ckUSDT/ckUSDC, CHAT/ICP (on both ICPSwap and KongSwap).
478
479```motoko
480// Discover pools, then add liquidity
481let pools = await menese.getICPDexPools();
482// Find ICP/ckUSDC pool
483let pool = Array.find<DexTypes.PoolInfo>(pools, func(p) { p.token0Symbol == "ICP" and p.token1Symbol == "ckUSDC" });
484
485switch (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 ledger
491 token1 = "xevnm-gaaaa-aaaar-qafnq-cai"; // ckUSDC
492 token0Amount = 100_000_000; // 1 ICP
493 token1Amount = 10_000_000; // 10 ckUSDC
494 slippagePct = 1.0;
495 };
496 let result = await menese.addICPLiquidity(req);
497 };
498 case null { /* pool not found */ };
499};
500
501// View positions
502let positions = await menese.getICPLPPositions();
503// Remove liquidity
504let removeReq : DexTypes.RemoveLiquidityRequest = {
505 poolId = positions[0].poolId;
506 dex = positions[0].dex;
507 lpTokens = positions[0].liquidity; // Remove all
508 slippagePct = 1.0;
509};
510let removed = await menese.removeICPLiquidity(removeReq);
511```
512
513### Tool 15: ICP AI Rebalancer (FREE)
514
515AI-powered portfolio rebalancing recommendations using Herfindahl-Hirschman Index diversification scoring, impermanent loss estimation, and risk-adjusted APY analysis.
516
517| Operation | Function | Cost |
518|-----------|----------|------|
519| Get recommendations | `getICPRebalanceRecommendations(preferences, tokenBalances, pools?)` → `[RebalanceRecommendation]` | FREE |
520
521**Types:**
522
523```
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"
527
528RebalanceRecommendation = { 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```
530
531```motoko
532// Get rebalancing recommendations for your ICP portfolio
533let prefs : DexTypes.RebalancePreferences = {
534 targetCategories = ["stablecoin", "defi", "lst"];
535 riskTolerance = "moderate";
536 minApy = ?5.0; // Only suggest >5% APY
537 maxImpermanentLoss = ?10.0; // Max 10% IL risk
538 autoCompound = true;
539};
540
541// Pass current balances: [(canisterId, amount)]
542let balances = [
543 ("ryjl3-tyaaa-aaaaa-aaaba-cai", 500_000_000), // 5 ICP
544 ("xevnm-gaaaa-aaaar-qafnq-cai", 100_000_000), // 100 ckUSDC
545 ("mxzaz-hqaaa-aaaar-qaada-cai", 50_000), // 0.0005 ckBTC
546];
547
548let 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```
554
555---
556
557## Combining Tools — Practical Automation Examples
558
559The real power is combining these tools. Below are complete patterns showing how tools work together.
560
561### Example 1: DCA Bot (Timer + Balance + Swap)
562
563Buy USDC with SOL every hour if balance exceeds threshold.
564
565```motoko
566// 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, skip
572
573 let swapAmt = balance - 50_000_000; // Keep 0.05 SOL for rent
574 let _ = await menese.swapRaydiumApiUser(
575 "So11111111111111111111111111111111111111112", // SOL
576 "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
577 swapAmt, 150, true, false, null, null
578 );
579};
580
581// Run every hour
582let timerId = Timer.recurringTimer<system>(#seconds(3600), dcaCycle);
583```
584
585### Example 2: Stop-Loss via Strategy Engine
586
587Set a stop-loss rule that auto-sells when price drops. No timer needed — MeneseSDK evaluates.
588
589```motoko
590// 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 level
597 sizePct = 100; // Sell 100% of position
598 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 SOL
603 swapAmountWei = null;
604};
605let ruleId = await menese.addStrategyRule(rule);
606```
607
608### Example 3: Take-Profit + Stop-Loss Combo
609
610Set both on the same position — whichever triggers first wins.
611
612```motoko
613// Tools: addStrategyRule × 2
614// Take-profit at 200
615let tp : Menese.Rule = { /* ... */ ruleType = #TakeProfit; triggerPrice = 200_000_000; sizePct = 50; /* sell half */ /* ... */ };
616let tpId = await menese.addStrategyRule(tp);
617
618// Stop-loss at 100
619let sl : Menese.Rule = { /* ... */ ruleType = #StopLoss; triggerPrice = 100_000_000; sizePct = 100; /* sell all */ /* ... */ };
620let slId = await menese.addStrategyRule(sl);
621
622// When one triggers, cancel the other
623// Check via getMyStrategyRules() or getStrategyLogs() in your timer
624```
625
626### Example 4: DCA via Strategy Engine (no custom timer)
627
628Let MeneseSDK handle the scheduling internally.
629
630```motoko
631// Tool: addStrategyRule with DCA config
632let 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 buy
641 currentInterval = 0;
642 intervalSeconds = 3600; // Every hour
643 lastExecutedAt = 0;
644 maxIntervals = 168; // Run for 1 week (168 hours)
645 targetToken = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; // Buy USDC
646 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```
655
656### Example 5: Multi-Chain Sweep (Balance + Send across chains)
657
658Check all balances, sweep any above threshold to treasury.
659
660```motoko
661// Tools: getAllBalances (FREE) + sendSolTransaction + sendICP + sendEvmNativeTokenAutonomous
662func sweepCycle() : async () {
663 let bals = await menese.getAllBalances();
664
665 // Sweep SOL if > 1 SOL
666 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 };
674
675 // Sweep ICP if > 1 ICP
676 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 };
684
685 // Sweep ETH if > 0.1 ETH
686 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, null
691 );
692 };
693 };
694 case (#err(_)) {};
695 };
696};
697```
698
699### Example 6: DeFi Yield Rebalancer (Aave + Lido + LP)
700
701Allocate idle ETH across DeFi protocols on a timer.
702
703```motoko
704// Tools: getMyEvmBalance + getAWethBalance + getStEthBalance (all FREE)
705// + aaveSupplyEth + stakeEthForStEth + wrapStEth ($0.10 each)
706
707func rebalanceCycle() : async () {
708 let evmAddr = (await menese.getMyEvmAddress()).evmAddress; // Cached ideally
709 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 };
712
713 let reserve = 50_000_000_000_000_000; // 0.05 ETH for gas
714 if (ethBal <= reserve) return;
715 let deployable = ethBal - reserve;
716
717 // 50% Aave, 50% Lido
718 let aaveTarget = deployable / 2;
719 let lidoTarget = deployable / 2;
720
721 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};
729
730// Run every 6 hours
731let timerId = Timer.recurringTimer<system>(#seconds(21600), rebalanceCycle);
732```
733
734### Example 7: Cross-Chain Arbitrage (Bridge + Swap)
735
736Move funds between Ethereum and Solana to capture price differences.
737
738```motoko
739// Tools: getTokenQuote (FREE) + getRaydiumQuote (FREE)
740// + quickUltrafastEthToSol ($0.10) + swapRaydiumApiUser ($0.075)
741
742// 1. Check ETH USDC price on Uniswap
743let ethQuote = await menese.getTokenQuote("USDC", "WETH", 1000_000_000, ethRpc);
744
745// 2. Check SOL USDC price on Raydium
746let solQuote = await menese.getRaydiumQuote(USDC_MINT, SOL_MINT, 1000_000_000, 100);
747
748// 3. If profitable, bridge and swap
749// Bridge ETH → SOL: quickUltrafastEthToSol
750// Swap on Raydium: swapRaydiumApiUser
751// Bridge back: quickSolToEth
752```
753
754### Example 8: Merchant Payment Flow (Address + Balance + Sweep)
755
756Accept payments and auto-sweep to treasury.
757
758```motoko
759// Tools: getMySolanaAddress (FREE, cached) + getMySolanaBalance (FREE)
760// + sendSolTransaction ($0.05)
761
762// 1. Show payment address to customer (from cache)
763let payAddr = cachedAddresses.solana;
764
765// 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 treasury
769 ignore await menese.sendSolTransaction(treasury, bal - 50_000_000);
770};
771```
772
773### Example 9: Scheduled Weekly Swap (Strategy Engine)
774
775Use `#Scheduled` rule type for time-based operations without custom timers.
776
777```motoko
778let 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 details
787 lpConfig = null; apyMigrationConfig = null; volatilityConfig = null;
788 swapAmountLamports = ?500_000_000; // 0.5 SOL
789 swapAmountWei = null;
790};
791ignore await menese.addStrategyRule(weekly);
792```
793
794### Example 10: Monitor + React to Volatility
795
796Use `#VolatilityTrigger` or custom timer with price feeds.
797
798```motoko
799// 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 conditions
810 swapAmountLamports = null;
811 swapAmountWei = ?500_000_000_000_000_000; // 0.5 ETH
812};
813
814// Custom approach: read Chainlink price feed + react
815func checkVolatility() : async () {
816 let price = await menese.callEvmContractRead(
817 "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", // ETH/USD Chainlink
818 "feaf968c", [], ethRpc
819 );
820 // Parse price, compare to threshold, execute swap if needed
821};
822```
823
824---
825
826## Unit Conversion Quick Reference
827
828| 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 |
844
845---
846
847## Common Pitfalls
848
8491. **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 8
8535. **EVM needs your RPC** — configure endpoints before any EVM operation
8546. **XRP amount is Text** — pass `"1.5"` not `1500000`
8557. **Cache addresses** — deterministic per principal, fetch once and store
8568. **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 FREE
85810. **Strategy rules are FREE to create** — you only pay when execution happens
859
860---
861
862## Pricing Summary
863
864| 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 |
872
873| 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 |
879
880---
881
882## Files in This Skill
883
884| 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 |