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
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.
If you don't have dfx installed, run this single command:
bash
sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
Verify it works:
bash
dfx --version
That's it. No accounts needed, no wallets to set up — dfx handles everything.
bash
clawhub install multichain-protocol
Or manually: copy SKILL.md + wallet_commands.py to your workspace.
bash
dfx identity new my-wallet
dfx identity use my-wallet
Ask your bot:
text
"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"
For multi-user, automation, and timers — deploy WalletBot.mo as your own ICP canister.
Canister (Recommended)CLI (Quick)FlowUser → ClawdBot → Your Canister → MeneseSDKUser → ClawdBot → dfx canister call → MeneseSDKSetupDeploy WalletBot.mo, register with SDKCopy scripts/wallet_commands.py, doneBest forMulti-user, automation, timers, productionSingle-user, prototyping, testingAutomationICP timers for DCA/rebalance/botsNone (manual only)
Addresses are deterministic — the same principal always gets the same addresses on every chain. Fetch once, cache forever.
motoko
// Canister pattern — cache in stable var
stable var cachedAddresses : ?AddressBook = null;
public shared func getAddresses() : async AddressBook {
switch (cachedAddresses) {
case (?addrs) { addrs }; // Return cached — no inter-canister call
case null {
let sol = await menese.getMySolanaAddress();
let evm = await menese.getMyEvmAddress();
// ... fetch all chains once ...
let addrs = { solana = sol.address; evm = evm.evmAddress; /* ... */ };
cachedAddresses := ?addrs;
addrs;
};
};
};
python
# CLI pattern — fetch once, store in file
import json, os
CACHE_FILE = "addresses_cache.json"
def get_addresses():
if os.path.exists(CACHE_FILE):
return json.load(open(CACHE_FILE))
addrs = fetch_all_addresses() # dfx calls
json.dump(addrs, open(CACHE_FILE, "w"))
return addrs
Why: Saves inter-canister call latency + cycles. Addresses never change for a given principal.
All EVM operations (ETH, Arbitrum, Base, Polygon, BSC, Optimism) require your own RPC endpoint. MeneseSDK does not manage EVM RPCs.
ChainChain IDFree Public RPCEthereum1https://eth.llamarpc.comArbitrum42161https://arb1.arbitrum.io/rpcBase8453https://mainnet.base.orgPolygon137https://polygon-rpc.comBSC56https://bsc-dataseed1.binance.orgOptimism10https://mainnet.optimism.io
Use Alchemy/Infura for production reliability.
Every operation available, organized by category. Each tool shows the function, parameters, return type, cost, and a usage example.
Deterministic per-principal. Cache after first call.
ChainFunctionField to ExtractSolanagetMySolanaAddress``.addressEVM (all 6)getMyEvmAddress``.evmAddress (NOT .address)BitcoingetMyBitcoinAddress``.bech32AddressLitecoingetMyLitecoinAddress``.bech32AddressSUIgetMySuiAddress``.suiAddress (NOT .address)XRPgetMyXrpAddress``.classicAddressTONgetMyTonAddress``.nonBounceable (NOT .address)CardanogetMyCardanoAddress``.bech32AddressAptosgetMyAptosAddress``.addressNEARgetMyNearAddress``.implicitAccountId (NOT .accountId)TrongetTronAddress``.base58Address (NOT .base58)CloakCoingetMyCloakAddress``.base58AddressTHORChaingetMyThorAddress``.bech32Address
Batch: getAllAddresses() — all chains in one call.
Solana ATA: getMySolanaAta(mintBase58) — get associated token account for an SPL token.
motoko
// Example: get SOL address
let info = await menese.getMySolanaAddress();
let myAddress = info.address; // "5xK2abc..."
bash
# CLI
dfx canister call urs2a-ziaaa-aaaad-aembq-cai getMySolanaAddress --network ic --query
ChainFunctionReturnsUnitSolanagetMySolanaBalance``Result<Nat64, Text>lamports (÷10^9)ICPgetICPBalance``Result<Nat64, Text>e8s (÷10^8)ICP (for addr)getICPBalanceFor(principal)``Result<Nat64, Text>e8s (÷10^8)BitcoingetBitcoinBalance``Nat64satoshis (÷10^8)LitecoingetLitecoinBalance``Nat64litoshis (÷10^8)EVMgetMyEvmBalance(rpcUrl)``Result<Nat, Text>wei (÷10^18)XRPgetMyXrpBalance``Result<Text, Text>drops as textSUIgetMySuiBalance``Nat64mist (÷10^9)TONgetMyTonBalance``Result<Nat64, Text>nanotons (÷10^9)CardanogetCardanoBalance``Result<Nat64, Text>lovelace (÷10^6)AptosgetAptosBalance``Result<Nat64, Text>octas (÷10^8)NEARgetMyNearBalance``NatyoctoNEAR (÷10^24)THORChaingetThorBalance``[{amount, denom}]units (÷10^8)CloakCoingetCloakBalance``Result<{address, balance, utxoCount}, Text>units (÷10^6)TrongetTrxBalance(address)``Result<Nat64, Text>sun (÷10^6)ICRC-1 tokensgetICRC1Balance(ledgerId)``Result<Nat, Text>smallest unitICRC-1 (for addr)getICRC1BalanceFor(principal, ledgerId)``Result<Nat, Text>smallest unitICRC-1 infogetICRC1TokenInfo(ledgerId)``Result<TokenInfo, Text>name, symbol, decimalsICP tokens listgetSupportedICPTokens()``[{name,symbol,canisterId,type_,category}]queryTRC-20 tokensgetMyTrc20Balance(contract)``Result<Nat, Text>smallest unit
Batch: getAllBalances() — parallel fetch across all chains.
Performance tip: For high-frequency reads, query chain RPCs directly using cached addresses. MeneseSDK is best for signing; your own RPC is faster for reads.
motoko
// Example: check SOL balance, convert to human-readable
switch (await menese.getMySolanaBalance()) {
case (#ok(lamports)) { /* lamports / 1_000_000_000 = SOL */ };
case (#err(e)) { /* handle error */ };
};
Return types differ by chain — getting this wrong causes runtime errors.
ChainFunctionParamsReturnSolanasendSolTransaction``(to, lamports:Nat64)``Result<Text, Text>ICPsendICP``(to:Principal, e8s:Nat64)``Result<SendICPResult, Text>ICRC-1sendICRC1``(to:Principal, amount:Nat, ledger:Text)``Result<SendICRC1Result, Text>BitcoinsendBitcoin``(to, sats:Nat64)``Result<SendResultBtcLtc, Text>LitecoinsendLitecoin``(to, litoshis:Nat64)``Result<SendResult, Text> (NOT BtcLtc!)EVMsendEvmNativeTokenAutonomous``(to, wei:Nat, rpc, chainId:Nat, ?quoteId)``Result<SendResultEvm, Text>XRPsendXrpAutonomous``(to, amountXrp:Text, ?destTag:Nat32)FLAT SendResultXrpSUIsendSui``(to, mist:Nat64)``Result<SendResult, Text>TONsendTonSimple``(to, nanotons:Nat64)FLAT SendResultTonAptossendAptos``(to, octas:Nat64)``Result<SendResult, Text>NEARsendNearTransfer``(to, yocto:Nat)``Result<Text, Text>TronsendTrx``(to, sun:Nat64)``Result<Text, Text>CardanosendCardanoTransaction``(to, lovelace:Nat64)``Result<Text, Text>CloakCoinsendCloak``(to, amount:Nat64)``Result<SendResultCloak, Text>THORChainsendThor``(to, amount:Nat64, memo:Text)``Result<Text, Text>SPL TokentransferSplToken``(amount:Nat64, srcAta, dstAta)``TransferAndSendResultXRP IOUsendXrpIOU``(dest, currency, issuer, amount, ?tag)``SendResultXrpTRC-20sendTrc20``(contract, to, amount:Nat, feeLimit:Nat64)``Result<Text, Text>
Variant extras: sendBitcoinDynamicFee, sendBitcoinWithFee, sendLitecoinWithFee, sendSuiMax, sendTon (with bounce/comment), sendTonWithComment.
motoko
// Example: send 0.5 SOL
switch (await menese.sendSolTransaction("5xK2abc...", 500_000_000)) {
case (#ok(txHash)) { /* success — txHash is the Solana TX signature */ };
case (#err(e)) { /* handle error */ };
};
// Example: send XRP (FLAT return — check .success, not #ok)
let r = await menese.sendXrpAutonomous("rDestAddr...", "10.5", null);
if (r.success) { /* r.txHash, r.explorerUrl */ }
else { /* r.message has error */ };
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.
OperationFunctionParamsReturnApprove spenderapproveICRC2``(spender:Principal, amount:Nat, expiresAt:?Nat64, ledgerId:Text)``Result<ApproveResult, Text>Check allowancegetICRC2Allowance``(owner:Principal, spender:Principal, ledgerId:Text)``Result<Allowance, Text> — FREETransferFromtransferFromICRC2``(from:Principal, to:Principal, amount:Nat, ledgerId:Text)``Result<TransferFromResult, Text>motoko
// Approve MeneseSDK canister to spend 100 ckUSDC on your behalf
let ckUSDC = "xevnm-gaaaa-aaaar-qafnq-cai";
let sdk = Principal.fromText("urs2a-ziaaa-aaaad-aembq-cai");
let r = await menese.approveICRC2(sdk, 100_000_000, null, ckUSDC); // 100 ckUSDC (6 dec)
// Check remaining allowance (FREE)
let allowance = await menese.getICRC2Allowance(myPrincipal, sdk, ckUSDC);
// Transfer from (requires prior approval)
let t = await menese.transferFromICRC2(userPrincipal, treasuryPrincipal, 50_000_000, ckUSDC);
DEXChainFunctionKey DetailsRaydiumSolanaswapRaydiumApiUser8 params, FLAT returnUniswap V3EVMswapTokens, swapTokensMultiHopPass quoteId or rpc+chainIdUniswap shortcutsEVMswapETHForUSDC, swapUSDCForETHQuick ETH↔USDCICPSwap/KongSwapICPexecuteICPDexSwap(SwapRequest)Auto-routes best priceCetusSUIexecuteSuiSwap(network, from, to, amountIn, minOut)Network: #mainnetMinswapCardanoexecuteMinswapSwap(tokenIn, tokenOut, amount, slippage)Float slippage %XRP DEXXRPxrpSwap(destAmount, sendMax, paths, slipBps)Use xrpFindPaths first
Always get a quote first (FREE):
getRaydiumQuote(inputMint, outputMint, amount, slipBps)getTokenQuote(from, to, amountIn, rpc)getICPDexQuote(tokenIn, tokenOut, amountIn, slipPct) → AggregatedQuote (compares ICPSwap vs KongSwap)getSuiSwapQuote(network, from, to, amountIn, slipBps)getMinswapQuote(tokenIn, tokenOut, amountIn, slipPct)xrpFindPaths(destAmount, sourceCurrencies)motoko
// Example: swap 1 SOL → USDC on Raydium
let SOL = "So11111111111111111111111111111111111111112";
let USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
let result = await menese.swapRaydiumApiUser(
SOL, USDC,
1_000_000_000, // 1 SOL in lamports
150, // 1.5% slippage
true, // wrapSol: input is native SOL
false, // unwrapSol: output is USDC not SOL
null, null // auto-detect ATAs
);
// FLAT record — access directly:
// result.txSignature, result.outputAmount, result.priceImpactPct
motoko
// Example: swap on ICP DEX (auto-routes to ICPSwap or KongSwap)
let swapReq : Menese.SwapRequest = {
tokenIn = "ryjl3-tyaaa-aaaaa-aaaba-cai"; // ICP ledger
tokenOut = "mxzaz-hqaaa-aaaar-qaada-cai"; // ckUSDC
amountIn = 100_000_000; // 1 ICP
minAmountOut = 0;
slippagePct = 1.0;
preferredDex = null; // auto-pick best price
};
let result = await menese.executeICPDexSwap(swapReq);
DirectionFunctionParamsETH→SOLquickUltrafastEthToSol``(ethWei:Nat)USDC→SOLquickUltrafastUsdcToSol``(usdc:Nat)ETH→TokenquickUltrafastEthToToken``(ethWei:Nat, outputMint, slipBps:Nat)SOL→ETHquickSolToEth``(solLamports:Nat64, slipBps:Nat)USDC SOL→ETHquickUsdcBridgeSolToEth``(usdc:Nat64)CCTP (any)quickCctpBridge``(srcChainId, usdc, outputToken, fast, slipBps, ethRpc)motoko
// Example: bridge 0.1 ETH to Solana
let result = await menese.quickUltrafastEthToSol(100_000_000_000_000_000); // 0.1 ETH in wei
// Result<Text, Text> — ok = status text
OperationFunctionParamsSupply ETHaaveSupplyEth``(wei:Nat, rpc, ?quoteId) → Result<SupplyEthResult, Text>Withdraw ETHaaveWithdrawEth``(wei:Nat, rpc, ?quoteId) → Result<WithdrawEthResult, Text>Supply ERC-20aaveSupplyToken``(tokenAddr, amount:Nat, rpc, ?quoteId)Withdraw ERC-20aaveWithdrawToken``(tokenAddr, amount:Nat, rpc, ?quoteId)Read aWETH balgetAWethBalance``(user, rpc) → FREERead aToken balgetATokenBalance``(aTokenAddr, user, rpc) → FREEmotoko
// 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 */ };
};
OperationFunctionReturnStake ETH→stETHstakeEthForStEth(wei, rpc, ?quoteId)``Result<StakeResult, Text>Wrap stETH→wstETHwrapStEth(amount, rpc, ?quoteId)``Result<WrapResult, Text>Unwrap wstETH→stETHunwrapWstEth(amount, rpc, ?quoteId)``Result<UnwrapResult, Text>Read stETH balgetStEthBalance(user, rpc)FREERead wstETH balgetWstEthBalance(user, rpc)FREEmotoko
// 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);
OperationFunctionAdd ETH+Token LPaddLiquidityETH(tokenSymbol, tokenAmt, ethAmt, slipBps, rpc, ?quoteId)Add Token+Token LPaddLiquidity(tokenA, tokenB, amtA, amtB, slipBps, rpc, ?quoteId)Remove ETH LPremoveLiquidityETH(tokenSymbol, lpAmt, slipBps, feeOnTransfer, rpc, ?quoteId)Remove Token LPremoveLiquidity(tokenA, tokenB, lpAmt, slipBps, rpc, ?quoteId)Read reservesgetPoolReserves(tokenA, tokenB, rpc) — FREEGet pair addrgetPairAddress(tokenA, tokenB, rpc) — FREE
OperationFunctionCostRead (view)callEvmContractRead(contract, selector4byte, argsHexes, rpc)FREEWrite (tx)callEvmContractWrite(contract, selector, args, rpc, chainId, value, ?quoteId)$0.10
Selector = first 4 bytes of keccak256("functionName(type1,type2)"), hex-encoded, no 0x prefix.
motoko
// Read Chainlink ETH/USD price (FREE)
let result = await menese.callEvmContractRead(
"0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", // ETH/USD feed
"feaf968c", // latestRoundData()
[], ethRpc
);
OperationFunctionCostCreate ruleaddStrategyRule(Rule)FREEList rulesgetMyStrategyRules()FREEUpdate statusupdateStrategyRuleStatus(ruleId, status)FREEDelete ruledeleteStrategyRule(ruleId)FREEView logsgetStrategyLogs()FREEInit automationinitAutomation()FREE
Rule types: #DCA, #StopLoss, #TakeProfit, #Rebalance, #Scheduled, #APYMigration, #LiquidityProvision, #VolatilityTrigger.
Rule statuses: #Active, #Paused, #Cancelled, #Executed, #Executing, #Failed, #Draft, #Confirmed, #Ready.
OperationFunctionCostCreate Solana ATAcreateMySolanaAtaForMint(mint, ata)Send pricingCreate ATA (custom program)createMySolanaAtaForMintWithProgram(mint, ata, programId)Send pricingSet XRP trustlinexrpSetTrustline(currency, issuer, limit)Send pricingRead XRP trustlinesxrpGetAccountLines()FREEGet Solana ATAgetMySolanaAta(mint)FREE
OperationFunctionCostRegister canisterregisterDeveloperCanister(Principal, appName)FREEGet dev keygetMyDeveloperKey()FREERegenerate keyregenerateDeveloperKey()FREEValidate keyvalidateDeveloperKey(key)FREECheck accountgetMyGatewayAccount() → UserAccountFREECheck dev accountgetMyDeveloperAccount() → ?DeveloperAccountV3FREEDeposit creditsdepositGatewayCredits(currency, amount)ICP cost
OperationFunctionCostBTC max sendgetBitcoinMaxSendAmount(?feeRate) → {maxAmount, fee, utxoCount}FREELTC max sendgetLitecoinMaxSendAmount(?feeRate) → {maxAmount, fee, utxoCount}FREEHealth checkhealth()FREEVersionversion()FREE
Manage liquidity positions on ICPSwap and KongSwap. The SDK aggregates both DEXes.
OperationFunctionCostList poolsgetICPDexPools() → [PoolInfo]FREEList tokensgetICPDexTokens() → [DexToken]FREEView positionsgetICPLPPositions() → [LPPosition]FREEAdd liquidityaddICPLiquidity(AddLiquidityRequest) → Result<AddLiquidityResult, Text>$0.10Remove liquidityremoveICPLiquidity(RemoveLiquidityRequest) → Result<RemoveLiquidityResult, Text>$0.10
Types:
text
AddLiquidityRequest = { poolId:Text, dex:{#ICPSwap|#KongSwap}, token0:Text, token1:Text, token0Amount:Nat, token1Amount:Nat, slippagePct:Float }
RemoveLiquidityRequest = { poolId:Text, dex:{#ICPSwap|#KongSwap}, lpTokens:Nat, slippagePct:Float }
LPPosition = { poolId, dex, token0, token1, token0Symbol, token1Symbol, liquidity:Nat, token0Amount, token1Amount, unclaimedFees:?(Nat,Nat), valueUsd:?Nat }
PoolInfo = { poolId, dex, token0, token1, token0Symbol, token1Symbol, reserve0, reserve1, fee, tvl:?Nat, apr:?Float, volume24h:?Nat }
DexToken = { canisterId, symbol, name, decimals:Nat8, fee:Nat, standard:{#ICRC1|#ICRC2|#DIP20}, logo:?Text, category:?Text, availableOn:[DexId] }
Well-known pools: ICP/ckUSDC, ckBTC/ICP, ICP/ckETH, ckUSDT/ckUSDC, CHAT/ICP (on both ICPSwap and KongSwap).
motoko
// Discover pools, then add liquidity
let pools = await menese.getICPDexPools();
// Find ICP/ckUSDC pool
let pool = Array.find<DexTypes.PoolInfo>(pools, func(p) { p.token0Symbol == "ICP" and p.token1Symbol == "ckUSDC" });
switch (pool) {
case (?p) {
let req : DexTypes.AddLiquidityRequest = {
poolId = p.poolId;
dex = p.dex;
token0 = "ryjl3-tyaaa-aaaaa-aaaba-cai"; // ICP ledger
token1 = "xevnm-gaaaa-aaaar-qafnq-cai"; // ckUSDC
token0Amount = 100_000_000; // 1 ICP
token1Amount = 10_000_000; // 10 ckUSDC
slippagePct = 1.0;
};
let result = await menese.addICPLiquidity(req);
};
case null { /* pool not found */ };
};
// View positions
let positions = await menese.getICPLPPositions();
// Remove liquidity
let removeReq : DexTypes.RemoveLiquidityRequest = {
poolId = positions[0].poolId;
dex = positions[0].dex;
lpTokens = positions[0].liquidity; // Remove all
slippagePct = 1.0;
};
let removed = await menese.removeICPLiquidity(removeReq);
AI-powered portfolio rebalancing recommendations using Herfindahl-Hirschman Index diversification scoring, impermanent loss estimation, and risk-adjusted APY analysis.
OperationFunctionCostGet recommendationsgetICPRebalanceRecommendations(preferences, tokenBalances, pools?) → [RebalanceRecommendation]FREE
Types:
text
RebalancePreferences = { targetCategories:[Text], riskTolerance:Text, minApy:?Float, maxImpermanentLoss:?Float, autoCompound:Bool }
targetCategories: ["stablecoin", "defi", "lst", "yield", "wrapped", "meme", "ecosystem"]
riskTolerance: "conservative" | "moderate" | "aggressive"
RebalanceRecommendation = { id, action:{#Swap|#AddLiquidity|#RemoveLiquidity|#Compound}, fromToken, toToken, fromSymbol, toSymbol, amount:Nat, reason:Text, estimatedApy:?Float, currentApy:?Float, impermanentLossRisk:{#Low|#Medium|#High}, confidence:Float, estimatedGasUsd:?Float }
motoko
// Get rebalancing recommendations for your ICP portfolio
let prefs : DexTypes.RebalancePreferences = {
targetCategories = ["stablecoin", "defi", "lst"];
riskTolerance = "moderate";
minApy = ?5.0; // Only suggest >5% APY
maxImpermanentLoss = ?10.0; // Max 10% IL risk
autoCompound = true;
};
// Pass current balances: [(canisterId, amount)]
let balances = [
("ryjl3-tyaaa-aaaaa-aaaba-cai", 500_000_000), // 5 ICP
("xevnm-gaaaa-aaaar-qafnq-cai", 100_000_000), // 100 ckUSDC
("mxzaz-hqaaa-aaaar-qaada-cai", 50_000), // 0.0005 ckBTC
];
let recommendations = await menese.getICPRebalanceRecommendations(prefs, balances, null);
for (rec in recommendations.vals()) {
Debug.print(rec.reason # " | Confidence: " # Float.toText(rec.confidence));
// e.g., "Swap 2 ICP → ckUSDC and add to ICP/ckUSDC pool for 12.5% APY | Confidence: 0.85"
};
The real power is combining these tools. Below are complete patterns showing how tools work together.
Buy USDC with SOL every hour if balance exceeds threshold.
motoko
// Tools used: getMySolanaBalance (FREE) + swapRaydiumApiUser ($0.075)
func dcaCycle() : async () {
let balance = switch (await menese.getMySolanaBalance()) {
case (#ok(v)) v; case (#err(_)) return;
};
if (balance < 500_000_000) return; // < 0.5 SOL, skip
let swapAmt = balance - 50_000_000; // Keep 0.05 SOL for rent
let _ = await menese.swapRaydiumApiUser(
"So11111111111111111111111111111111111111112", // SOL
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
swapAmt, 150, true, false, null, null
);
};
// Run every hour
let timerId = Timer.recurringTimer<system>(#seconds(3600), dcaCycle);
Set a stop-loss rule that auto-sells when price drops. No timer needed — MeneseSDK evaluates.
motoko
// Tool used: addStrategyRule (FREE to create, execution costs per action)
let rule : Menese.Rule = {
id = 0;
ruleType = #StopLoss;
status = #Active;
chainType = #Solana;
triggerPrice = 120_000_000; // Trigger at this price level
sizePct = 100; // Sell 100% of position
positionId = 0;
createdAt = Time.now();
dcaConfig = null; lpConfig = null; scheduledConfig = null;
apyMigrationConfig = null; volatilityConfig = null;
swapAmountLamports = ?1_000_000_000; // 1 SOL
swapAmountWei = null;
};
let ruleId = await menese.addStrategyRule(rule);
Set both on the same position — whichever triggers first wins.
motoko
// Tools: addStrategyRule × 2
// Take-profit at 200
let tp : Menese.Rule = { /* ... */ ruleType = #TakeProfit; triggerPrice = 200_000_000; sizePct = 50; /* sell half */ /* ... */ };
let tpId = await menese.addStrategyRule(tp);
// Stop-loss at 100
let sl : Menese.Rule = { /* ... */ ruleType = #StopLoss; triggerPrice = 100_000_000; sizePct = 100; /* sell all */ /* ... */ };
let slId = await menese.addStrategyRule(sl);
// When one triggers, cancel the other
// Check via getMyStrategyRules() or getStrategyLogs() in your timer
Let MeneseSDK handle the scheduling internally.
motoko
// Tool: addStrategyRule with DCA config
let dca : Menese.Rule = {
id = 0;
ruleType = #DCA;
status = #Active;
chainType = #Solana;
triggerPrice = 0; sizePct = 100; positionId = 0;
createdAt = Time.now();
dcaConfig = ?{
amountPerInterval = 100_000_000; // 0.1 SOL per buy
currentInterval = 0;
intervalSeconds = 3600; // Every hour
lastExecutedAt = 0;
maxIntervals = 168; // Run for 1 week (168 hours)
targetToken = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"; // Buy USDC
totalSpent = 0;
};
lpConfig = null; scheduledConfig = null;
apyMigrationConfig = null; volatilityConfig = null;
swapAmountLamports = ?100_000_000;
swapAmountWei = null;
};
ignore await menese.addStrategyRule(dca);
Check all balances, sweep any above threshold to treasury.
motoko
// Tools: getAllBalances (FREE) + sendSolTransaction + sendICP + sendEvmNativeTokenAutonomous
func sweepCycle() : async () {
let bals = await menese.getAllBalances();
// Sweep SOL if > 1 SOL
switch (bals.solana) {
case (#ok(lamports)) {
if (lamports > 1_000_000_000) {
ignore await menese.sendSolTransaction(solTreasury, lamports - 50_000_000);
};
};
case (#err(_)) {};
};
// Sweep ICP if > 1 ICP
switch (bals.icp) {
case (#ok(e8s)) {
if (e8s > 100_000_000) {
ignore await menese.sendICP(Principal.fromText(icpTreasury), e8s - 100_000);
};
};
case (#err(_)) {};
};
// Sweep ETH if > 0.1 ETH
switch (await menese.getMyEvmBalance(ethRpc)) {
case (#ok(wei)) {
if (wei > 100_000_000_000_000_000) {
ignore await menese.sendEvmNativeTokenAutonomous(
ethTreasury, wei - 50_000_000_000_000_000, ethRpc, 1, null
);
};
};
case (#err(_)) {};
};
};
Allocate idle ETH across DeFi protocols on a timer.
motoko
// Tools: getMyEvmBalance + getAWethBalance + getStEthBalance (all FREE)
// + aaveSupplyEth + stakeEthForStEth + wrapStEth ($0.10 each)
func rebalanceCycle() : async () {
let evmAddr = (await menese.getMyEvmAddress()).evmAddress; // Cached ideally
let ethBal = switch (await menese.getMyEvmBalance(ethRpc)) { case (#ok(v)) v; case _ 0 };
let aaveBal = switch (await menese.getAWethBalance(evmAddr, ethRpc)) { case (#ok(v)) v; case _ 0 };
let lidoBal = switch (await menese.getStEthBalance(evmAddr, ethRpc)) { case (#ok(v)) v; case _ 0 };
let reserve = 50_000_000_000_000_000; // 0.05 ETH for gas
if (ethBal <= reserve) return;
let deployable = ethBal - reserve;
// 50% Aave, 50% Lido
let aaveTarget = deployable / 2;
let lidoTarget = deployable / 2;
if (aaveTarget > aaveBal and aaveTarget - aaveBal > 10_000_000_000_000_000) {
ignore await menese.aaveSupplyEth(aaveTarget - aaveBal, ethRpc, null);
};
if (lidoTarget > lidoBal and lidoTarget - lidoBal > 10_000_000_000_000_000) {
ignore await menese.stakeEthForStEth(lidoTarget - lidoBal, ethRpc, null);
ignore await menese.wrapStEth(lidoTarget - lidoBal, ethRpc, null);
};
};
// Run every 6 hours
let timerId = Timer.recurringTimer<system>(#seconds(21600), rebalanceCycle);
Move funds between Ethereum and Solana to capture price differences.
motoko
// Tools: getTokenQuote (FREE) + getRaydiumQuote (FREE)
// + quickUltrafastEthToSol ($0.10) + swapRaydiumApiUser ($0.075)
// 1. Check ETH USDC price on Uniswap
let ethQuote = await menese.getTokenQuote("USDC", "WETH", 1000_000_000, ethRpc);
// 2. Check SOL USDC price on Raydium
let solQuote = await menese.getRaydiumQuote(USDC_MINT, SOL_MINT, 1000_000_000, 100);
// 3. If profitable, bridge and swap
// Bridge ETH → SOL: quickUltrafastEthToSol
// Swap on Raydium: swapRaydiumApiUser
// Bridge back: quickSolToEth
Accept payments and auto-sweep to treasury.
motoko
// Tools: getMySolanaAddress (FREE, cached) + getMySolanaBalance (FREE)
// + sendSolTransaction ($0.05)
// 1. Show payment address to customer (from cache)
let payAddr = cachedAddresses.solana;
// 2. Periodically check if payment arrived (FREE)
let bal = switch (await menese.getMySolanaBalance()) { case (#ok(v)) v; case _ 0 };
if (bal >= invoiceAmount) {
// 3. Mark paid, sweep to treasury
ignore await menese.sendSolTransaction(treasury, bal - 50_000_000);
};
Use #Scheduled rule type for time-based operations without custom timers.
motoko
let weekly : Menese.Rule = {
id = 0;
ruleType = #Scheduled;
status = #Active;
chainType = #Solana;
triggerPrice = 0; sizePct = 100; positionId = 0;
createdAt = Time.now();
dcaConfig = null;
scheduledConfig = ?{}; // SDK handles scheduling details
lpConfig = null; apyMigrationConfig = null; volatilityConfig = null;
swapAmountLamports = ?500_000_000; // 0.5 SOL
swapAmountWei = null;
};
ignore await menese.addStrategyRule(weekly);
Use #VolatilityTrigger or custom timer with price feeds.
motoko
// Strategy engine approach:
let volRule : Menese.Rule = {
id = 0;
ruleType = #VolatilityTrigger;
status = #Active;
chainType = #EVM;
triggerPrice = 0; sizePct = 50; positionId = 0;
createdAt = Time.now();
dcaConfig = null; lpConfig = null; scheduledConfig = null;
apyMigrationConfig = null;
volatilityConfig = ?{}; // SDK evaluates volatility conditions
swapAmountLamports = null;
swapAmountWei = ?500_000_000_000_000_000; // 0.5 ETH
};
// Custom approach: read Chainlink price feed + react
func checkVolatility() : async () {
let price = await menese.callEvmContractRead(
"0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419", // ETH/USD Chainlink
"feaf968c", [], ethRpc
);
// Parse price, compare to threshold, execute swap if needed
};
ChainUnitDecimals1 Token =Solanalamports91,000,000,000ICPe8s8100,000,000Bitcoinsatoshis8100,000,000Litecoinlitoshis8100,000,000EVMwei1810^18XRPdrops (Text)6"1.0"SUImist91,000,000,000TONnanotons91,000,000,000Cardanolovelace61,000,000Aptosoctas8100,000,000NEARyoctoNEAR2410^24Tronsun61,000,000CloakCoinunits61,000,000THORChainunits8100,000,000
evmAddress not address, suiAddress not address, nonBounceable not address, implicitAccountId not accountId, base58Address not base58.success). Raydium swap also returns FLAT. Everything else uses Result<T, Text> with #ok/#err.SendResult ( .txHash), Bitcoin = SendResultBtcLtc ( .txid + .fee)"1.5" not 1500000OperationClient ModeAgent ModeAddresses/Balances/QuotesFREEFREEStrategy rule CRUDFREEFREESend/Transfer$0.05$0.10DEX Swap$0.075$0.15Bridge$0.10$0.20DeFi (Aave/Lido/LP/Custom)—$0.10TierPriceActions/MonthFree$05 (lifetime)Developer$35/mo1,000Pro$99/mo5,000Enterprise$249/moUnlimited
FilePurposeSKILL.mdThis guide — all tools, examples, best practicesWalletBot.moICP canister wrapping MeneseSDK (production use)scripts/wallet_commands.pyPython CLI for dfx calls (prototyping/testing)references/api-surface.mdFull API — every type definition and function signaturereferences/automation.mdDeep dive — timer bots, DeFi yield, strategy patterns, custom contracts