Skip to content

Commit a3a77b0

Browse files
committed
feature: emission proposal
1 parent a0e7ac8 commit a3a77b0

File tree

11 files changed

+231
-78
lines changed

11 files changed

+231
-78
lines changed

src/torusdk/_common.py

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,17 @@
22
import re
33
import warnings
44
from collections import defaultdict
5-
from enum import Enum
65
from typing import Any, Callable, Mapping, TypeVar
76

87
from pydantic import SecretStr
98
from pydantic_settings import BaseSettings, SettingsConfigDict
109

11-
from torusdk.balance import from_rems
1210
from torusdk.types.types import Ss58Address
1311

1412
IPFS_REGEX = re.compile(r"^Qm[1-9A-HJ-NP-Za-km-z]{44}$")
1513
SS58_FORMAT = 42
1614

1715

18-
def extract_ipfs():
19-
pass
20-
21-
2216
def deprecated(func: Callable[..., Any]) -> Callable[..., Any]:
2317
def wrapper(*args: Any, **kwargs: Any) -> Any:
2418
warnings.warn(
@@ -66,27 +60,6 @@ def get_available_nodes(
6660
return node_urls
6761

6862

69-
class BalanceUnit(str, Enum):
70-
joule = "rems"
71-
j = "r"
72-
nano = "torus"
73-
n = "t"
74-
75-
76-
def format_balance(balance: int, unit: BalanceUnit = BalanceUnit.nano) -> str:
77-
"""
78-
Formats a balance.
79-
"""
80-
81-
match unit:
82-
case BalanceUnit.nano | BalanceUnit.n:
83-
return f"{balance}"
84-
case BalanceUnit.joule | BalanceUnit.j:
85-
in_joules = from_rems(balance)
86-
round_joules = round(in_joules, 4)
87-
return f"{round_joules:,}" + " \u2653"
88-
89-
9063
K = TypeVar("K")
9164
V = TypeVar("V")
9265
Z = TypeVar("Z")

src/torusdk/balance.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
from enum import Enum
12
from typing import Any, TypeVar
23

34
DECIMALS = 18
4-
UNIT_NAME = "Toids"
5+
UNIT_NAME = "Rems"
56

67

78
def from_rems(amount: int) -> float:
@@ -20,12 +21,25 @@ def to_rems(amount: float) -> int:
2021
return int(amount * (10**DECIMALS))
2122

2223

23-
class Rem(int):
24-
def __new__(cls, value: int):
25-
return super().__new__(cls, value)
24+
class BalanceUnit(str, Enum):
25+
joule = "rems"
26+
j = "r"
27+
nano = "torus"
28+
n = "t"
2629

27-
def __mul__(self, other: int):
28-
return Rem(super().__mul__(other))
30+
31+
def format_balance(balance: int, unit: BalanceUnit = BalanceUnit.nano) -> str:
32+
"""
33+
Formats a balance.
34+
"""
35+
36+
match unit:
37+
case BalanceUnit.nano | BalanceUnit.n:
38+
return f"{balance}"
39+
case BalanceUnit.joule | BalanceUnit.j:
40+
in_joules = from_rems(balance)
41+
round_joules = round(in_joules, 4)
42+
return f"{round_joules:,}" + " \u2653"
2943

3044

3145
def from_horus(amount: int, subnet_tempo: int = 100) -> float:
@@ -46,9 +60,6 @@ def repr_j(amount: int):
4660
return f"{from_rems(amount)} {UNIT_NAME}"
4761

4862

49-
breakpoint()
50-
51-
5263
T = TypeVar("T", str, int)
5364

5465

src/torusdk/cli/_common.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from dataclasses import dataclass
23
from getpass import getpass
34
from typing import Any, Callable, Mapping, TypeVar, cast
@@ -12,8 +13,8 @@
1213
from torustrateinterface import Keypair
1314
from typer import Context
1415

15-
from torusdk._common import TorusSettings, get_node_url
16-
from torusdk.balance import dict_from_nano, from_rems
16+
from torusdk._common import IPFS_REGEX, TorusSettings, get_node_url
17+
from torusdk.balance import dict_from_nano, from_rems, to_rems
1718
from torusdk.client import TorusClient
1819
from torusdk.errors import InvalidPasswordError, PasswordNotProvidedError
1920
from torusdk.key import load_keypair, resolve_key_ss58
@@ -52,6 +53,19 @@ def merge_models(model_a: T, model_b: BaseModel) -> T:
5253
return model_a.__class__(**merged_dict)
5354

5455

56+
def extract_cid(value: str):
57+
cid_hash = re.match(IPFS_REGEX, value)
58+
if not cid_hash:
59+
raise typer.BadParameter(f"CID provided is invalid: {value}")
60+
return cid_hash.group()
61+
62+
63+
def input_to_rems(value: float | None):
64+
if value is None:
65+
return None
66+
return to_rems(value)
67+
68+
5569
@dataclass
5670
class ExtraCtxData:
5771
output_json: bool

src/torusdk/cli/balance.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import typer
44
from typer import Context
55

6-
from torusdk._common import BalanceUnit, format_balance
7-
from torusdk.balance import to_rems
6+
from torusdk.balance import BalanceUnit, format_balance, to_rems
87
from torusdk.cli._common import (
98
NOT_IMPLEMENTED_MESSAGE,
109
make_custom_context,

src/torusdk/cli/key.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from typeguard import check_type
99
from typer import Context
1010

11-
from torusdk._common import SS58_FORMAT, BalanceUnit, format_balance
11+
from torusdk._common import SS58_FORMAT
12+
from torusdk.balance import BalanceUnit, format_balance
1213
from torusdk.cli._common import (
1314
make_custom_context,
1415
print_table_from_plain_dict,

src/torusdk/cli/misc.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
import typer
44
from typer import Context
55

6-
from torusdk._common import BalanceUnit, format_balance
7-
from torusdk.balance import from_rems
6+
from torusdk.balance import BalanceUnit, format_balance, from_rems
87
from torusdk.cli._common import (
98
HIDE_FEATURES,
109
make_custom_context,

src/torusdk/cli/proposal.py

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import re
2-
from typing import Optional, Union
2+
from typing import Optional
33

44
import typer
55
from rich.progress import track
@@ -9,21 +9,29 @@
99
from torusdk.balance import to_rems
1010
from torusdk.cli._common import (
1111
CustomCtx,
12+
extract_cid,
13+
input_to_rems,
1214
make_custom_context,
15+
merge_models,
1316
render_pydantic_table,
1417
)
1518
from torusdk.client import TorusClient
1619
from torusdk.key import local_key_adresses
17-
from torusdk.misc import local_keys_to_stakedbalance, get_global_params
18-
from torusdk.types.types import OptionalNetworkParams
20+
from torusdk.misc import (
21+
get_emission_params,
22+
get_global_params,
23+
local_keys_to_stakedbalance,
24+
)
1925
from torusdk.types.proposal import (
20-
Proposal,
26+
Emission,
2127
GlobalCustom,
2228
GlobalParams,
23-
Emission,
29+
OptionalEmission,
30+
Proposal,
31+
TransferDaoTreasury,
2432
)
33+
from torusdk.types.types import OptionalNetworkParams
2534
from torusdk.util import convert_cid_on_proposal
26-
from torusdk.cli._common import merge_models
2735

2836
proposal_app = typer.Typer(no_args_is_help=True)
2937

@@ -135,33 +143,31 @@ def list_proposals(ctx: Context, query_cid: bool = typer.Option(True)):
135143
emission_p = [
136144
*filter(lambda x: isinstance(x.data, Emission), parsed_proposals)
137145
]
138-
146+
transfer_p = [
147+
*filter(
148+
lambda x: isinstance(x.data, TransferDaoTreasury), parsed_proposals
149+
)
150+
]
139151
render_pydantic_table(
140152
custom_p, context.console, "Custom Proposals", ["data"]
141153
)
142154
render_pydantic_table(
143155
global_params_p, context.console, "Global Params Proposals"
144156
)
145157
render_pydantic_table(emission_p, context.console, "Emission Proposals")
158+
render_pydantic_table(transfer_p, context.console, "Transfer Proposals")
146159

147160

148161
@proposal_app.command()
149162
def transfer_dao_funds(
150163
ctx: Context,
151164
signer_key: str,
152165
amount: float,
153-
cid_hash: str,
154166
dest: str,
167+
cid: str = typer.Argument(..., callback=extract_cid),
155168
):
156169
context = make_custom_context(ctx)
157170

158-
if not re.match(IPFS_REGEX, cid_hash):
159-
context.error(f"CID provided is invalid: {cid_hash}")
160-
raise typer.Exit(code=1)
161-
162-
ipfs_prefix = "ipfs://"
163-
cid = ipfs_prefix + cid_hash
164-
165171
nano_amount = to_rems(amount)
166172
keypair = context.load_key(signer_key, None)
167173
dest = context.resolve_ss58(dest)
@@ -174,16 +180,20 @@ def transfer_dao_funds(
174180
def propose_globally(
175181
ctx: Context,
176182
key: str,
177-
cid: str,
183+
cid_hash: str = typer.Argument(..., callback=extract_cid),
178184
max_name_length: Optional[int] = None,
179185
min_name_length: Optional[int] = None,
180186
max_allowed_agents: Optional[int] = None,
181187
max_allowed_weights: Optional[int] = None,
182188
min_weight_stake: Optional[int] = None,
183189
min_weight_control_fee: Optional[int] = None,
184-
min_staking_fee: Optional[int] = None,
190+
min_staking_fee: Optional[float] = typer.Argument(
191+
..., callback=input_to_rems
192+
),
185193
dividends_participation_weight: Optional[int] = None,
186-
proposal_cost: Optional[int] = None,
194+
proposal_cost: Optional[float] = typer.Argument(
195+
..., callback=input_to_rems
196+
),
187197
):
188198
local_variables = locals()
189199
proposal_args = OptionalNetworkParams.model_validate(local_variables)
@@ -194,18 +204,23 @@ def propose_globally(
194204
proposal = merge_models(global_params, proposal_args)
195205

196206
kp = context.load_key(key)
197-
cid_hash = re.match(IPFS_REGEX, cid)
198-
if not cid_hash:
199-
context.error(f"CID provided is invalid: {cid}")
200-
raise typer.Exit(code=1)
201-
client.add_global_proposal(kp, proposal, cid)
207+
client.add_global_proposal(kp, proposal, cid_hash)
202208

203209

204210
@proposal_app.command()
205211
def propose_emission(
206212
ctx: Context,
207213
key: str,
208-
recycling_percentage: Optional[int],
209-
treasury_percentage: Optional[int],
214+
cid: str = typer.Argument(..., callback=extract_cid),
215+
recycling_percentage: Optional[int] = typer.Option(None),
216+
treasury_percentage: Optional[int] = typer.Option(None),
210217
):
211-
pass
218+
local_variables = locals()
219+
proposal_args = OptionalEmission.model_validate(local_variables)
220+
221+
context = make_custom_context(ctx)
222+
client = context.com_client()
223+
emission_params = get_emission_params(client)
224+
proposal = merge_models(emission_params, proposal_args)
225+
kp = context.load_key(key)
226+
client.add_emission_proposal(kp, proposal, cid)

src/torusdk/client.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from torusdk._common import transform_stake_dmap
1717
from torusdk.errors import ChainTransactionError, NetworkQueryError
18+
from torusdk.types.proposal import Emission
1819
from torusdk.types.types import (
1920
Agent,
2021
AgentApplication,
@@ -1714,6 +1715,43 @@ def add_global_proposal(
17141715

17151716
return response
17161717

1718+
def add_emission_proposal(
1719+
self,
1720+
key: Keypair,
1721+
params: Emission,
1722+
cid: str,
1723+
):
1724+
"""
1725+
Submits a proposal for altering the emission parameters of the network.
1726+
1727+
Allows for the submission of a proposal to change the emission
1728+
parameters of the network, such as the block reward, emission curve,
1729+
and other emission-related settings.
1730+
1731+
Args:
1732+
key: The keypair used for signing the proposal transaction.
1733+
params: A dictionary containing emission parameters like the block
1734+
reward, emission curve, and other emission-related settings.
1735+
1736+
Returns:
1737+
A receipt of the emission proposal transaction.
1738+
1739+
Raises:
1740+
InvalidParameterError: If the provided emission parameters are invalid.
1741+
ChainTransactionError: If the transaction fails.
1742+
"""
1743+
1744+
raw_emission = params.model_dump()
1745+
emission_params = {"data": cid, **raw_emission}
1746+
response = self.compose_call(
1747+
fn="add_emission_proposal",
1748+
params=emission_params,
1749+
key=key,
1750+
module="Governance",
1751+
)
1752+
1753+
return response
1754+
17171755
def vote_on_proposal(
17181756
self,
17191757
key: Keypair,

0 commit comments

Comments
 (0)