Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Generate Privy wallet security policy rules from natural language and submit them for on-chain user approval.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
exports.py
1"""2Wallet skill exports — for use in task scripts via core.skill_tools.34Usage:5from core.skill_tools import wallet6info = wallet.wallet_info()7bal = wallet.wallet_balance(chain="base")8all_bal = wallet.wallet_get_all_balances()910Delegates to /app/tools/wallet core functions for single-source maintenance.11"""1213import asyncio1415try:16import nest_asyncio17nest_asyncio.apply()18except ImportError:19pass2021# Import core functions from /app/tools/wallet22from tools.wallet import (23_wallet_request,24_is_fly_machine,25_get_wallet_addresses,26_validate_and_clean_rules,27DEBANK_CHAIN_MAP,28)29from core.http_client import proxied_get3031EVM_CHAINS = list(DEBANK_CHAIN_MAP.keys())323334def _run(coro):35"""Run async in sync context (works even if event loop is running)."""36try:37loop = asyncio.get_event_loop()38return loop.run_until_complete(coro)39except RuntimeError:40return asyncio.run(coro)414243# ── Info ─────────────────────────────────────────────────────────────────────4445def wallet_info():46"""Get all wallet addresses."""47return _run(_wallet_request("GET", "/agent/wallet"))484950# ── Balances ─────────────────────────────────────────────────────────────────5152def wallet_balance(chain: str, address: str = "", asset: str = ""):53"""Get EVM balance on a chain (via DeBank or wallet-service fallback)."""54import os55async def _impl():56if chain not in EVM_CHAINS:57return {"error": f"Invalid chain '{chain}'. Must be one of: {', '.join(EVM_CHAINS)}"}58debank_key = os.environ.get("DEBANK_API_KEY", "")59if debank_key:60evm_address = address61if not evm_address:62addrs = await _get_wallet_addresses()63evm_address = addrs.get("evm", "")64if not evm_address:65return {"error": "Could not determine EVM wallet address"}66resp = proxied_get(67"https://pro-openapi.debank.com/v1/user/token_list",68params={"id": evm_address, "chain_id": DEBANK_CHAIN_MAP.get(chain), "is_all": "false"},69headers={"AccessKey": debank_key},70)71resp.raise_for_status()72return {"address": evm_address, "chain": chain, "tokens": resp.json(), "source": "debank"}73else:74params = [f"chain_type=ethereum&chain={chain}"]75if asset: params.append(f"asset={asset}")76return await _wallet_request("GET", f"/agent/balance?{'&'.join(params)}")77return _run(_impl())787980def wallet_sol_balance(address: str = "", asset: str = ""):81"""Get Solana balance."""82import os83async def _impl():84birdeye_key = os.environ.get("BIRDEYE_API_KEY", "")85if birdeye_key:86sol_address = address87if not sol_address:88addrs = await _get_wallet_addresses()89sol_address = addrs.get("sol", "")90if not sol_address:91return {"error": "Could not determine Solana wallet address"}92resp = proxied_get(93"https://public-api.birdeye.so/wallet/v2/net-worth",94params={"wallet": sol_address},95headers={"X-API-KEY": birdeye_key, "x-chain": "solana", "accept": "application/json"},96)97resp.raise_for_status()98return {"address": sol_address, "source": "birdeye", "data": resp.json()}99else:100params = ["chain_type=solana"]101if asset: params.append(f"asset={asset}")102return await _wallet_request("GET", f"/agent/balance?{'&'.join(params)}")103return _run(_impl())104105106def wallet_get_all_balances(evm_address: str = "", sol_address: str = ""):107"""Get balances across all chains."""108async def _impl():109ea, sa = evm_address, sol_address110if not ea or not sa:111if _is_fly_machine():112try:113addrs = await _get_wallet_addresses()114ea = ea or addrs.get("evm", "")115sa = sa or addrs.get("sol", "")116except Exception:117pass118# Delegate to per-chain balance calls119result = {}120if ea:121for chain in EVM_CHAINS:122try:123data = wallet_balance(chain, ea)124if "error" not in data:125result[chain] = data126except Exception:127pass128if sa:129try:130data = wallet_sol_balance(sa)131if "error" not in data:132result["solana"] = data133except Exception:134pass135return result136return _run(_impl())137138139# ── Transfers ────────────────────────────────────────────────────────────────140141def wallet_transfer(to, amount, chain_id=1, data="", **kw):142"""Sign and broadcast EVM tx."""143async def _impl():144body = {"to": to, "amount": str(amount), "chain_id": chain_id}145if data: body["data"] = data146for k in ("gas_limit", "gas_price", "max_fee_per_gas", "max_priority_fee_per_gas", "nonce"):147if kw.get(k): body[k] = kw[k]148if kw.get("tx_type") is not None: body["tx_type"] = kw["tx_type"]149return await _wallet_request("POST", "/agent/transfer", body)150return _run(_impl())151152153def wallet_sign_transaction(to, amount, chain_id=1, data="", **kw):154"""Sign EVM tx without broadcasting."""155async def _impl():156body = {"to": to, "amount": str(amount), "chain_id": chain_id}157if data: body["data"] = data158for k in ("gas_limit", "gas_price", "max_fee_per_gas", "max_priority_fee_per_gas", "nonce"):159if kw.get(k): body[k] = kw[k]160if kw.get("tx_type") is not None: body["tx_type"] = kw["tx_type"]161return await _wallet_request("POST", "/agent/sign-transaction", body)162return _run(_impl())163164165def wallet_sign(message):166"""EIP-191 personal_sign."""167return _run(_wallet_request("POST", "/agent/sign", {"message": message}))168169170def wallet_sign_typed_data(domain, types, primaryType, message):171"""Sign EIP-712 typed data."""172return _run(_wallet_request("POST", "/agent/sign-typed-data", {173"domain": domain, "types": types, "primaryType": primaryType, "message": message,174}))175176177def wallet_transactions(chain="ethereum", asset="", limit=20):178"""EVM tx history."""179qs = f"?chain_type=ethereum&chain={chain}&asset={asset or 'eth'}&limit={limit}"180return _run(_wallet_request("GET", f"/agent/transactions{qs}"))181182183# ── Solana ───────────────────────────────────────────────────────────────────184185def wallet_sol_transfer(transaction, caip2="solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"):186"""Sign and broadcast Solana tx."""187return _run(_wallet_request("POST", "/agent/sol/transfer", {188"transaction": transaction, "caip2": caip2,189}))190191192def wallet_sol_sign_transaction(transaction):193"""Sign Solana tx without broadcasting."""194return _run(_wallet_request("POST", "/agent/sol/sign-transaction", {"transaction": transaction}))195196197def wallet_sol_sign(message):198"""Sign message with Solana wallet."""199return _run(_wallet_request("POST", "/agent/sol/sign", {"message": message}))200201202def wallet_sol_transactions(chain="solana", asset="sol", limit=20):203"""Solana tx history."""204qs = f"?chain_type=solana&chain={chain}&asset={asset}&limit={limit}"205return _run(_wallet_request("GET", f"/agent/transactions{qs}"))206207208# ── Policy ───────────────────────────────────────────────────────────────────209210def wallet_get_policy(chain_type="ethereum"):211"""Get current policy status."""212return _run(_wallet_request("GET", f"/agent/policy?chain_type={chain_type}"))213214215def validate_and_clean_rules(rules, chain_type):216"""Validate rules (re-export from system)."""217return _validate_and_clean_rules(rules, chain_type)218