Skip to content

Commit 5c5fa3d

Browse files
authored
Merge pull request #530 from lidofinance/susds-hoodi
ET sUSDS support [HOODI]
2 parents ccdc2a8 + 50a1d8e commit 5c5fa3d

File tree

5 files changed

+743
-0
lines changed

5 files changed

+743
-0
lines changed
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
"""
2+
Vote 2025_11_06 (HOODI)
3+
4+
1. Termporarily grant ADD_TOKEN_TO_ALLOWED_LIST_ROLE to Aragon Voting
5+
2. Add sUSDS to the Sandbox stablecoins Allowed Tokens Registry
6+
3. Revoke ADD_TOKEN_TO_ALLOWED_LIST_ROLE from Aragon Voting
7+
4. Remove CREATE_PAYMENTS_ROLE from EVMScriptExecutor on Aragon Finance
8+
5. Grant CREATE_PAYMENTS_ROLE to EVMScriptExecutor on Aragon Finance with amount limits
9+
10+
# Vote #45 passed & executed on Nov-07-2025 02:14:24 PM UTC, block 1573439
11+
.
12+
"""
13+
14+
from typing import Dict, List, Tuple, NamedTuple
15+
16+
from brownie import interface, web3, convert
17+
18+
from utils.voting import bake_vote_items, confirm_vote_script, create_vote
19+
from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description
20+
from utils.config import get_deployer_account, get_is_live, get_priority_fee
21+
from utils.mainnet_fork import pass_and_exec_dao_vote
22+
from utils.permission_parameters import Param, SpecialArgumentID, encode_argument_value_if, ArgumentValue, Op
23+
from utils.permissions import encode_permission_revoke, encode_permission_grant_p
24+
25+
class TokenLimit(NamedTuple):
26+
address: str
27+
limit: int
28+
29+
# ============================== Addresses ===================================
30+
SUSDS_TOKEN = "0xDaE6a7669f9aB8b2C4E52464AA6FB7F9402aDc70"
31+
USDC_TOKEN = "0x97bb030B93faF4684eAC76bA0bf3be5ec7140F36"
32+
USDT_TOKEN = "0x64f1904d1b419c6889BDf3238e31A138E258eA68"
33+
DAI_TOKEN = "0x17fc691f6EF57D2CA719d30b8fe040123d4ee319"
34+
STETH_TOKEN = "0x3508a952176b3c15387c97be809eaffb1982176a"
35+
36+
SANDBOX_STABLES_ALLOWED_TOKENS_REGISTRY = "0x40Db7E8047C487bD8359289272c717eA3C34D1D3"
37+
VOTING = "0x49B3512c44891bef83F8967d075121Bd1b07a01B"
38+
FINANCE = "0x254Ae22bEEba64127F0e59fe8593082F3cd13f6b"
39+
ET_EVM_SCRIPT_EXECUTOR = "0x79a20FD0FA36453B2F45eAbab19bfef43575Ba9E"
40+
ADD_TOKEN_TO_ALLOWED_LIST_ROLE = "ADD_TOKEN_TO_ALLOWED_LIST_ROLE"
41+
CREATE_PAYMENTS_ROLE = "CREATE_PAYMENTS_ROLE"
42+
43+
STABLES_LIMIT = 1_000
44+
USDC_LIMIT = TokenLimit(USDC_TOKEN, STABLES_LIMIT * 10**6)
45+
USDT_LIMIT = TokenLimit(USDT_TOKEN, STABLES_LIMIT * 10**6)
46+
DAI_LIMIT = TokenLimit(DAI_TOKEN, STABLES_LIMIT * 10**18)
47+
SUSDS_LIMIT = TokenLimit(SUSDS_TOKEN, STABLES_LIMIT * 10**18)
48+
STETH_LIMIT = TokenLimit(STETH_TOKEN, 200 * 10**18)
49+
50+
def amount_limits() -> List[Param]:
51+
token_arg_index = 0
52+
amount_arg_index = 2
53+
54+
return [
55+
# 0: if (1) then (2) else (3)
56+
Param(
57+
SpecialArgumentID.LOGIC_OP_PARAM_ID, Op.IF_ELSE, encode_argument_value_if(condition=1, success=2, failure=3)
58+
),
59+
# 1: (_token == USDC)
60+
Param(token_arg_index, Op.EQ, ArgumentValue(USDC_LIMIT.address)),
61+
# 2: { return _amount <= 1_000 }
62+
Param(amount_arg_index, Op.LTE, ArgumentValue(USDC_LIMIT.limit)),
63+
#
64+
# 3: else if (4) then (5) else (6)
65+
Param(
66+
SpecialArgumentID.LOGIC_OP_PARAM_ID, Op.IF_ELSE, encode_argument_value_if(condition=4, success=5, failure=6)
67+
),
68+
# 4: (_token == USDT)
69+
Param(token_arg_index, Op.EQ, ArgumentValue(USDT_LIMIT.address)),
70+
# 5: { return _amount <= 1_000 }
71+
Param(amount_arg_index, Op.LTE, ArgumentValue(USDT_LIMIT.limit)),
72+
#
73+
# 6: else if (7) then (8) else (9)
74+
Param(
75+
SpecialArgumentID.LOGIC_OP_PARAM_ID, Op.IF_ELSE, encode_argument_value_if(condition=7, success=8, failure=9)
76+
),
77+
# 7: (_token == DAI)
78+
Param(token_arg_index, Op.EQ, ArgumentValue(DAI_LIMIT.address)),
79+
# 8: { return _amount <= 1_000 }
80+
Param(amount_arg_index, Op.LTE, ArgumentValue(DAI_LIMIT.limit)),
81+
#
82+
# 9: else if (10) then (11) else (12)
83+
Param(
84+
SpecialArgumentID.LOGIC_OP_PARAM_ID, Op.IF_ELSE, encode_argument_value_if(condition=10, success=11, failure=12),
85+
),
86+
# 10: (_token == SUSDS)
87+
Param(token_arg_index, Op.EQ, ArgumentValue(SUSDS_LIMIT.address)),
88+
# 11: { return _amount <= 1_000 }
89+
Param(amount_arg_index, Op.LTE, ArgumentValue(SUSDS_LIMIT.limit)),
90+
#
91+
# 12: else if (13) then (14) else (15)
92+
Param(
93+
SpecialArgumentID.LOGIC_OP_PARAM_ID, Op.IF_ELSE, encode_argument_value_if(condition=13, success=14, failure=15),
94+
),
95+
# 13: (_token == STETH)
96+
Param(token_arg_index, Op.EQ, ArgumentValue(STETH_LIMIT.address)),
97+
# 14: { return _amount <= 200 }
98+
Param(amount_arg_index, Op.LTE, ArgumentValue(STETH_LIMIT.limit)),
99+
#
100+
# 15: else { return false }
101+
Param(SpecialArgumentID.PARAM_VALUE_PARAM_ID, Op.RET, ArgumentValue(0)),
102+
]
103+
104+
# ============================= Description ==================================
105+
IPFS_DESCRIPTION = "sUSDS swaps (HOODI)"
106+
107+
108+
# ================================ Main ======================================
109+
def get_vote_items() -> Tuple[List[str], List[Tuple[str, str]]]:
110+
111+
sandbox_stables_allowed_tokens_registry = interface.AllowedTokensRegistry(SANDBOX_STABLES_ALLOWED_TOKENS_REGISTRY)
112+
113+
vote_desc_items, call_script_items = zip(
114+
(
115+
"1. Termporarily grant ADD_TOKEN_TO_ALLOWED_LIST_ROLE to Aragon Voting",
116+
(
117+
sandbox_stables_allowed_tokens_registry.address, sandbox_stables_allowed_tokens_registry.grantRole.encode_input(
118+
convert.to_uint(web3.keccak(text=ADD_TOKEN_TO_ALLOWED_LIST_ROLE)),
119+
VOTING,
120+
)
121+
)
122+
),
123+
(
124+
"2. Add sUSDS to the Sandbox stablecoins Allowed Tokens Registry",
125+
(sandbox_stables_allowed_tokens_registry.address, sandbox_stables_allowed_tokens_registry.addToken.encode_input(SUSDS_TOKEN))
126+
),
127+
(
128+
"3. Revoke ADD_TOKEN_TO_ALLOWED_LIST_ROLE from Aragon Voting",
129+
(
130+
sandbox_stables_allowed_tokens_registry.address, sandbox_stables_allowed_tokens_registry.revokeRole.encode_input(
131+
convert.to_uint(web3.keccak(text=ADD_TOKEN_TO_ALLOWED_LIST_ROLE)),
132+
VOTING,
133+
)
134+
)
135+
),
136+
(
137+
"4. Remove CREATE_PAYMENTS_ROLE from EVMScriptExecutor on Aragon Finance",
138+
encode_permission_revoke(
139+
target_app=FINANCE,
140+
permission_name=CREATE_PAYMENTS_ROLE,
141+
revoke_from=ET_EVM_SCRIPT_EXECUTOR,
142+
),
143+
),
144+
(
145+
"5. Grant CREATE_PAYMENTS_ROLE to EVMScriptExecutor on Aragon Finance with amount limits",
146+
encode_permission_grant_p(
147+
target_app=FINANCE,
148+
permission_name=CREATE_PAYMENTS_ROLE,
149+
grant_to=ET_EVM_SCRIPT_EXECUTOR,
150+
params=amount_limits(),
151+
),
152+
),
153+
)
154+
155+
156+
return vote_desc_items, call_script_items
157+
158+
159+
def start_vote(tx_params: Dict[str, str], silent: bool = False):
160+
vote_desc_items, call_script_items = get_vote_items()
161+
vote_items = bake_vote_items(list(vote_desc_items), list(call_script_items))
162+
163+
desc_ipfs = (
164+
calculate_vote_ipfs_description(IPFS_DESCRIPTION)
165+
if silent else upload_vote_ipfs_description(IPFS_DESCRIPTION)
166+
)
167+
168+
vote_id, tx = confirm_vote_script(vote_items, silent, desc_ipfs) and list(
169+
create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs)
170+
)
171+
172+
return vote_id, tx
173+
174+
175+
def main():
176+
tx_params: Dict[str, str] = {"from": get_deployer_account().address}
177+
if get_is_live():
178+
tx_params["priority_fee"] = get_priority_fee()
179+
180+
vote_id, _ = start_vote(tx_params=tx_params, silent=False)
181+
vote_id >= 0 and print(f"Vote created: {vote_id}.")
182+
183+
184+
def start_and_execute_vote_on_fork_manual():
185+
if get_is_live():
186+
raise Exception("This script is for local testing only.")
187+
188+
tx_params = {"from": get_deployer_account()}
189+
vote_id, _ = start_vote(tx_params=tx_params, silent=True)
190+
print(f"Vote created: {vote_id}.")
191+
pass_and_exec_dao_vote(int(vote_id), step_by_step=True)

0 commit comments

Comments
 (0)