Skip to content

Commit b021cfe

Browse files
authored
feat(hip-3-relayer): CLI commands for account management (#3307)
1 parent fffeab1 commit b021cfe

File tree

5 files changed

+177
-2
lines changed

5 files changed

+177
-2
lines changed

apps/hip-3-pusher/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "hip-3-pusher"
3-
version = "0.2.4"
3+
version = "0.2.5"
44
description = "Hyperliquid HIP-3 market oracle pusher"
55
readme = "README.md"
66
requires-python = "==3.13.*"
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import argparse
2+
from pathlib import Path
3+
4+
from eth_account import Account
5+
from hyperliquid.exchange import Exchange
6+
from hyperliquid.utils import constants
7+
from hyperliquid.utils.constants import MAINNET_API_URL
8+
from hyperliquid.utils.signing import get_timestamp_ms, sign_l1_action
9+
10+
11+
def reserve_request_weight(exchange: Exchange, weight: int):
12+
timestamp = get_timestamp_ms()
13+
reserve_action = {
14+
"type": "reserveRequestWeight",
15+
"weight": weight,
16+
}
17+
signature = sign_l1_action(
18+
exchange.wallet,
19+
reserve_action,
20+
exchange.vault_address,
21+
timestamp,
22+
exchange.expires_after,
23+
exchange.base_url == MAINNET_API_URL,
24+
)
25+
return exchange._post_action(
26+
reserve_action,
27+
signature,
28+
timestamp,
29+
)
30+
31+
32+
def main():
33+
parser = argparse.ArgumentParser(
34+
description="Reserve requests for a single account (0.0005 USDC per transaction)"
35+
)
36+
parser.add_argument(
37+
"--private-key-file",
38+
required=True,
39+
help="Path to private key file for account",
40+
)
41+
parser.add_argument(
42+
"--weight",
43+
type=int,
44+
required=True,
45+
help="request weight to reserve",
46+
)
47+
network = parser.add_mutually_exclusive_group(required=True)
48+
network.add_argument(
49+
"--testnet",
50+
action="store_true",
51+
help="Use testnet",
52+
)
53+
network.add_argument(
54+
"--mainnet",
55+
action="store_true",
56+
help="Use mainnet",
57+
)
58+
parser.add_argument(
59+
"--dry-run",
60+
action="store_true",
61+
help="Only show parameters without sending",
62+
)
63+
64+
args = parser.parse_args()
65+
66+
network = "testnet" if args.testnet else "mainnet"
67+
base_url = constants.TESTNET_API_URL if args.testnet else constants.MAINNET_API_URL
68+
print(f"Using {network} URL: {base_url}")
69+
70+
account = Account.from_key(Path(args.private_key_file).read_text().strip())
71+
exchange = Exchange(wallet=account, base_url=base_url)
72+
print("address:", account.address)
73+
weight = args.weight
74+
print("weight:", weight)
75+
76+
if args.dry_run:
77+
print(f"dry run: {network}: would reserve {weight} request weight for account {account.address}")
78+
else:
79+
print("calling reserveRequestWeight...")
80+
print(reserve_request_weight(exchange, weight))
81+
82+
83+
if __name__ == "__main__":
84+
main()
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import argparse
2+
from pathlib import Path
3+
4+
from eth_account import Account
5+
from hyperliquid.exchange import Exchange
6+
from hyperliquid.utils import constants
7+
8+
9+
def main():
10+
parser = argparse.ArgumentParser(
11+
description="Send USDC from one Hyperliquid account to another (at least 6 to activate new one)"
12+
)
13+
parser.add_argument(
14+
"--private-key-file",
15+
required=True,
16+
help="Path to private key file for account",
17+
)
18+
parser.add_argument(
19+
"--recipient-address",
20+
required=True,
21+
help="Recipient address",
22+
)
23+
parser.add_argument(
24+
"--amount",
25+
type=float,
26+
required=True,
27+
help="Amount to send in USDC",
28+
)
29+
network = parser.add_mutually_exclusive_group(required=True)
30+
network.add_argument(
31+
"--testnet",
32+
action="store_true",
33+
help="Use testnet",
34+
)
35+
network.add_argument(
36+
"--mainnet",
37+
action="store_true",
38+
help="Use mainnet",
39+
)
40+
parser.add_argument(
41+
"--dry-run",
42+
action="store_true",
43+
help="Only show parameters without sending",
44+
)
45+
46+
args = parser.parse_args()
47+
48+
network = "testnet" if args.testnet else "mainnet"
49+
base_url = constants.TESTNET_API_URL if args.testnet else constants.MAINNET_API_URL
50+
print(f"Using {network} URL: {base_url}")
51+
52+
sender_account = Account.from_key(Path(args.private_key_file).read_text().strip())
53+
sender_exchange = Exchange(wallet=sender_account, base_url=base_url)
54+
print("sender address:", sender_account.address)
55+
recipient_address = args.recipient_address
56+
print("recipient address:", recipient_address)
57+
amount = args.amount
58+
print("amount:", amount)
59+
60+
if args.dry_run:
61+
print(f"dry run: {network}: would send {amount} USDC from {sender_account.address} to {recipient_address}")
62+
else:
63+
print("calling usd_transfer...")
64+
print(sender_exchange.usd_transfer(amount=amount, destination=recipient_address))
65+
66+
67+
if __name__ == "__main__":
68+
main()
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import argparse
2+
3+
from eth_account import Account
4+
from pathlib import Path
5+
6+
7+
def main():
8+
parser = argparse.ArgumentParser(
9+
description="Print address of given private key"
10+
)
11+
parser.add_argument(
12+
"--private-key-file",
13+
required=True,
14+
help="Path to private key file",
15+
)
16+
17+
args = parser.parse_args()
18+
account = Account.from_key(Path(args.private_key_file).read_text().strip())
19+
print("address:", account.address)
20+
21+
22+
if __name__ == "__main__":
23+
main()

apps/hip-3-pusher/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)