1
1
use std:: collections:: BTreeMap ;
2
2
3
3
use borsh:: { BorshDeserialize , BorshSerialize } ;
4
+ use masp_primitives:: convert:: AllowedConversion ;
5
+ use masp_primitives:: transaction:: components:: I128Sum ;
6
+ use namada_core:: masp:: encode_asset_type;
4
7
use namada_macros:: BorshDeserializer ;
5
8
use namada_sdk:: address:: Address ;
6
9
use namada_sdk:: ibc:: trace:: ibc_token;
@@ -9,10 +12,12 @@ use namada_sdk::masp_primitives::merkle_tree::FrozenCommitmentTree;
9
12
use namada_sdk:: masp_primitives:: sapling;
10
13
use namada_sdk:: migrations;
11
14
use namada_sdk:: storage:: DbColFam ;
12
- use namada_shielded_token:: storage_key:: masp_reward_precision_key;
13
- use namada_shielded_token:: { ConversionLeaf , ConversionState } ;
15
+ use namada_shielded_token:: storage_key:: {
16
+ masp_conversion_key, masp_reward_precision_key,
17
+ } ;
18
+ use namada_shielded_token:: { ConversionLeaf , ConversionState , MaspEpoch } ;
14
19
use namada_trans_token:: storage_key:: { balance_key, minted_balance_key} ;
15
- use namada_trans_token:: { Amount , Store } ;
20
+ use namada_trans_token:: { Amount , Denomination , MaspDigitPos , Store } ;
16
21
17
22
pub const OLD_CONVERSION_STATE_TYPE_HASH : & str =
18
23
"05E2FD0BEBD54A05AAE349BBDE61F90893F09A72850EFD4F69060821EC5DE65F" ;
@@ -121,8 +126,117 @@ fn shielded_reward_precision_migration() {
121
126
. unwrap ( ) ;
122
127
}
123
128
129
+ // Demonstrate clearing MASP rewards for the given IBC tokens by overwriting
130
+ // their allowed conversions with conversions that do not contain rewards.
131
+ fn shielded_reward_reset_migration ( ) {
132
+ pub type ChannelId = & ' static str ;
133
+ pub type BaseToken = & ' static str ;
134
+ // Valid precisions must be in the intersection of i128 and u128
135
+ pub type Precision = i128 ;
136
+
137
+ // The MASP epoch in which this migration will be applied. This number
138
+ // controls the number of epochs of conversions created.
139
+ const TARGET_MASP_EPOCH : MaspEpoch = MaspEpoch :: new ( 2000 ) ;
140
+ // The denomination of the targetted token. Since all tokens here are IBC
141
+ // tokens, this is 0.
142
+ const DENOMINATION : Denomination = Denomination ( 0u8 ) ;
143
+ // The tokens whose rewarrds will be reset.
144
+ const IBC_TOKENS : [ ( ChannelId , BaseToken , Precision ) ; 6 ] = [
145
+ ( "channel-1" , "uosmo" , 1000i128 ) ,
146
+ ( "channel-2" , "uatom" , 1000i128 ) ,
147
+ ( "channel-3" , "utia" , 1000i128 ) ,
148
+ ( "channel-0" , "stuosmo" , 1000i128 ) ,
149
+ ( "channel-0" , "stuatom" , 1000i128 ) ,
150
+ ( "channel-0" , "stutia" , 1000i128 ) ,
151
+ ] ;
152
+
153
+ let mut updates = Vec :: new ( ) ;
154
+ // Reset the allowed conversions for the above tokens
155
+ for ( channel_id, base_token, precision) in IBC_TOKENS {
156
+ let ibc_denom = format ! ( "transfer/{channel_id}/{base_token}" ) ;
157
+ let token_address = ibc_token ( & ibc_denom) . clone ( ) ;
158
+
159
+ // Erase the TOK rewards that have been distributed so far
160
+ let mut asset_types = BTreeMap :: new ( ) ;
161
+ let mut precision_toks = BTreeMap :: new ( ) ;
162
+ let mut reward_deltas = BTreeMap :: new ( ) ;
163
+ // TOK[ep, digit]
164
+ let mut asset_type = |epoch, digit| {
165
+ * asset_types. entry ( ( epoch, digit) ) . or_insert_with ( || {
166
+ encode_asset_type (
167
+ token_address. clone ( ) ,
168
+ DENOMINATION ,
169
+ digit,
170
+ Some ( epoch) ,
171
+ )
172
+ . expect ( "unable to encode asset type" )
173
+ } )
174
+ } ;
175
+ // PRECISION TOK[ep, digit]
176
+ let mut precision_tok = |epoch, digit| {
177
+ precision_toks
178
+ . entry ( ( epoch, digit) )
179
+ . or_insert_with ( || {
180
+ AllowedConversion :: from ( I128Sum :: from_pair (
181
+ asset_type ( epoch, digit) ,
182
+ precision,
183
+ ) )
184
+ } )
185
+ . clone ( )
186
+ } ;
187
+ // -PRECISION TOK[ep, digit] + PRECISION TOK[ep+1, digit]
188
+ let mut reward_delta = |epoch, digit| {
189
+ reward_deltas
190
+ . entry ( ( epoch, digit) )
191
+ . or_insert_with ( || {
192
+ -precision_tok ( epoch, digit)
193
+ + precision_tok ( epoch. next ( ) . unwrap ( ) , digit)
194
+ } )
195
+ . clone ( )
196
+ } ;
197
+ // Write the new TOK conversions to memory
198
+ for digit in MaspDigitPos :: iter ( ) {
199
+ // -PRECISION TOK[ep, digit] + PRECISION TOK[current_ep, digit]
200
+ let mut reward: AllowedConversion = I128Sum :: zero ( ) . into ( ) ;
201
+ for epoch in MaspEpoch :: iter_bounds_inclusive (
202
+ MaspEpoch :: zero ( ) ,
203
+ TARGET_MASP_EPOCH . prev ( ) . unwrap ( ) ,
204
+ )
205
+ . rev ( )
206
+ {
207
+ // TOK[ep, digit]
208
+ let asset_type = encode_asset_type (
209
+ token_address. clone ( ) ,
210
+ DENOMINATION ,
211
+ digit,
212
+ Some ( epoch) ,
213
+ )
214
+ . expect ( "unable to encode asset type" ) ;
215
+ reward += reward_delta ( epoch, digit) ;
216
+ // Write the conversion update to memory
217
+ updates. push ( migrations:: DbUpdateType :: Add {
218
+ key : masp_conversion_key ( & asset_type) ,
219
+ cf : DbColFam :: SUBSPACE ,
220
+ value : reward. clone ( ) . into ( ) ,
221
+ force : false ,
222
+ } ) ;
223
+ }
224
+ }
225
+ }
226
+
227
+ let changes = migrations:: DbChanges {
228
+ changes : updates. into_iter ( ) . collect ( ) ,
229
+ } ;
230
+ std:: fs:: write (
231
+ "shielded_reward_reset_migration.json" ,
232
+ serde_json:: to_string ( & changes) . unwrap ( ) ,
233
+ )
234
+ . unwrap ( ) ;
235
+ }
236
+
124
237
// Generate various migrations
125
238
fn main ( ) {
126
239
minted_balance_migration ( ) ;
127
240
shielded_reward_precision_migration ( ) ;
241
+ shielded_reward_reset_migration ( ) ;
128
242
}
0 commit comments