Skip to content

Commit b7b08cf

Browse files
committed
Implemented a migration to reset existing MASP rewards.
1 parent 963d2ff commit b7b08cf

File tree

5 files changed

+127
-4
lines changed

5 files changed

+127
-4
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/migrations/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ repository.workspace = true
1313
version.workspace = true
1414
rust-version.workspace = true
1515

16+
[features]
17+
masp = ["masp_primitives"]
18+
1619
[dependencies]
20+
masp_primitives = { workspace = true, optional = true }
1721
namada_macros.workspace = true
1822

1923
lazy_static.workspace = true

crates/migrations/src/foreign_types.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ derive_typehash!(Vec::<u8>);
1212
derive_typehash!(Vec::<String>);
1313
derive_typehash!(u64);
1414
derive_typehash!(u128);
15+
#[cfg(feature = "masp")]
16+
derive_typehash!(masp_primitives::convert::AllowedConversion);

examples/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ masp_proofs = { workspace = true, default-features = false, features = [
3434
"download-params",
3535
] }
3636
namada_apps_lib = { workspace = true, features = ["migrations"] }
37+
namada_core = { workspace = true, default-features = false }
3738
namada_macros = { workspace = true }
38-
namada_migrations = { workspace = true }
39+
namada_migrations = { workspace = true, features = ["masp"] }
3940
namada_parameters = { workspace = true }
4041
namada_trans_token = { workspace = true, features = ["migrations"] }
4142
namada_sdk = { workspace = true, default-features = false, features = [

examples/make-db-migration.rs

+117-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use std::collections::BTreeMap;
22

33
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;
47
use namada_macros::BorshDeserializer;
58
use namada_sdk::address::Address;
69
use namada_sdk::ibc::trace::ibc_token;
@@ -9,10 +12,12 @@ use namada_sdk::masp_primitives::merkle_tree::FrozenCommitmentTree;
912
use namada_sdk::masp_primitives::sapling;
1013
use namada_sdk::migrations;
1114
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};
1419
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};
1621

1722
pub const OLD_CONVERSION_STATE_TYPE_HASH: &str =
1823
"05E2FD0BEBD54A05AAE349BBDE61F90893F09A72850EFD4F69060821EC5DE65F";
@@ -121,8 +126,117 @@ fn shielded_reward_precision_migration() {
121126
.unwrap();
122127
}
123128

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+
124237
// Generate various migrations
125238
fn main() {
126239
minted_balance_migration();
127240
shielded_reward_precision_migration();
241+
shielded_reward_reset_migration();
128242
}

0 commit comments

Comments
 (0)