tusdt-cli 0.2.5__tar.gz → 0.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/PKG-INFO +1 -1
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/pyproject.toml +1 -1
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/__init__.py +1 -1
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/client.py +95 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/commands/auction.py +340 -1
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/commands/governance.py +1 -3
- tusdt_cli-0.2.6/src/tusdt_cli/commands/token.py +538 -0
- tusdt_cli-0.2.5/src/tusdt_cli/commands/token.py +0 -245
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/.gitignore +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/LICENSE +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/README.md +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/requirements.txt +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/abi/tusdt_auction.json +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/abi/tusdt_erc20.json +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/abi/tusdt_governance.json +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/abi/tusdt_oracle.json +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/abi/tusdt_treasury.json +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/abi/tusdt_vault.json +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/cli.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/commands/__init__.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/commands/oracle.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/commands/treasury.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/commands/vault.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/config.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/utils.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/src/tusdt_cli/wallet.py +0 -0
- {tusdt_cli-0.2.5 → tusdt_cli-0.2.6}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tusdt-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: CLI for interacting with the TUSDT ink! smart contract system on subtensor(bittensor)
|
|
5
5
|
Project-URL: Homepage, https://github.com/tensorusd/tusdt-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/tensorusd/tusdt-cli
|
|
@@ -722,6 +722,37 @@ class TUSDTClient:
|
|
|
722
722
|
"""Transfer *amount* TUSDT tokens to *to*."""
|
|
723
723
|
return self._exec(self.token, keypair, "transfer", args={"to": to, "value": amount})
|
|
724
724
|
|
|
725
|
+
def token_controller(self, keypair: Keypair) -> str:
|
|
726
|
+
"""Return the controller address of the TUSDT token contract."""
|
|
727
|
+
result = self._read(self.token, keypair, "controller")
|
|
728
|
+
return unwrap_plain(result)
|
|
729
|
+
|
|
730
|
+
def token_mint(self, keypair: Keypair, to: str, amount: int) -> dict[str, Any]:
|
|
731
|
+
"""Mint *amount* TUSDT tokens to *to* (controller only)."""
|
|
732
|
+
return self._exec(self.token, keypair, "mint", args={"to": to, "value": amount})
|
|
733
|
+
|
|
734
|
+
def token_burn(self, keypair: Keypair, from_addr: str, amount: int) -> dict[str, Any]:
|
|
735
|
+
"""Burn *amount* TUSDT tokens from *from_addr* (controller only)."""
|
|
736
|
+
return self._exec(self.token, keypair, "burn", args={"from": from_addr, "value": amount})
|
|
737
|
+
|
|
738
|
+
def token_increase_allowance(self, keypair: Keypair, spender: str, delta: int) -> dict[str, Any]:
|
|
739
|
+
"""Increase *spender*'s allowance by *delta* TUSDT tokens."""
|
|
740
|
+
return self._exec(
|
|
741
|
+
self.token, keypair, "increase_allowance", args={"spender": spender, "delta_value": delta}
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
def token_decrease_allowance(self, keypair: Keypair, spender: str, delta: int) -> dict[str, Any]:
|
|
745
|
+
"""Decrease *spender*'s allowance by *delta* TUSDT tokens."""
|
|
746
|
+
return self._exec(
|
|
747
|
+
self.token, keypair, "decrease_allowance", args={"spender": spender, "delta_value": delta}
|
|
748
|
+
)
|
|
749
|
+
|
|
750
|
+
def token_transfer_from(self, keypair: Keypair, from_addr: str, to: str, amount: int) -> dict[str, Any]:
|
|
751
|
+
"""Transfer *amount* TUSDT tokens from *from_addr* to *to* (requires allowance)."""
|
|
752
|
+
return self._exec(
|
|
753
|
+
self.token, keypair, "transfer_from", args={"from": from_addr, "to": to, "value": amount}
|
|
754
|
+
)
|
|
755
|
+
|
|
725
756
|
# ==================================================================
|
|
726
757
|
# AUCTION OPERATIONS
|
|
727
758
|
# ==================================================================
|
|
@@ -826,6 +857,70 @@ class TUSDTClient:
|
|
|
826
857
|
return None
|
|
827
858
|
return raw if isinstance(raw, dict) else raw
|
|
828
859
|
|
|
860
|
+
def get_auction_controller(self, keypair: Keypair) -> str:
|
|
861
|
+
"""Return the auction controller address."""
|
|
862
|
+
result = self._read(self.auction, keypair, "controller")
|
|
863
|
+
return unwrap_plain(result)
|
|
864
|
+
|
|
865
|
+
def get_auction_governance(self, keypair: Keypair) -> str:
|
|
866
|
+
"""Return the auction governance address."""
|
|
867
|
+
result = self._read(self.auction, keypair, "governance")
|
|
868
|
+
return unwrap_plain(result)
|
|
869
|
+
|
|
870
|
+
def get_auction_admin(self, keypair: Keypair) -> str | None:
|
|
871
|
+
"""Return the auction admin address, or None if not set."""
|
|
872
|
+
result = self._read(self.auction, keypair, "admin")
|
|
873
|
+
return unwrap_option(result)
|
|
874
|
+
|
|
875
|
+
def create_auction(
|
|
876
|
+
self,
|
|
877
|
+
keypair: Keypair,
|
|
878
|
+
vault_owner: str,
|
|
879
|
+
vault_id: int,
|
|
880
|
+
collateral_balance: int,
|
|
881
|
+
debt_balance: int,
|
|
882
|
+
min_bid: int,
|
|
883
|
+
liquidation_price: int,
|
|
884
|
+
duration_ms: int,
|
|
885
|
+
) -> dict[str, Any]:
|
|
886
|
+
"""Create a new liquidation auction (controller only)."""
|
|
887
|
+
return self._exec(
|
|
888
|
+
self.auction,
|
|
889
|
+
keypair,
|
|
890
|
+
"create_auction",
|
|
891
|
+
args={
|
|
892
|
+
"vault_owner": vault_owner,
|
|
893
|
+
"vault_id": vault_id,
|
|
894
|
+
"collateral_balance": collateral_balance,
|
|
895
|
+
"debt_balance": debt_balance,
|
|
896
|
+
"min_bid": min_bid,
|
|
897
|
+
"liquidation_price": liquidation_price,
|
|
898
|
+
"duration_ms": duration_ms,
|
|
899
|
+
},
|
|
900
|
+
)
|
|
901
|
+
|
|
902
|
+
def auction_set_admin(self, keypair: Keypair, admin: str | None) -> dict[str, Any]:
|
|
903
|
+
"""Set or clear the auction admin (governance only). Pass None to clear."""
|
|
904
|
+
return self._exec(self.auction, keypair, "set_admin", args={"admin": admin})
|
|
905
|
+
|
|
906
|
+
def auction_update_governance(self, keypair: Keypair, new_governance: str) -> dict[str, Any]:
|
|
907
|
+
"""Transfer auction governance to a new account (controller only)."""
|
|
908
|
+
return self._exec(self.auction, keypair, "update_governance", args={"new_governance": new_governance})
|
|
909
|
+
|
|
910
|
+
def auction_transfer_winning_bid(
|
|
911
|
+
self,
|
|
912
|
+
keypair: Keypair,
|
|
913
|
+
auction_id: int,
|
|
914
|
+
recipient: str,
|
|
915
|
+
) -> dict[str, Any]:
|
|
916
|
+
"""Transfer the winning bid amount to a recipient (controller only)."""
|
|
917
|
+
return self._exec(
|
|
918
|
+
self.auction,
|
|
919
|
+
keypair,
|
|
920
|
+
"transfer_winning_bid",
|
|
921
|
+
args={"auction_id": auction_id, "recipient": recipient},
|
|
922
|
+
)
|
|
923
|
+
|
|
829
924
|
# ==================================================================
|
|
830
925
|
# ORACLE OPERATIONS
|
|
831
926
|
# ==================================================================
|
|
@@ -32,7 +32,18 @@ _wallet_option = click.option(
|
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
_AUCTION_ADVANCED = {
|
|
35
|
+
_AUCTION_ADVANCED = {
|
|
36
|
+
"list-all",
|
|
37
|
+
"total-count",
|
|
38
|
+
"vault-auction",
|
|
39
|
+
"bids",
|
|
40
|
+
"bid-info",
|
|
41
|
+
"create",
|
|
42
|
+
"set-admin",
|
|
43
|
+
"update-governance",
|
|
44
|
+
"transfer-winning-bid",
|
|
45
|
+
}
|
|
46
|
+
_AUCTION_BASIC_READS = {"controller", "governance", "admin-address"}
|
|
36
47
|
|
|
37
48
|
|
|
38
49
|
@click.group("auction", cls=ModeAwareGroup, advanced_commands=_AUCTION_ADVANCED)
|
|
@@ -605,3 +616,331 @@ def bid_info(ctx: click.Context, auction_id: int, bid_id: int, network: str | No
|
|
|
605
616
|
"Withdrawn": data.get("is_withdrawn", False),
|
|
606
617
|
},
|
|
607
618
|
)
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
# ------------------------------------------------------------------
|
|
622
|
+
# controller
|
|
623
|
+
# ------------------------------------------------------------------
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
@auction_group.command("controller")
|
|
627
|
+
@_network_option
|
|
628
|
+
@click.pass_context
|
|
629
|
+
def auction_controller_cmd(ctx: click.Context, network: str | None) -> None:
|
|
630
|
+
"""Show the controller address of the auction contract.
|
|
631
|
+
|
|
632
|
+
\b
|
|
633
|
+
Examples:
|
|
634
|
+
tusdt auction controller
|
|
635
|
+
tusdt auction controller --network testnet
|
|
636
|
+
"""
|
|
637
|
+
config = load_config(network=network)
|
|
638
|
+
|
|
639
|
+
try:
|
|
640
|
+
keypair = get_reader_keypair(config)
|
|
641
|
+
client = TUSDTClient(config)
|
|
642
|
+
addr = client.get_auction_controller(keypair)
|
|
643
|
+
except Exception as exc:
|
|
644
|
+
print_error(str(exc))
|
|
645
|
+
return
|
|
646
|
+
|
|
647
|
+
print_dict("Auction Controller", {"Address": addr})
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
# ------------------------------------------------------------------
|
|
651
|
+
# governance
|
|
652
|
+
# ------------------------------------------------------------------
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
@auction_group.command("governance")
|
|
656
|
+
@_network_option
|
|
657
|
+
@click.pass_context
|
|
658
|
+
def auction_governance_cmd(ctx: click.Context, network: str | None) -> None:
|
|
659
|
+
"""Show the governance address of the auction contract.
|
|
660
|
+
|
|
661
|
+
\b
|
|
662
|
+
Examples:
|
|
663
|
+
tusdt auction governance
|
|
664
|
+
tusdt auction governance --network testnet
|
|
665
|
+
"""
|
|
666
|
+
config = load_config(network=network)
|
|
667
|
+
|
|
668
|
+
try:
|
|
669
|
+
keypair = get_reader_keypair(config)
|
|
670
|
+
client = TUSDTClient(config)
|
|
671
|
+
addr = client.get_auction_governance(keypair)
|
|
672
|
+
except Exception as exc:
|
|
673
|
+
print_error(str(exc))
|
|
674
|
+
return
|
|
675
|
+
|
|
676
|
+
print_dict("Auction Governance", {"Address": addr})
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
# ------------------------------------------------------------------
|
|
680
|
+
# admin-address
|
|
681
|
+
# ------------------------------------------------------------------
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
@auction_group.command("admin-address")
|
|
685
|
+
@_network_option
|
|
686
|
+
@click.pass_context
|
|
687
|
+
def auction_admin_cmd(ctx: click.Context, network: str | None) -> None:
|
|
688
|
+
"""Show the admin address of the auction contract, if set.
|
|
689
|
+
|
|
690
|
+
\b
|
|
691
|
+
Examples:
|
|
692
|
+
tusdt auction admin-address
|
|
693
|
+
tusdt auction admin-address --network testnet
|
|
694
|
+
"""
|
|
695
|
+
config = load_config(network=network)
|
|
696
|
+
|
|
697
|
+
try:
|
|
698
|
+
keypair = get_reader_keypair(config)
|
|
699
|
+
client = TUSDTClient(config)
|
|
700
|
+
admin = client.get_auction_admin(keypair)
|
|
701
|
+
except Exception as exc:
|
|
702
|
+
print_error(str(exc))
|
|
703
|
+
return
|
|
704
|
+
|
|
705
|
+
if admin is None:
|
|
706
|
+
print_info("No admin set")
|
|
707
|
+
else:
|
|
708
|
+
print_dict("Auction Admin", {"Address": admin})
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
# ------------------------------------------------------------------
|
|
712
|
+
# create
|
|
713
|
+
# ------------------------------------------------------------------
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
@auction_group.command("create")
|
|
717
|
+
@click.argument("vault_owner", type=str, metavar="<ss58-address>")
|
|
718
|
+
@click.argument("vault_id", type=int, metavar="<vault-id>")
|
|
719
|
+
@click.option(
|
|
720
|
+
"--collateral-balance",
|
|
721
|
+
type=str,
|
|
722
|
+
required=True,
|
|
723
|
+
help="Collateral balance in human-readable units (e.g. 10.0)",
|
|
724
|
+
)
|
|
725
|
+
@click.option(
|
|
726
|
+
"--debt-balance", type=str, required=True, help="Debt balance in human-readable units (e.g. 100.0)"
|
|
727
|
+
)
|
|
728
|
+
@click.option("--min-bid", type=str, required=True, help="Minimum bid in human-readable units (e.g. 10.0)")
|
|
729
|
+
@click.option(
|
|
730
|
+
"--liquidation-price", type=int, required=True, help="Liquidation price as raw integer (10^18 scale)"
|
|
731
|
+
)
|
|
732
|
+
@click.option("--duration-ms", type=int, required=True, help="Auction duration in milliseconds (integer)")
|
|
733
|
+
@_wallet_option
|
|
734
|
+
@_network_option
|
|
735
|
+
@click.pass_context
|
|
736
|
+
def create_auction_cmd(
|
|
737
|
+
ctx: click.Context,
|
|
738
|
+
vault_owner: str,
|
|
739
|
+
vault_id: int,
|
|
740
|
+
collateral_balance: str,
|
|
741
|
+
debt_balance: str,
|
|
742
|
+
min_bid: str,
|
|
743
|
+
liquidation_price: int,
|
|
744
|
+
duration_ms: int,
|
|
745
|
+
wallet_name: str | None,
|
|
746
|
+
network: str | None,
|
|
747
|
+
) -> None:
|
|
748
|
+
"""Create a new liquidation auction (controller only).
|
|
749
|
+
|
|
750
|
+
\b
|
|
751
|
+
VAULT_OWNER is the SS58 address of the vault owner.
|
|
752
|
+
VAULT_ID is the numeric vault ID (integer).
|
|
753
|
+
Examples:
|
|
754
|
+
tusdt auction create 5GrwvaEF... 0 --collateral-balance 10 --debt-balance 100 --min-bid 10 --liquidation-price 1500000000000000000 --duration-ms 86400000 --wallet-name MyWallet
|
|
755
|
+
"""
|
|
756
|
+
config = load_config(network=network)
|
|
757
|
+
if wallet_name:
|
|
758
|
+
config["wallet_name"] = wallet_name
|
|
759
|
+
decimals = config.get("decimals", 9)
|
|
760
|
+
|
|
761
|
+
raw_collateral = parse_balance(collateral_balance, decimals)
|
|
762
|
+
raw_debt = parse_balance(debt_balance, decimals)
|
|
763
|
+
raw_min_bid = parse_balance(min_bid, decimals)
|
|
764
|
+
|
|
765
|
+
try:
|
|
766
|
+
vault_owner = resolve_ss58(vault_owner, config.get("wallet_path"))
|
|
767
|
+
except Exception as exc:
|
|
768
|
+
print_error(str(exc))
|
|
769
|
+
|
|
770
|
+
try:
|
|
771
|
+
keypair = get_signer_keypair(config)
|
|
772
|
+
except Exception as exc:
|
|
773
|
+
print_error(str(exc))
|
|
774
|
+
|
|
775
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
776
|
+
print_info(f"Creating auction for vault {vault_id} (owner: {vault_owner})...")
|
|
777
|
+
|
|
778
|
+
try:
|
|
779
|
+
client = TUSDTClient(config)
|
|
780
|
+
result = client.create_auction(
|
|
781
|
+
keypair,
|
|
782
|
+
vault_owner,
|
|
783
|
+
vault_id,
|
|
784
|
+
raw_collateral,
|
|
785
|
+
raw_debt,
|
|
786
|
+
raw_min_bid,
|
|
787
|
+
liquidation_price,
|
|
788
|
+
duration_ms,
|
|
789
|
+
)
|
|
790
|
+
print_success("Auction created!")
|
|
791
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
792
|
+
except Exception as exc:
|
|
793
|
+
print_error(str(exc))
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
# ------------------------------------------------------------------
|
|
797
|
+
# set-admin
|
|
798
|
+
# ------------------------------------------------------------------
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
@auction_group.command("set-admin")
|
|
802
|
+
@click.argument("address", type=str, metavar="<ss58-address>", required=False)
|
|
803
|
+
@click.option("--clear", is_flag=True, default=False, help="Clear the admin (set to None)")
|
|
804
|
+
@_wallet_option
|
|
805
|
+
@_network_option
|
|
806
|
+
@click.pass_context
|
|
807
|
+
def auction_set_admin_cmd(
|
|
808
|
+
ctx: click.Context,
|
|
809
|
+
address: str | None,
|
|
810
|
+
clear: bool,
|
|
811
|
+
wallet_name: str | None,
|
|
812
|
+
network: str | None,
|
|
813
|
+
) -> None:
|
|
814
|
+
"""Set or clear the auction admin (governance only).
|
|
815
|
+
|
|
816
|
+
\b
|
|
817
|
+
ADDRESS is the SS58 address of the admin, or omit and use --clear to remove.
|
|
818
|
+
Examples:
|
|
819
|
+
tusdt auction set-admin 5GrwvaEF... --wallet-name MyWallet
|
|
820
|
+
tusdt auction set-admin --clear --wallet-name MyWallet
|
|
821
|
+
"""
|
|
822
|
+
config = load_config(network=network)
|
|
823
|
+
if wallet_name:
|
|
824
|
+
config["wallet_name"] = wallet_name
|
|
825
|
+
|
|
826
|
+
admin = None if clear else address
|
|
827
|
+
if not clear and not address:
|
|
828
|
+
print_error("Provide an SS58 address or use --clear to remove the admin")
|
|
829
|
+
return
|
|
830
|
+
|
|
831
|
+
try:
|
|
832
|
+
keypair = get_signer_keypair(config)
|
|
833
|
+
except Exception as exc:
|
|
834
|
+
print_error(str(exc))
|
|
835
|
+
return
|
|
836
|
+
|
|
837
|
+
action = "Clearing" if clear else f"Setting to {address}"
|
|
838
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
839
|
+
print_info(f"{action} auction admin...")
|
|
840
|
+
|
|
841
|
+
try:
|
|
842
|
+
client = TUSDTClient(config)
|
|
843
|
+
result = client.auction_set_admin(keypair, admin)
|
|
844
|
+
print_success("Auction admin updated!")
|
|
845
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
846
|
+
except Exception as exc:
|
|
847
|
+
print_error(str(exc))
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
# ------------------------------------------------------------------
|
|
851
|
+
# update-governance
|
|
852
|
+
# ------------------------------------------------------------------
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
@auction_group.command("update-governance")
|
|
856
|
+
@click.argument("address", type=str, metavar="<ss58-address>")
|
|
857
|
+
@_wallet_option
|
|
858
|
+
@_network_option
|
|
859
|
+
@click.pass_context
|
|
860
|
+
def auction_update_governance_cmd(
|
|
861
|
+
ctx: click.Context,
|
|
862
|
+
address: str,
|
|
863
|
+
wallet_name: str | None,
|
|
864
|
+
network: str | None,
|
|
865
|
+
) -> None:
|
|
866
|
+
"""Transfer auction governance to a new account (controller only).
|
|
867
|
+
|
|
868
|
+
\b
|
|
869
|
+
ADDRESS is the SS58 address of the new governance account.
|
|
870
|
+
Examples:
|
|
871
|
+
tusdt auction update-governance 5GrwvaEF... --wallet-name MyWallet
|
|
872
|
+
tusdt auction update-governance 5GrwvaEF... --wallet-name MyWallet --network testnet
|
|
873
|
+
"""
|
|
874
|
+
config = load_config(network=network)
|
|
875
|
+
if wallet_name:
|
|
876
|
+
config["wallet_name"] = wallet_name
|
|
877
|
+
|
|
878
|
+
try:
|
|
879
|
+
keypair = get_signer_keypair(config)
|
|
880
|
+
except Exception as exc:
|
|
881
|
+
print_error(str(exc))
|
|
882
|
+
return
|
|
883
|
+
|
|
884
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
885
|
+
print_info(f"Updating auction governance to {address}...")
|
|
886
|
+
|
|
887
|
+
try:
|
|
888
|
+
client = TUSDTClient(config)
|
|
889
|
+
result = client.auction_update_governance(keypair, address)
|
|
890
|
+
print_success("Auction governance updated!")
|
|
891
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
892
|
+
except Exception as exc:
|
|
893
|
+
print_error(str(exc))
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
# ------------------------------------------------------------------
|
|
897
|
+
# transfer-winning-bid
|
|
898
|
+
# ------------------------------------------------------------------
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
@auction_group.command("transfer-winning-bid")
|
|
902
|
+
@click.argument("auction_id", type=int, metavar="<auction-id>")
|
|
903
|
+
@click.argument("recipient", type=str, metavar="<ss58-address>")
|
|
904
|
+
@_wallet_option
|
|
905
|
+
@_network_option
|
|
906
|
+
@click.pass_context
|
|
907
|
+
def transfer_winning_bid_cmd(
|
|
908
|
+
ctx: click.Context,
|
|
909
|
+
auction_id: int,
|
|
910
|
+
recipient: str,
|
|
911
|
+
wallet_name: str | None,
|
|
912
|
+
network: str | None,
|
|
913
|
+
) -> None:
|
|
914
|
+
"""Transfer the winning bid amount to a recipient (controller only).
|
|
915
|
+
|
|
916
|
+
\b
|
|
917
|
+
AUCTION_ID is the numeric auction ID (integer).
|
|
918
|
+
RECIPIENT is the SS58 address to receive the winning bid tokens.
|
|
919
|
+
Examples:
|
|
920
|
+
tusdt auction transfer-winning-bid 0 5GrwvaEF... --wallet-name MyWallet
|
|
921
|
+
tusdt auction transfer-winning-bid 5 5GrwvaEF... --wallet-name MyWallet --network testnet
|
|
922
|
+
"""
|
|
923
|
+
config = load_config(network=network)
|
|
924
|
+
if wallet_name:
|
|
925
|
+
config["wallet_name"] = wallet_name
|
|
926
|
+
|
|
927
|
+
try:
|
|
928
|
+
recipient = resolve_ss58(recipient, config.get("wallet_path"))
|
|
929
|
+
except Exception as exc:
|
|
930
|
+
print_error(str(exc))
|
|
931
|
+
|
|
932
|
+
try:
|
|
933
|
+
keypair = get_signer_keypair(config)
|
|
934
|
+
except Exception as exc:
|
|
935
|
+
print_error(str(exc))
|
|
936
|
+
|
|
937
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
938
|
+
print_info(f"Transferring winning bid for auction {auction_id} to {recipient}...")
|
|
939
|
+
|
|
940
|
+
try:
|
|
941
|
+
client = TUSDTClient(config)
|
|
942
|
+
result = client.auction_transfer_winning_bid(keypair, auction_id, recipient)
|
|
943
|
+
print_success("Winning bid transferred!")
|
|
944
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
945
|
+
except Exception as exc:
|
|
946
|
+
print_error(str(exc))
|
|
@@ -1300,9 +1300,7 @@ def vote_cmd(
|
|
|
1300
1300
|
ph = ph[2:]
|
|
1301
1301
|
proof_bytes = bytes.fromhex(ph)
|
|
1302
1302
|
if len(proof_bytes) != 32:
|
|
1303
|
-
print_error(
|
|
1304
|
-
f"Each --proof must be exactly 32 bytes (64 hex chars), got {len(proof_bytes)} bytes"
|
|
1305
|
-
)
|
|
1303
|
+
print_error(f"Each --proof must be exactly 32 bytes (64 hex chars), got {len(proof_bytes)} bytes")
|
|
1306
1304
|
return
|
|
1307
1305
|
proof_list.append(list(proof_bytes))
|
|
1308
1306
|
|
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
"""Token (ERC-20) CLI commands."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from tusdt_cli.client import TUSDTClient
|
|
6
|
+
from tusdt_cli.config import NETWORKS, load_config
|
|
7
|
+
from tusdt_cli.utils import (
|
|
8
|
+
ModeAwareGroup,
|
|
9
|
+
format_balance,
|
|
10
|
+
parse_balance,
|
|
11
|
+
print_dict,
|
|
12
|
+
print_error,
|
|
13
|
+
print_info,
|
|
14
|
+
print_success,
|
|
15
|
+
print_tx_result,
|
|
16
|
+
)
|
|
17
|
+
from tusdt_cli.wallet import get_reader_keypair, get_signer_keypair, resolve_ss58
|
|
18
|
+
|
|
19
|
+
_network_option = click.option(
|
|
20
|
+
"--network",
|
|
21
|
+
type=click.Choice(list(NETWORKS.keys()), case_sensitive=False),
|
|
22
|
+
default=None,
|
|
23
|
+
help="Network preset (overrides rpc & contract addresses)",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
_wallet_option = click.option(
|
|
27
|
+
"--wallet-name",
|
|
28
|
+
default=None,
|
|
29
|
+
help="Bittensor wallet name for signing (prompts for coldkey password)",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
_TOKEN_ADVANCED = {"mint", "burn", "increase-allowance", "decrease-allowance", "transfer-from"}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@click.group("token", cls=ModeAwareGroup, advanced_commands=_TOKEN_ADVANCED)
|
|
37
|
+
def token_group() -> None:
|
|
38
|
+
"""TUSDT token operations."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ------------------------------------------------------------------
|
|
42
|
+
# balance
|
|
43
|
+
# ------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@token_group.command("balance")
|
|
47
|
+
@click.option("--owner", default=None, help="Account SS58 address or wallet name (defaults to --wallet-name)")
|
|
48
|
+
@_wallet_option
|
|
49
|
+
@_network_option
|
|
50
|
+
@click.pass_context
|
|
51
|
+
def balance(ctx: click.Context, owner: str | None, wallet_name: str | None, network: str | None) -> None:
|
|
52
|
+
"""Show the TUSDT token balance for an account.
|
|
53
|
+
|
|
54
|
+
\b
|
|
55
|
+
Owner is resolved from --wallet-name, or pass --owner explicitly.
|
|
56
|
+
Examples:
|
|
57
|
+
tusdt token balance --wallet-name MyWallet
|
|
58
|
+
tusdt token balance --owner 5GrwvaEF... --network testnet
|
|
59
|
+
"""
|
|
60
|
+
config = load_config(network=network)
|
|
61
|
+
decimals = config.get("decimals", 9)
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
if owner:
|
|
65
|
+
account = resolve_ss58(owner, config.get("wallet_path"))
|
|
66
|
+
elif wallet_name:
|
|
67
|
+
account = resolve_ss58(wallet_name, config.get("wallet_path"))
|
|
68
|
+
else:
|
|
69
|
+
print_error("Provide --owner (address or wallet name) or --wallet-name")
|
|
70
|
+
return
|
|
71
|
+
except Exception as exc:
|
|
72
|
+
print_error(str(exc))
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
keypair = get_reader_keypair(config)
|
|
77
|
+
client = TUSDTClient(config)
|
|
78
|
+
raw = client.balance_of(keypair, account)
|
|
79
|
+
except Exception as exc:
|
|
80
|
+
print_error(str(exc))
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
print_dict(
|
|
84
|
+
"Token Balance",
|
|
85
|
+
{
|
|
86
|
+
"Account": account,
|
|
87
|
+
"Balance": format_balance(raw, decimals),
|
|
88
|
+
"Raw": raw,
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ------------------------------------------------------------------
|
|
94
|
+
# approve
|
|
95
|
+
# ------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@token_group.command("approve")
|
|
99
|
+
@click.argument("spender", type=str, metavar="<spender>")
|
|
100
|
+
@click.argument("amount", type=str, metavar="<amount>")
|
|
101
|
+
@_wallet_option
|
|
102
|
+
@_network_option
|
|
103
|
+
@click.pass_context
|
|
104
|
+
def approve(
|
|
105
|
+
ctx: click.Context, spender: str, amount: str, wallet_name: str | None, network: str | None
|
|
106
|
+
) -> None:
|
|
107
|
+
"""Approve a spender to use your TUSDT tokens.
|
|
108
|
+
|
|
109
|
+
\b
|
|
110
|
+
SPENDER is the SS58 address or wallet name of the account to approve.
|
|
111
|
+
AMOUNT is the human-readable token amount to approve (e.g. 1000).
|
|
112
|
+
Examples:
|
|
113
|
+
tusdt token approve 5GrwvaEF... 1000 --wallet-name MyWallet
|
|
114
|
+
tusdt token approve SpenderWallet 500.5 --wallet-name MyWallet --network testnet
|
|
115
|
+
"""
|
|
116
|
+
config = load_config(network=network)
|
|
117
|
+
if wallet_name:
|
|
118
|
+
config["wallet_name"] = wallet_name
|
|
119
|
+
decimals = config.get("decimals", 9)
|
|
120
|
+
raw_amount = parse_balance(amount, decimals)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
spender = resolve_ss58(spender, config.get("wallet_path"))
|
|
124
|
+
except Exception as exc:
|
|
125
|
+
print_error(str(exc))
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
keypair = get_signer_keypair(config)
|
|
129
|
+
except Exception as exc:
|
|
130
|
+
print_error(str(exc))
|
|
131
|
+
|
|
132
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
133
|
+
print_info(f"Approving {spender} to spend {amount} tokens...")
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
client = TUSDTClient(config)
|
|
137
|
+
result = client.approve(keypair, spender, raw_amount)
|
|
138
|
+
print_success("Approval successful!")
|
|
139
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
140
|
+
except Exception as exc:
|
|
141
|
+
print_error(str(exc))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# ------------------------------------------------------------------
|
|
145
|
+
# allowance
|
|
146
|
+
# ------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@token_group.command("allowance")
|
|
150
|
+
@click.argument("spender", type=str, metavar="<spender>")
|
|
151
|
+
@click.option("--owner", default=None, help="Owner SS58 address or wallet name (defaults to --wallet-name)")
|
|
152
|
+
@_wallet_option
|
|
153
|
+
@_network_option
|
|
154
|
+
@click.pass_context
|
|
155
|
+
def allowance(
|
|
156
|
+
ctx: click.Context, spender: str, owner: str | None, wallet_name: str | None, network: str | None
|
|
157
|
+
) -> None:
|
|
158
|
+
"""Show the allowance a spender has for an owner's tokens.
|
|
159
|
+
|
|
160
|
+
\b
|
|
161
|
+
SPENDER is the SS58 address or wallet name of the spender account.
|
|
162
|
+
Owner is resolved from --wallet-name, or pass --owner explicitly.
|
|
163
|
+
Examples:
|
|
164
|
+
tusdt token allowance 5GrwvaEF... --wallet-name MyWallet
|
|
165
|
+
tusdt token allowance SpenderWallet --owner 5Abc123... --network testnet
|
|
166
|
+
"""
|
|
167
|
+
config = load_config(network=network)
|
|
168
|
+
decimals = config.get("decimals", 9)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
if owner:
|
|
172
|
+
owner = resolve_ss58(owner, config.get("wallet_path"))
|
|
173
|
+
elif wallet_name:
|
|
174
|
+
owner = resolve_ss58(wallet_name, config.get("wallet_path"))
|
|
175
|
+
else:
|
|
176
|
+
print_error("Provide --owner (address or wallet name) or --wallet-name")
|
|
177
|
+
return
|
|
178
|
+
spender = resolve_ss58(spender, config.get("wallet_path"))
|
|
179
|
+
except Exception as exc:
|
|
180
|
+
print_error(str(exc))
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
keypair = get_reader_keypair(config)
|
|
185
|
+
client = TUSDTClient(config)
|
|
186
|
+
raw = client.allowance(keypair, owner, spender)
|
|
187
|
+
except Exception as exc:
|
|
188
|
+
print_error(str(exc))
|
|
189
|
+
return
|
|
190
|
+
|
|
191
|
+
print_dict(
|
|
192
|
+
"Allowance",
|
|
193
|
+
{
|
|
194
|
+
"Owner": owner,
|
|
195
|
+
"Spender": spender,
|
|
196
|
+
"Allowance": format_balance(raw, decimals),
|
|
197
|
+
"Raw": raw,
|
|
198
|
+
},
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# ------------------------------------------------------------------
|
|
203
|
+
# transfer
|
|
204
|
+
# ------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@token_group.command("transfer")
|
|
208
|
+
@click.argument("to", type=str, metavar="<recipient>")
|
|
209
|
+
@click.argument("amount", type=str, metavar="<amount>")
|
|
210
|
+
@_wallet_option
|
|
211
|
+
@_network_option
|
|
212
|
+
@click.pass_context
|
|
213
|
+
def transfer(ctx: click.Context, to: str, amount: str, wallet_name: str | None, network: str | None) -> None:
|
|
214
|
+
"""Transfer TUSDT tokens to another account.
|
|
215
|
+
|
|
216
|
+
\b
|
|
217
|
+
TO is the SS58 address or wallet name of the recipient.
|
|
218
|
+
AMOUNT is the human-readable token amount to send (e.g. 50).
|
|
219
|
+
Examples:
|
|
220
|
+
tusdt token transfer 5GrwvaEF... 50 --wallet-name MyWallet
|
|
221
|
+
tusdt token transfer RecipientWallet 100.5 --wallet-name MyWallet --network testnet
|
|
222
|
+
"""
|
|
223
|
+
config = load_config(network=network)
|
|
224
|
+
if wallet_name:
|
|
225
|
+
config["wallet_name"] = wallet_name
|
|
226
|
+
decimals = config.get("decimals", 9)
|
|
227
|
+
raw_amount = parse_balance(amount, decimals)
|
|
228
|
+
|
|
229
|
+
try:
|
|
230
|
+
to = resolve_ss58(to, config.get("wallet_path"))
|
|
231
|
+
except Exception as exc:
|
|
232
|
+
print_error(str(exc))
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
keypair = get_signer_keypair(config)
|
|
236
|
+
except Exception as exc:
|
|
237
|
+
print_error(str(exc))
|
|
238
|
+
|
|
239
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
240
|
+
print_info(f"Transferring {amount} tokens to {to}...")
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
client = TUSDTClient(config)
|
|
244
|
+
result = client.transfer(keypair, to, raw_amount)
|
|
245
|
+
print_success("Transfer successful!")
|
|
246
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
247
|
+
except Exception as exc:
|
|
248
|
+
print_error(str(exc))
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# ------------------------------------------------------------------
|
|
252
|
+
# controller
|
|
253
|
+
# ------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
@token_group.command("controller")
|
|
257
|
+
@_network_option
|
|
258
|
+
@click.pass_context
|
|
259
|
+
def token_controller_cmd(ctx: click.Context, network: str | None) -> None:
|
|
260
|
+
"""Show the controller address of the TUSDT token contract.
|
|
261
|
+
|
|
262
|
+
\b
|
|
263
|
+
Examples:
|
|
264
|
+
tusdt token controller
|
|
265
|
+
tusdt token controller --network testnet
|
|
266
|
+
"""
|
|
267
|
+
config = load_config(network=network)
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
keypair = get_reader_keypair(config)
|
|
271
|
+
client = TUSDTClient(config)
|
|
272
|
+
addr = client.token_controller(keypair)
|
|
273
|
+
except Exception as exc:
|
|
274
|
+
print_error(str(exc))
|
|
275
|
+
return
|
|
276
|
+
|
|
277
|
+
print_dict("Token Controller", {"Address": addr})
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
# ------------------------------------------------------------------
|
|
281
|
+
# mint
|
|
282
|
+
# ------------------------------------------------------------------
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@token_group.command("mint")
|
|
286
|
+
@click.argument("to", type=str, metavar="<ss58-address>")
|
|
287
|
+
@click.argument("amount", type=str, metavar="<amount>")
|
|
288
|
+
@_wallet_option
|
|
289
|
+
@_network_option
|
|
290
|
+
@click.pass_context
|
|
291
|
+
def mint(ctx: click.Context, to: str, amount: str, wallet_name: str | None, network: str | None) -> None:
|
|
292
|
+
"""Mint TUSDT tokens to an account (controller only).
|
|
293
|
+
|
|
294
|
+
\b
|
|
295
|
+
TO is the SS58 address of the recipient.
|
|
296
|
+
AMOUNT is the human-readable token amount to mint (e.g. 1000).
|
|
297
|
+
Examples:
|
|
298
|
+
tusdt token mint 5GrwvaEF... 1000 --wallet-name MyWallet
|
|
299
|
+
tusdt token mint 5GrwvaEF... 500.5 --wallet-name MyWallet --network testnet
|
|
300
|
+
"""
|
|
301
|
+
config = load_config(network=network)
|
|
302
|
+
if wallet_name:
|
|
303
|
+
config["wallet_name"] = wallet_name
|
|
304
|
+
decimals = config.get("decimals", 9)
|
|
305
|
+
raw_amount = parse_balance(amount, decimals)
|
|
306
|
+
|
|
307
|
+
try:
|
|
308
|
+
to = resolve_ss58(to, config.get("wallet_path"))
|
|
309
|
+
except Exception as exc:
|
|
310
|
+
print_error(str(exc))
|
|
311
|
+
|
|
312
|
+
try:
|
|
313
|
+
keypair = get_signer_keypair(config)
|
|
314
|
+
except Exception as exc:
|
|
315
|
+
print_error(str(exc))
|
|
316
|
+
|
|
317
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
318
|
+
print_info(f"Minting {amount} tokens to {to}...")
|
|
319
|
+
|
|
320
|
+
try:
|
|
321
|
+
client = TUSDTClient(config)
|
|
322
|
+
result = client.token_mint(keypair, to, raw_amount)
|
|
323
|
+
print_success("Mint successful!")
|
|
324
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
325
|
+
except Exception as exc:
|
|
326
|
+
print_error(str(exc))
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
# ------------------------------------------------------------------
|
|
330
|
+
# burn
|
|
331
|
+
# ------------------------------------------------------------------
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@token_group.command("burn")
|
|
335
|
+
@click.argument("from_addr", type=str, metavar="<ss58-address>")
|
|
336
|
+
@click.argument("amount", type=str, metavar="<amount>")
|
|
337
|
+
@_wallet_option
|
|
338
|
+
@_network_option
|
|
339
|
+
@click.pass_context
|
|
340
|
+
def burn(
|
|
341
|
+
ctx: click.Context, from_addr: str, amount: str, wallet_name: str | None, network: str | None
|
|
342
|
+
) -> None:
|
|
343
|
+
"""Burn TUSDT tokens from an account (controller only).
|
|
344
|
+
|
|
345
|
+
\b
|
|
346
|
+
FROM is the SS58 address to burn tokens from.
|
|
347
|
+
AMOUNT is the human-readable token amount to burn (e.g. 1000).
|
|
348
|
+
Examples:
|
|
349
|
+
tusdt token burn 5GrwvaEF... 1000 --wallet-name MyWallet
|
|
350
|
+
tusdt token burn 5GrwvaEF... 500.5 --wallet-name MyWallet --network testnet
|
|
351
|
+
"""
|
|
352
|
+
config = load_config(network=network)
|
|
353
|
+
if wallet_name:
|
|
354
|
+
config["wallet_name"] = wallet_name
|
|
355
|
+
decimals = config.get("decimals", 9)
|
|
356
|
+
raw_amount = parse_balance(amount, decimals)
|
|
357
|
+
|
|
358
|
+
try:
|
|
359
|
+
from_addr = resolve_ss58(from_addr, config.get("wallet_path"))
|
|
360
|
+
except Exception as exc:
|
|
361
|
+
print_error(str(exc))
|
|
362
|
+
|
|
363
|
+
try:
|
|
364
|
+
keypair = get_signer_keypair(config)
|
|
365
|
+
except Exception as exc:
|
|
366
|
+
print_error(str(exc))
|
|
367
|
+
|
|
368
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
369
|
+
print_info(f"Burning {amount} tokens from {from_addr}...")
|
|
370
|
+
|
|
371
|
+
try:
|
|
372
|
+
client = TUSDTClient(config)
|
|
373
|
+
result = client.token_burn(keypair, from_addr, raw_amount)
|
|
374
|
+
print_success("Burn successful!")
|
|
375
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
376
|
+
except Exception as exc:
|
|
377
|
+
print_error(str(exc))
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# ------------------------------------------------------------------
|
|
381
|
+
# increase-allowance
|
|
382
|
+
# ------------------------------------------------------------------
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
@token_group.command("increase-allowance")
|
|
386
|
+
@click.argument("spender", type=str, metavar="<ss58-address>")
|
|
387
|
+
@click.argument("amount", type=str, metavar="<amount>")
|
|
388
|
+
@_wallet_option
|
|
389
|
+
@_network_option
|
|
390
|
+
@click.pass_context
|
|
391
|
+
def increase_allowance_cmd(
|
|
392
|
+
ctx: click.Context, spender: str, amount: str, wallet_name: str | None, network: str | None
|
|
393
|
+
) -> None:
|
|
394
|
+
"""Increase a spender's allowance by a given amount.
|
|
395
|
+
|
|
396
|
+
\b
|
|
397
|
+
SPENDER is the SS58 address of the spender account.
|
|
398
|
+
AMOUNT is the human-readable token amount to add to the allowance (e.g. 1000).
|
|
399
|
+
Examples:
|
|
400
|
+
tusdt token increase-allowance 5GrwvaEF... 1000 --wallet-name MyWallet
|
|
401
|
+
tusdt token increase-allowance 5GrwvaEF... 500.5 --wallet-name MyWallet --network testnet
|
|
402
|
+
"""
|
|
403
|
+
config = load_config(network=network)
|
|
404
|
+
if wallet_name:
|
|
405
|
+
config["wallet_name"] = wallet_name
|
|
406
|
+
decimals = config.get("decimals", 9)
|
|
407
|
+
raw_delta = parse_balance(amount, decimals)
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
spender = resolve_ss58(spender, config.get("wallet_path"))
|
|
411
|
+
except Exception as exc:
|
|
412
|
+
print_error(str(exc))
|
|
413
|
+
|
|
414
|
+
try:
|
|
415
|
+
keypair = get_signer_keypair(config)
|
|
416
|
+
except Exception as exc:
|
|
417
|
+
print_error(str(exc))
|
|
418
|
+
|
|
419
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
420
|
+
print_info(f"Increasing {spender}'s allowance by {amount} tokens...")
|
|
421
|
+
|
|
422
|
+
try:
|
|
423
|
+
client = TUSDTClient(config)
|
|
424
|
+
result = client.token_increase_allowance(keypair, spender, raw_delta)
|
|
425
|
+
print_success("Allowance increased!")
|
|
426
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
427
|
+
except Exception as exc:
|
|
428
|
+
print_error(str(exc))
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
# ------------------------------------------------------------------
|
|
432
|
+
# decrease-allowance
|
|
433
|
+
# ------------------------------------------------------------------
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
@token_group.command("decrease-allowance")
|
|
437
|
+
@click.argument("spender", type=str, metavar="<ss58-address>")
|
|
438
|
+
@click.argument("amount", type=str, metavar="<amount>")
|
|
439
|
+
@_wallet_option
|
|
440
|
+
@_network_option
|
|
441
|
+
@click.pass_context
|
|
442
|
+
def decrease_allowance_cmd(
|
|
443
|
+
ctx: click.Context, spender: str, amount: str, wallet_name: str | None, network: str | None
|
|
444
|
+
) -> None:
|
|
445
|
+
"""Decrease a spender's allowance by a given amount.
|
|
446
|
+
|
|
447
|
+
\b
|
|
448
|
+
SPENDER is the SS58 address of the spender account.
|
|
449
|
+
AMOUNT is the human-readable token amount to subtract from the allowance (e.g. 1000).
|
|
450
|
+
Examples:
|
|
451
|
+
tusdt token decrease-allowance 5GrwvaEF... 1000 --wallet-name MyWallet
|
|
452
|
+
tusdt token decrease-allowance 5GrwvaEF... 500.5 --wallet-name MyWallet --network testnet
|
|
453
|
+
"""
|
|
454
|
+
config = load_config(network=network)
|
|
455
|
+
if wallet_name:
|
|
456
|
+
config["wallet_name"] = wallet_name
|
|
457
|
+
decimals = config.get("decimals", 9)
|
|
458
|
+
raw_delta = parse_balance(amount, decimals)
|
|
459
|
+
|
|
460
|
+
try:
|
|
461
|
+
spender = resolve_ss58(spender, config.get("wallet_path"))
|
|
462
|
+
except Exception as exc:
|
|
463
|
+
print_error(str(exc))
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
keypair = get_signer_keypair(config)
|
|
467
|
+
except Exception as exc:
|
|
468
|
+
print_error(str(exc))
|
|
469
|
+
|
|
470
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
471
|
+
print_info(f"Decreasing {spender}'s allowance by {amount} tokens...")
|
|
472
|
+
|
|
473
|
+
try:
|
|
474
|
+
client = TUSDTClient(config)
|
|
475
|
+
result = client.token_decrease_allowance(keypair, spender, raw_delta)
|
|
476
|
+
print_success("Allowance decreased!")
|
|
477
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
478
|
+
except Exception as exc:
|
|
479
|
+
print_error(str(exc))
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
# ------------------------------------------------------------------
|
|
483
|
+
# transfer-from
|
|
484
|
+
# ------------------------------------------------------------------
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
@token_group.command("transfer-from")
|
|
488
|
+
@click.argument("from_addr", type=str, metavar="<from-ss58-address>")
|
|
489
|
+
@click.argument("to", type=str, metavar="<to-ss58-address>")
|
|
490
|
+
@click.argument("amount", type=str, metavar="<amount>")
|
|
491
|
+
@_wallet_option
|
|
492
|
+
@_network_option
|
|
493
|
+
@click.pass_context
|
|
494
|
+
def transfer_from_cmd(
|
|
495
|
+
ctx: click.Context,
|
|
496
|
+
from_addr: str,
|
|
497
|
+
to: str,
|
|
498
|
+
amount: str,
|
|
499
|
+
wallet_name: str | None,
|
|
500
|
+
network: str | None,
|
|
501
|
+
) -> None:
|
|
502
|
+
"""Transfer TUSDT tokens from one account to another (requires allowance).
|
|
503
|
+
|
|
504
|
+
\b
|
|
505
|
+
FROM is the SS58 address to transfer tokens from.
|
|
506
|
+
TO is the SS58 address of the recipient.
|
|
507
|
+
AMOUNT is the human-readable token amount to transfer (e.g. 1000).
|
|
508
|
+
Examples:
|
|
509
|
+
tusdt token transfer-from 5GrwvaEF... 5FHneW... 1000 --wallet-name MyWallet
|
|
510
|
+
tusdt token transfer-from 5GrwvaEF... 5FHneW... 500.5 --wallet-name MyWallet --network testnet
|
|
511
|
+
"""
|
|
512
|
+
config = load_config(network=network)
|
|
513
|
+
if wallet_name:
|
|
514
|
+
config["wallet_name"] = wallet_name
|
|
515
|
+
decimals = config.get("decimals", 9)
|
|
516
|
+
raw_amount = parse_balance(amount, decimals)
|
|
517
|
+
|
|
518
|
+
try:
|
|
519
|
+
from_addr = resolve_ss58(from_addr, config.get("wallet_path"))
|
|
520
|
+
to = resolve_ss58(to, config.get("wallet_path"))
|
|
521
|
+
except Exception as exc:
|
|
522
|
+
print_error(str(exc))
|
|
523
|
+
|
|
524
|
+
try:
|
|
525
|
+
keypair = get_signer_keypair(config)
|
|
526
|
+
except Exception as exc:
|
|
527
|
+
print_error(str(exc))
|
|
528
|
+
|
|
529
|
+
print_info(f"Signer: {keypair.ss58_address}")
|
|
530
|
+
print_info(f"Transferring {amount} tokens from {from_addr} to {to}...")
|
|
531
|
+
|
|
532
|
+
try:
|
|
533
|
+
client = TUSDTClient(config)
|
|
534
|
+
result = client.token_transfer_from(keypair, from_addr, to, raw_amount)
|
|
535
|
+
print_success("Transfer successful!")
|
|
536
|
+
print_tx_result(result, config.get("network", "finney"))
|
|
537
|
+
except Exception as exc:
|
|
538
|
+
print_error(str(exc))
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
"""Token (ERC-20) CLI commands."""
|
|
2
|
-
|
|
3
|
-
import click
|
|
4
|
-
|
|
5
|
-
from tusdt_cli.client import TUSDTClient
|
|
6
|
-
from tusdt_cli.config import NETWORKS, load_config
|
|
7
|
-
from tusdt_cli.utils import (
|
|
8
|
-
HelpfulGroup,
|
|
9
|
-
format_balance,
|
|
10
|
-
parse_balance,
|
|
11
|
-
print_dict,
|
|
12
|
-
print_error,
|
|
13
|
-
print_info,
|
|
14
|
-
print_success,
|
|
15
|
-
print_tx_result,
|
|
16
|
-
)
|
|
17
|
-
from tusdt_cli.wallet import get_reader_keypair, get_signer_keypair, resolve_ss58
|
|
18
|
-
|
|
19
|
-
_network_option = click.option(
|
|
20
|
-
"--network",
|
|
21
|
-
type=click.Choice(list(NETWORKS.keys()), case_sensitive=False),
|
|
22
|
-
default=None,
|
|
23
|
-
help="Network preset (overrides rpc & contract addresses)",
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
_wallet_option = click.option(
|
|
27
|
-
"--wallet-name",
|
|
28
|
-
default=None,
|
|
29
|
-
help="Bittensor wallet name for signing (prompts for coldkey password)",
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@click.group("token", cls=HelpfulGroup)
|
|
34
|
-
def token_group() -> None:
|
|
35
|
-
"""TUSDT token operations."""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# ------------------------------------------------------------------
|
|
39
|
-
# balance
|
|
40
|
-
# ------------------------------------------------------------------
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@token_group.command("balance")
|
|
44
|
-
@click.option("--owner", default=None, help="Account SS58 address or wallet name (defaults to --wallet-name)")
|
|
45
|
-
@_wallet_option
|
|
46
|
-
@_network_option
|
|
47
|
-
@click.pass_context
|
|
48
|
-
def balance(ctx: click.Context, owner: str | None, wallet_name: str | None, network: str | None) -> None:
|
|
49
|
-
"""Show the TUSDT token balance for an account.
|
|
50
|
-
|
|
51
|
-
\b
|
|
52
|
-
Owner is resolved from --wallet-name, or pass --owner explicitly.
|
|
53
|
-
Examples:
|
|
54
|
-
tusdt token balance --wallet-name MyWallet
|
|
55
|
-
tusdt token balance --owner 5GrwvaEF... --network testnet
|
|
56
|
-
"""
|
|
57
|
-
config = load_config(network=network)
|
|
58
|
-
decimals = config.get("decimals", 9)
|
|
59
|
-
|
|
60
|
-
try:
|
|
61
|
-
if owner:
|
|
62
|
-
account = resolve_ss58(owner, config.get("wallet_path"))
|
|
63
|
-
elif wallet_name:
|
|
64
|
-
account = resolve_ss58(wallet_name, config.get("wallet_path"))
|
|
65
|
-
else:
|
|
66
|
-
print_error("Provide --owner (address or wallet name) or --wallet-name")
|
|
67
|
-
return
|
|
68
|
-
except Exception as exc:
|
|
69
|
-
print_error(str(exc))
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
try:
|
|
73
|
-
keypair = get_reader_keypair(config)
|
|
74
|
-
client = TUSDTClient(config)
|
|
75
|
-
raw = client.balance_of(keypair, account)
|
|
76
|
-
except Exception as exc:
|
|
77
|
-
print_error(str(exc))
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
print_dict(
|
|
81
|
-
"Token Balance",
|
|
82
|
-
{
|
|
83
|
-
"Account": account,
|
|
84
|
-
"Balance": format_balance(raw, decimals),
|
|
85
|
-
"Raw": raw,
|
|
86
|
-
},
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
# ------------------------------------------------------------------
|
|
91
|
-
# approve
|
|
92
|
-
# ------------------------------------------------------------------
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@token_group.command("approve")
|
|
96
|
-
@click.argument("spender", type=str, metavar="<spender>")
|
|
97
|
-
@click.argument("amount", type=str, metavar="<amount>")
|
|
98
|
-
@_wallet_option
|
|
99
|
-
@_network_option
|
|
100
|
-
@click.pass_context
|
|
101
|
-
def approve(
|
|
102
|
-
ctx: click.Context, spender: str, amount: str, wallet_name: str | None, network: str | None
|
|
103
|
-
) -> None:
|
|
104
|
-
"""Approve a spender to use your TUSDT tokens.
|
|
105
|
-
|
|
106
|
-
\b
|
|
107
|
-
SPENDER is the SS58 address or wallet name of the account to approve.
|
|
108
|
-
AMOUNT is the human-readable token amount to approve (e.g. 1000).
|
|
109
|
-
Examples:
|
|
110
|
-
tusdt token approve 5GrwvaEF... 1000 --wallet-name MyWallet
|
|
111
|
-
tusdt token approve SpenderWallet 500.5 --wallet-name MyWallet --network testnet
|
|
112
|
-
"""
|
|
113
|
-
config = load_config(network=network)
|
|
114
|
-
if wallet_name:
|
|
115
|
-
config["wallet_name"] = wallet_name
|
|
116
|
-
decimals = config.get("decimals", 9)
|
|
117
|
-
raw_amount = parse_balance(amount, decimals)
|
|
118
|
-
|
|
119
|
-
try:
|
|
120
|
-
spender = resolve_ss58(spender, config.get("wallet_path"))
|
|
121
|
-
except Exception as exc:
|
|
122
|
-
print_error(str(exc))
|
|
123
|
-
|
|
124
|
-
try:
|
|
125
|
-
keypair = get_signer_keypair(config)
|
|
126
|
-
except Exception as exc:
|
|
127
|
-
print_error(str(exc))
|
|
128
|
-
|
|
129
|
-
print_info(f"Signer: {keypair.ss58_address}")
|
|
130
|
-
print_info(f"Approving {spender} to spend {amount} tokens...")
|
|
131
|
-
|
|
132
|
-
try:
|
|
133
|
-
client = TUSDTClient(config)
|
|
134
|
-
result = client.approve(keypair, spender, raw_amount)
|
|
135
|
-
print_success("Approval successful!")
|
|
136
|
-
print_tx_result(result, config.get("network", "finney"))
|
|
137
|
-
except Exception as exc:
|
|
138
|
-
print_error(str(exc))
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
# ------------------------------------------------------------------
|
|
142
|
-
# allowance
|
|
143
|
-
# ------------------------------------------------------------------
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
@token_group.command("allowance")
|
|
147
|
-
@click.argument("spender", type=str, metavar="<spender>")
|
|
148
|
-
@click.option("--owner", default=None, help="Owner SS58 address or wallet name (defaults to --wallet-name)")
|
|
149
|
-
@_wallet_option
|
|
150
|
-
@_network_option
|
|
151
|
-
@click.pass_context
|
|
152
|
-
def allowance(
|
|
153
|
-
ctx: click.Context, spender: str, owner: str | None, wallet_name: str | None, network: str | None
|
|
154
|
-
) -> None:
|
|
155
|
-
"""Show the allowance a spender has for an owner's tokens.
|
|
156
|
-
|
|
157
|
-
\b
|
|
158
|
-
SPENDER is the SS58 address or wallet name of the spender account.
|
|
159
|
-
Owner is resolved from --wallet-name, or pass --owner explicitly.
|
|
160
|
-
Examples:
|
|
161
|
-
tusdt token allowance 5GrwvaEF... --wallet-name MyWallet
|
|
162
|
-
tusdt token allowance SpenderWallet --owner 5Abc123... --network testnet
|
|
163
|
-
"""
|
|
164
|
-
config = load_config(network=network)
|
|
165
|
-
decimals = config.get("decimals", 9)
|
|
166
|
-
|
|
167
|
-
try:
|
|
168
|
-
if owner:
|
|
169
|
-
owner = resolve_ss58(owner, config.get("wallet_path"))
|
|
170
|
-
elif wallet_name:
|
|
171
|
-
owner = resolve_ss58(wallet_name, config.get("wallet_path"))
|
|
172
|
-
else:
|
|
173
|
-
print_error("Provide --owner (address or wallet name) or --wallet-name")
|
|
174
|
-
return
|
|
175
|
-
spender = resolve_ss58(spender, config.get("wallet_path"))
|
|
176
|
-
except Exception as exc:
|
|
177
|
-
print_error(str(exc))
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
try:
|
|
181
|
-
keypair = get_reader_keypair(config)
|
|
182
|
-
client = TUSDTClient(config)
|
|
183
|
-
raw = client.allowance(keypair, owner, spender)
|
|
184
|
-
except Exception as exc:
|
|
185
|
-
print_error(str(exc))
|
|
186
|
-
return
|
|
187
|
-
|
|
188
|
-
print_dict(
|
|
189
|
-
"Allowance",
|
|
190
|
-
{
|
|
191
|
-
"Owner": owner,
|
|
192
|
-
"Spender": spender,
|
|
193
|
-
"Allowance": format_balance(raw, decimals),
|
|
194
|
-
"Raw": raw,
|
|
195
|
-
},
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
# ------------------------------------------------------------------
|
|
200
|
-
# transfer
|
|
201
|
-
# ------------------------------------------------------------------
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
@token_group.command("transfer")
|
|
205
|
-
@click.argument("to", type=str, metavar="<recipient>")
|
|
206
|
-
@click.argument("amount", type=str, metavar="<amount>")
|
|
207
|
-
@_wallet_option
|
|
208
|
-
@_network_option
|
|
209
|
-
@click.pass_context
|
|
210
|
-
def transfer(ctx: click.Context, to: str, amount: str, wallet_name: str | None, network: str | None) -> None:
|
|
211
|
-
"""Transfer TUSDT tokens to another account.
|
|
212
|
-
|
|
213
|
-
\b
|
|
214
|
-
TO is the SS58 address or wallet name of the recipient.
|
|
215
|
-
AMOUNT is the human-readable token amount to send (e.g. 50).
|
|
216
|
-
Examples:
|
|
217
|
-
tusdt token transfer 5GrwvaEF... 50 --wallet-name MyWallet
|
|
218
|
-
tusdt token transfer RecipientWallet 100.5 --wallet-name MyWallet --network testnet
|
|
219
|
-
"""
|
|
220
|
-
config = load_config(network=network)
|
|
221
|
-
if wallet_name:
|
|
222
|
-
config["wallet_name"] = wallet_name
|
|
223
|
-
decimals = config.get("decimals", 9)
|
|
224
|
-
raw_amount = parse_balance(amount, decimals)
|
|
225
|
-
|
|
226
|
-
try:
|
|
227
|
-
to = resolve_ss58(to, config.get("wallet_path"))
|
|
228
|
-
except Exception as exc:
|
|
229
|
-
print_error(str(exc))
|
|
230
|
-
|
|
231
|
-
try:
|
|
232
|
-
keypair = get_signer_keypair(config)
|
|
233
|
-
except Exception as exc:
|
|
234
|
-
print_error(str(exc))
|
|
235
|
-
|
|
236
|
-
print_info(f"Signer: {keypair.ss58_address}")
|
|
237
|
-
print_info(f"Transferring {amount} tokens to {to}...")
|
|
238
|
-
|
|
239
|
-
try:
|
|
240
|
-
client = TUSDTClient(config)
|
|
241
|
-
result = client.transfer(keypair, to, raw_amount)
|
|
242
|
-
print_success("Transfer successful!")
|
|
243
|
-
print_tx_result(result, config.get("network", "finney"))
|
|
244
|
-
except Exception as exc:
|
|
245
|
-
print_error(str(exc))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|