communex.cli.balance
1import re 2from typing import Optional 3 4import typer 5from typer import Context 6 7from communex._common import IPFS_REGEX, BalanceUnit, format_balance 8from communex.balance import to_nano 9from communex.cli._common import (make_custom_context, 10 print_table_from_plain_dict) 11from communex.compat.key import (resolve_key_ss58_encrypted, 12 try_classic_load_key) 13from communex.errors import ChainTransactionError 14from communex.faucet.powv2 import solve_for_difficulty_fast 15 16balance_app = typer.Typer(no_args_is_help=True) 17 18 19@balance_app.command() 20def free_balance( 21 ctx: Context, 22 key: str, 23 unit: BalanceUnit = BalanceUnit.joule, 24 password: Optional[str] = None, 25): 26 """ 27 Gets free balance of a key. 28 """ 29 context = make_custom_context(ctx) 30 client = context.com_client() 31 32 key_address = resolve_key_ss58_encrypted(key, context, password) 33 34 with context.progress_status(f"Getting free balance of key {key_address}..."): 35 balance = client.get_balance(key_address) 36 37 context.output(format_balance(balance, unit)) 38 39 40@balance_app.command() 41def staked_balance( 42 ctx: Context, 43 key: str, 44 unit: BalanceUnit = BalanceUnit.joule, 45 password: Optional[str] = None, 46): 47 """ 48 Gets the balance staked on the key itself. 49 """ 50 context = make_custom_context(ctx) 51 client = context.com_client() 52 53 key_address = resolve_key_ss58_encrypted(key, context, password) 54 55 with context.progress_status(f"Getting staked balance of key {key_address}..."): 56 result = sum(client.get_staketo(key=key_address).values()) 57 58 context.output(format_balance(result, unit)) 59 60 61@balance_app.command() 62def show( 63 ctx: Context, 64 key: str, 65 unit: BalanceUnit = BalanceUnit.joule, 66 password: Optional[str] = None, 67): 68 """ 69 Gets entire balance of a key (free balance + staked balance). 70 """ 71 context = make_custom_context(ctx) 72 client = context.com_client() 73 74 key_address = resolve_key_ss58_encrypted(key, context, password) 75 76 with context.progress_status(f"Getting value of key {key_address}..."): 77 staked_balance = sum(client.get_staketo(key=key_address).values()) 78 free_balance = client.get_balance(key_address) 79 balance_sum = free_balance + staked_balance 80 81 print_table_from_plain_dict( 82 {"Free": format_balance(free_balance, unit), "Staked": format_balance(staked_balance, unit), "Total": format_balance(balance_sum, unit)}, [ 83 "Result", "Amount"], context.console 84 ) 85 86 87@balance_app.command() 88def get_staked( 89 ctx: Context, 90 key: str, 91 unit: BalanceUnit = BalanceUnit.joule, 92 password: Optional[str] = None, 93): 94 """ 95 Gets total stake of a key it delegated across other keys. 96 """ 97 context = make_custom_context(ctx) 98 client = context.com_client() 99 100 key_address = resolve_key_ss58_encrypted(key, context, password) 101 102 with context.progress_status(f"Getting stake of {key_address}..."): 103 result = sum(client.get_staketo(key=key_address).values()) 104 105 context.output(format_balance(result, unit)) 106 107 108@balance_app.command() 109def transfer(ctx: Context, key: str, amount: float, dest: str): 110 """ 111 Transfer amount to destination using key 112 """ 113 context = make_custom_context(ctx) 114 client = context.com_client() 115 116 nano_amount = to_nano(amount) 117 resolved_key = try_classic_load_key(key, context) 118 resolved_dest = resolve_key_ss58_encrypted(dest, context) 119 120 if not context.confirm( 121 f"Are you sure you want to transfer {amount} tokens to {dest}?" 122 ): 123 raise typer.Abort() 124 125 with context.progress_status(f"Transferring {amount} tokens to {dest}..."): 126 response = client.transfer( 127 key=resolved_key, amount=nano_amount, dest=resolved_dest 128 ) 129 130 if response.is_success: 131 context.info(f"Transferred {amount} tokens to {dest}") 132 else: 133 raise ChainTransactionError(response.error_message) # type: ignore 134 135 136@balance_app.command() 137def transfer_stake( 138 ctx: Context, key: str, amount: float, from_key: str, dest: str 139): 140 """ 141 Transfers stake of key from point A to point B 142 """ 143 context = make_custom_context(ctx) 144 client = context.com_client() 145 146 resolved_from = resolve_key_ss58_encrypted(from_key, context) 147 resolved_dest = resolve_key_ss58_encrypted(dest, context) 148 resolved_key = try_classic_load_key(key, context) 149 nano_amount = to_nano(amount) 150 151 with context.progress_status( 152 f"Transferring {amount} tokens from {from_key} to {dest}' ..." 153 ): 154 response = client.transfer_stake( 155 key=resolved_key, 156 amount=nano_amount, 157 from_module_key=resolved_from, 158 dest_module_address=resolved_dest, 159 ) 160 161 if response.is_success: 162 context.info(f"Transferred {amount} tokens from {from_key} to {dest}") 163 else: 164 raise ChainTransactionError(response.error_message) # type: ignore 165 166 167@balance_app.command() 168def stake( 169 ctx: Context, 170 key: str, 171 amount: float, 172 dest: str, 173): 174 """ 175 Stake amount to destination using key 176 """ 177 context = make_custom_context(ctx) 178 client = context.com_client() 179 180 nano_amount = to_nano(amount) 181 resolved_key = try_classic_load_key(key, context) 182 resolved_dest = resolve_key_ss58_encrypted(dest, context) 183 delegating_message = ( 184 "By default you delegate DAO " 185 "voting power to the validator you stake to. " 186 "In case you want to change this, call: " 187 "`comx key power-delegation <key> --disable`." 188 ) 189 context.info("INFO: ", style="bold green", end="") # type: ignore 190 context.info(delegating_message) # type: ignore 191 with context.progress_status( 192 f"Staking {amount} tokens to {dest}..." 193 ): 194 response = client.stake( 195 key=resolved_key, amount=nano_amount, dest=resolved_dest 196 ) 197 198 if response.is_success: 199 context.info(f"Staked {amount} tokens to {dest}") 200 else: 201 raise ChainTransactionError(response.error_message) # type: ignore 202 203 204@balance_app.command() 205def unstake(ctx: Context, key: str, amount: float, dest: str): 206 """ 207 Unstake amount from destination using key 208 """ 209 context = make_custom_context(ctx) 210 client = context.com_client() 211 212 nano_amount = to_nano(amount) 213 resolved_key = try_classic_load_key(key, context) 214 resolved_dest = resolve_key_ss58_encrypted(dest, context) 215 216 with context.progress_status( 217 f"Unstaking {amount} tokens from {dest}'..." 218 ): 219 response = client.unstake( 220 key=resolved_key, amount=nano_amount, dest=resolved_dest 221 ) # TODO: is it right? 222 223 if response.is_success: 224 context.info(f"Unstaked {amount} tokens from {dest}") 225 else: 226 raise ChainTransactionError(response.error_message) # type: ignore 227 228 229@balance_app.command() 230def run_faucet( 231 ctx: Context, 232 key: str, 233 num_processes: Optional[int] = None, 234 num_executions: int = 1, 235): 236 context = make_custom_context(ctx) 237 use_testnet = ctx.obj.use_testnet 238 if not use_testnet: 239 context.error("Faucet only enabled on testnet") 240 return 241 resolved_key = try_classic_load_key(key, context) 242 client = context.com_client() 243 for _ in range(num_executions): 244 with context.progress_status("Solving PoW..."): 245 solution = solve_for_difficulty_fast( 246 client, 247 resolved_key, 248 client.url, 249 num_processes=num_processes, 250 ) 251 with context.progress_status("Sending solution to blockchain"): 252 params = { 253 "block_number": solution.block_number, 254 "nonce": solution.nonce, 255 "work": solution.seal, 256 "key": resolved_key.ss58_address, 257 } 258 client.compose_call("faucet", params=params, unsigned=True, 259 module="FaucetModule", key=resolved_key.ss58_address) # type: ignore 260 261 262@balance_app.command() 263def transfer_dao_funds( 264 ctx: Context, 265 signer_key: str, 266 amount: float, 267 cid_hash: str, 268 dest: str, 269): 270 context = make_custom_context(ctx) 271 if not re.match(IPFS_REGEX, cid_hash): 272 context.error(f"CID provided is invalid: {cid_hash}") 273 exit(1) 274 ipfs_prefix = "ipfs://" 275 cid = ipfs_prefix + cid_hash 276 277 client = context.com_client() 278 279 nano_amount = to_nano(amount) 280 dest = resolve_key_ss58_encrypted(dest, context) 281 signer_keypair = try_classic_load_key(signer_key, context) 282 client.add_transfer_dao_treasury_proposal( 283 signer_keypair, cid, nano_amount, dest 284 )
balance_app =
<typer.main.Typer object>
@balance_app.command()
def
free_balance( ctx: typer.models.Context, key: str, unit: communex._common.BalanceUnit = <BalanceUnit.joule: 'joule'>, password: Optional[str] = None):
20@balance_app.command() 21def free_balance( 22 ctx: Context, 23 key: str, 24 unit: BalanceUnit = BalanceUnit.joule, 25 password: Optional[str] = None, 26): 27 """ 28 Gets free balance of a key. 29 """ 30 context = make_custom_context(ctx) 31 client = context.com_client() 32 33 key_address = resolve_key_ss58_encrypted(key, context, password) 34 35 with context.progress_status(f"Getting free balance of key {key_address}..."): 36 balance = client.get_balance(key_address) 37 38 context.output(format_balance(balance, unit))
Gets free balance of a key.
@balance_app.command()
def
staked_balance( ctx: typer.models.Context, key: str, unit: communex._common.BalanceUnit = <BalanceUnit.joule: 'joule'>, password: Optional[str] = None):
41@balance_app.command() 42def staked_balance( 43 ctx: Context, 44 key: str, 45 unit: BalanceUnit = BalanceUnit.joule, 46 password: Optional[str] = None, 47): 48 """ 49 Gets the balance staked on the key itself. 50 """ 51 context = make_custom_context(ctx) 52 client = context.com_client() 53 54 key_address = resolve_key_ss58_encrypted(key, context, password) 55 56 with context.progress_status(f"Getting staked balance of key {key_address}..."): 57 result = sum(client.get_staketo(key=key_address).values()) 58 59 context.output(format_balance(result, unit))
Gets the balance staked on the key itself.
@balance_app.command()
def
show( ctx: typer.models.Context, key: str, unit: communex._common.BalanceUnit = <BalanceUnit.joule: 'joule'>, password: Optional[str] = None):
62@balance_app.command() 63def show( 64 ctx: Context, 65 key: str, 66 unit: BalanceUnit = BalanceUnit.joule, 67 password: Optional[str] = None, 68): 69 """ 70 Gets entire balance of a key (free balance + staked balance). 71 """ 72 context = make_custom_context(ctx) 73 client = context.com_client() 74 75 key_address = resolve_key_ss58_encrypted(key, context, password) 76 77 with context.progress_status(f"Getting value of key {key_address}..."): 78 staked_balance = sum(client.get_staketo(key=key_address).values()) 79 free_balance = client.get_balance(key_address) 80 balance_sum = free_balance + staked_balance 81 82 print_table_from_plain_dict( 83 {"Free": format_balance(free_balance, unit), "Staked": format_balance(staked_balance, unit), "Total": format_balance(balance_sum, unit)}, [ 84 "Result", "Amount"], context.console 85 )
Gets entire balance of a key (free balance + staked balance).
@balance_app.command()
def
get_staked( ctx: typer.models.Context, key: str, unit: communex._common.BalanceUnit = <BalanceUnit.joule: 'joule'>, password: Optional[str] = None):
88@balance_app.command() 89def get_staked( 90 ctx: Context, 91 key: str, 92 unit: BalanceUnit = BalanceUnit.joule, 93 password: Optional[str] = None, 94): 95 """ 96 Gets total stake of a key it delegated across other keys. 97 """ 98 context = make_custom_context(ctx) 99 client = context.com_client() 100 101 key_address = resolve_key_ss58_encrypted(key, context, password) 102 103 with context.progress_status(f"Getting stake of {key_address}..."): 104 result = sum(client.get_staketo(key=key_address).values()) 105 106 context.output(format_balance(result, unit))
Gets total stake of a key it delegated across other keys.
@balance_app.command()
def
transfer(ctx: typer.models.Context, key: str, amount: float, dest: str):
109@balance_app.command() 110def transfer(ctx: Context, key: str, amount: float, dest: str): 111 """ 112 Transfer amount to destination using key 113 """ 114 context = make_custom_context(ctx) 115 client = context.com_client() 116 117 nano_amount = to_nano(amount) 118 resolved_key = try_classic_load_key(key, context) 119 resolved_dest = resolve_key_ss58_encrypted(dest, context) 120 121 if not context.confirm( 122 f"Are you sure you want to transfer {amount} tokens to {dest}?" 123 ): 124 raise typer.Abort() 125 126 with context.progress_status(f"Transferring {amount} tokens to {dest}..."): 127 response = client.transfer( 128 key=resolved_key, amount=nano_amount, dest=resolved_dest 129 ) 130 131 if response.is_success: 132 context.info(f"Transferred {amount} tokens to {dest}") 133 else: 134 raise ChainTransactionError(response.error_message) # type: ignore
Transfer amount to destination using key
@balance_app.command()
def
transfer_stake( ctx: typer.models.Context, key: str, amount: float, from_key: str, dest: str):
137@balance_app.command() 138def transfer_stake( 139 ctx: Context, key: str, amount: float, from_key: str, dest: str 140): 141 """ 142 Transfers stake of key from point A to point B 143 """ 144 context = make_custom_context(ctx) 145 client = context.com_client() 146 147 resolved_from = resolve_key_ss58_encrypted(from_key, context) 148 resolved_dest = resolve_key_ss58_encrypted(dest, context) 149 resolved_key = try_classic_load_key(key, context) 150 nano_amount = to_nano(amount) 151 152 with context.progress_status( 153 f"Transferring {amount} tokens from {from_key} to {dest}' ..." 154 ): 155 response = client.transfer_stake( 156 key=resolved_key, 157 amount=nano_amount, 158 from_module_key=resolved_from, 159 dest_module_address=resolved_dest, 160 ) 161 162 if response.is_success: 163 context.info(f"Transferred {amount} tokens from {from_key} to {dest}") 164 else: 165 raise ChainTransactionError(response.error_message) # type: ignore
Transfers stake of key from point A to point B
@balance_app.command()
def
stake(ctx: typer.models.Context, key: str, amount: float, dest: str):
168@balance_app.command() 169def stake( 170 ctx: Context, 171 key: str, 172 amount: float, 173 dest: str, 174): 175 """ 176 Stake amount to destination using key 177 """ 178 context = make_custom_context(ctx) 179 client = context.com_client() 180 181 nano_amount = to_nano(amount) 182 resolved_key = try_classic_load_key(key, context) 183 resolved_dest = resolve_key_ss58_encrypted(dest, context) 184 delegating_message = ( 185 "By default you delegate DAO " 186 "voting power to the validator you stake to. " 187 "In case you want to change this, call: " 188 "`comx key power-delegation <key> --disable`." 189 ) 190 context.info("INFO: ", style="bold green", end="") # type: ignore 191 context.info(delegating_message) # type: ignore 192 with context.progress_status( 193 f"Staking {amount} tokens to {dest}..." 194 ): 195 response = client.stake( 196 key=resolved_key, amount=nano_amount, dest=resolved_dest 197 ) 198 199 if response.is_success: 200 context.info(f"Staked {amount} tokens to {dest}") 201 else: 202 raise ChainTransactionError(response.error_message) # type: ignore
Stake amount to destination using key
@balance_app.command()
def
unstake(ctx: typer.models.Context, key: str, amount: float, dest: str):
205@balance_app.command() 206def unstake(ctx: Context, key: str, amount: float, dest: str): 207 """ 208 Unstake amount from destination using key 209 """ 210 context = make_custom_context(ctx) 211 client = context.com_client() 212 213 nano_amount = to_nano(amount) 214 resolved_key = try_classic_load_key(key, context) 215 resolved_dest = resolve_key_ss58_encrypted(dest, context) 216 217 with context.progress_status( 218 f"Unstaking {amount} tokens from {dest}'..." 219 ): 220 response = client.unstake( 221 key=resolved_key, amount=nano_amount, dest=resolved_dest 222 ) # TODO: is it right? 223 224 if response.is_success: 225 context.info(f"Unstaked {amount} tokens from {dest}") 226 else: 227 raise ChainTransactionError(response.error_message) # type: ignore
Unstake amount from destination using key
@balance_app.command()
def
run_faucet( ctx: typer.models.Context, key: str, num_processes: Optional[int] = None, num_executions: int = 1):
230@balance_app.command() 231def run_faucet( 232 ctx: Context, 233 key: str, 234 num_processes: Optional[int] = None, 235 num_executions: int = 1, 236): 237 context = make_custom_context(ctx) 238 use_testnet = ctx.obj.use_testnet 239 if not use_testnet: 240 context.error("Faucet only enabled on testnet") 241 return 242 resolved_key = try_classic_load_key(key, context) 243 client = context.com_client() 244 for _ in range(num_executions): 245 with context.progress_status("Solving PoW..."): 246 solution = solve_for_difficulty_fast( 247 client, 248 resolved_key, 249 client.url, 250 num_processes=num_processes, 251 ) 252 with context.progress_status("Sending solution to blockchain"): 253 params = { 254 "block_number": solution.block_number, 255 "nonce": solution.nonce, 256 "work": solution.seal, 257 "key": resolved_key.ss58_address, 258 } 259 client.compose_call("faucet", params=params, unsigned=True, 260 module="FaucetModule", key=resolved_key.ss58_address) # type: ignore
@balance_app.command()
def
transfer_dao_funds( ctx: typer.models.Context, signer_key: str, amount: float, cid_hash: str, dest: str):
263@balance_app.command() 264def transfer_dao_funds( 265 ctx: Context, 266 signer_key: str, 267 amount: float, 268 cid_hash: str, 269 dest: str, 270): 271 context = make_custom_context(ctx) 272 if not re.match(IPFS_REGEX, cid_hash): 273 context.error(f"CID provided is invalid: {cid_hash}") 274 exit(1) 275 ipfs_prefix = "ipfs://" 276 cid = ipfs_prefix + cid_hash 277 278 client = context.com_client() 279 280 nano_amount = to_nano(amount) 281 dest = resolve_key_ss58_encrypted(dest, context) 282 signer_keypair = try_classic_load_key(signer_key, context) 283 client.add_transfer_dao_treasury_proposal( 284 signer_keypair, cid, nano_amount, dest 285 )