-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.py
More file actions
122 lines (93 loc) · 3.64 KB
/
cli.py
File metadata and controls
122 lines (93 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""Simple CLI for Axon vault payments.
Usage:
python cli.py pay <to> <token> <amount> [--memo TEXT]
python cli.py balance [TOKEN]
python cli.py poll <request_id>
python cli.py status
"""
import argparse
import json
import os
import sys
from dotenv import load_dotenv
from axonfi import AxonClientSync, Chain, KNOWN_TOKENS, resolve_token
load_dotenv()
def _load_bot_key() -> str:
"""Load bot private key from env (raw hex) or keystore file + passphrase."""
raw_key = os.environ.get("AXON_BOT_PRIVATE_KEY")
if raw_key:
return raw_key
keystore_path = os.environ.get("AXON_BOT_KEYSTORE_PATH")
passphrase = os.environ.get("AXON_BOT_PASSPHRASE")
if keystore_path and passphrase:
from eth_account import Account
with open(keystore_path) as f:
keystore = json.load(f)
return "0x" + Account.decrypt(keystore, passphrase).hex()
print("Error: set AXON_BOT_PRIVATE_KEY or AXON_BOT_KEYSTORE_PATH + AXON_BOT_PASSPHRASE", file=sys.stderr)
sys.exit(1)
def get_client() -> AxonClientSync:
return AxonClientSync(
vault_address=os.environ["AXON_VAULT_ADDRESS"],
chain_id=int(os.environ.get("AXON_CHAIN_ID", str(Chain.BaseSepolia))),
bot_private_key=_load_bot_key(),
)
def cmd_pay(args):
client = get_client()
print(f"Paying {args.amount} {args.token} to {args.to}...")
result = client.pay(to=args.to, token=args.token, amount=float(args.amount), memo=args.memo)
print(f"Status: {result.status}")
if result.tx_hash:
print(f"TX: {result.tx_hash}")
if result.request_id:
print(f"Request ID: {result.request_id}")
if result.reason:
print(f"Reason: {result.reason}")
def cmd_balance(args):
client = get_client()
token = args.token or "USDC"
chain_id = int(os.environ.get("AXON_CHAIN_ID", str(Chain.BaseSepolia)))
token_address = resolve_token(token, chain_id)
balance_raw = client.get_balance(token_address)
info = KNOWN_TOKENS.get(token)
if info:
human = balance_raw / (10 ** info.decimals)
print(f"{human:.6f} {token}")
else:
print(f"{balance_raw} base units")
def cmd_poll(args):
client = get_client()
result = client.poll(args.request_id)
print(f"Status: {result.status}")
if result.tx_hash:
print(f"TX: {result.tx_hash}")
if result.reason:
print(f"Reason: {result.reason}")
def cmd_status(args):
client = get_client()
active = client.is_active()
paused = client.is_paused()
print(f"Bot: {client.bot_address}")
print(f"Active: {active}")
print(f"Vault paused: {paused}")
def main():
parser = argparse.ArgumentParser(description="Axon CLI payments")
sub = parser.add_subparsers(dest="command", required=True)
p_pay = sub.add_parser("pay", help="Send a payment")
p_pay.add_argument("to", help="Recipient address")
p_pay.add_argument("token", help="Token symbol (USDC, WETH, ...)")
p_pay.add_argument("amount", help="Amount (human-readable)")
p_pay.add_argument("--memo", default="", help="Payment memo")
p_pay.set_defaults(func=cmd_pay)
p_bal = sub.add_parser("balance", help="Check token balance")
p_bal.add_argument("token", nargs="?", default="USDC", help="Token symbol")
p_bal.set_defaults(func=cmd_balance)
p_poll = sub.add_parser("poll", help="Poll payment status")
p_poll.add_argument("request_id", help="Request ID to poll")
p_poll.set_defaults(func=cmd_poll)
p_status = sub.add_parser("status", help="Check bot and vault status")
p_status.set_defaults(func=cmd_status)
args = parser.parse_args()
args.func(args)
if __name__ == "__main__":
main()