use std::str::FromStr;
use masp_primitives::asset_type::AssetType;
use masp_primitives::bls12_381::Scalar;
use masp_primitives::sapling::{Node, Nullifier};
use namada_core::address::{self, Address};
use namada_core::hash::Hash;
use namada_core::masp::MaspEpoch;
use namada_core::storage::{self, DbKeySeg, KeySeg};
use namada_systems::trans_token;
const BALANCE_STORAGE_KEY: &str = "balance";
pub const MASP_NULLIFIERS_KEY: &str = "nullifiers";
pub const MASP_UNDATED_BALANCE_KEY: &str = "undated_balance";
pub const MASP_CONVERSIONS_KEY: &str = "conversions";
pub const MASP_SCHEDULED_REWARD_PRECISION_KEY: &str =
"scheduled_reward_precision";
pub const MASP_SCHEDULED_BASE_NATIVE_PRECISION_KEY: &str =
"scheduled_base_native_precision";
pub const MASP_NOTE_COMMITMENT_TREE_KEY: &str = "commitment_tree";
pub const MASP_NOTE_COMMITMENT_ANCHOR_PREFIX: &str = "note_commitment_anchor";
pub const MASP_CONVERT_ANCHOR_KEY: &str = "convert_anchor";
pub const MASP_TOKEN_MAP_KEY: &str = "tokens";
pub const MASP_ASSETS_HASH_KEY: &str = "assets_hash";
pub const MASP_LAST_INFLATION_KEY: &str = "last_inflation";
pub const MASP_LAST_LOCKED_AMOUNT_KEY: &str = "last_locked_amount";
pub const MASP_KP_GAIN_KEY: &str = "proportional_gain";
pub const MASP_KD_GAIN_KEY: &str = "derivative_gain";
pub const MASP_LOCKED_AMOUNT_TARGET_KEY: &str = "locked_amount_target";
pub const MASP_MAX_REWARD_RATE_KEY: &str = "max_reward_rate";
pub const MASP_TOTAL_REWARDS: &str = "max_total_rewards";
pub const MASP_REWARD_PRECISION_KEY: &str = "reward_precision";
pub const MASP_BASE_NATIVE_PRECISION_KEY: &str = "base_native_precision";
pub fn masp_kp_gain_key<TransToken: trans_token::Keys>(
token_addr: &Address,
) -> storage::Key {
TransToken::parameter_prefix(token_addr)
.with_segment(MASP_KP_GAIN_KEY.to_owned())
}
pub fn masp_kd_gain_key<TransToken: trans_token::Keys>(
token_addr: &Address,
) -> storage::Key {
TransToken::parameter_prefix(token_addr)
.with_segment(MASP_KD_GAIN_KEY.to_owned())
}
pub fn masp_max_reward_rate_key<TransToken: trans_token::Keys>(
token_addr: &Address,
) -> storage::Key {
TransToken::parameter_prefix(token_addr)
.with_segment(MASP_MAX_REWARD_RATE_KEY.to_owned())
}
pub fn masp_reward_precision_key<TransToken: trans_token::Keys>(
token_addr: &Address,
) -> storage::Key {
TransToken::parameter_prefix(token_addr)
.with_segment(MASP_REWARD_PRECISION_KEY.to_owned())
}
pub fn masp_locked_amount_target_key<TransToken: trans_token::Keys>(
token_addr: &Address,
) -> storage::Key {
TransToken::parameter_prefix(token_addr)
.with_segment(MASP_LOCKED_AMOUNT_TARGET_KEY.to_owned())
}
pub fn masp_last_locked_amount_key<TransToken: trans_token::Keys>(
token_address: &Address,
) -> storage::Key {
TransToken::parameter_prefix(token_address)
.with_segment(MASP_LAST_LOCKED_AMOUNT_KEY.to_owned())
}
pub fn masp_last_inflation_key<TransToken: trans_token::Keys>(
token_address: &Address,
) -> storage::Key {
TransToken::parameter_prefix(token_address)
.with_segment(MASP_LAST_INFLATION_KEY.to_owned())
}
pub fn is_masp_scheduled_reward_precision_key(
key: &storage::Key,
) -> Option<(MaspEpoch, Address)> {
match &key.segments[..] {
[
DbKeySeg::AddressSeg(address::MASP),
DbKeySeg::StringSeg(prefix),
DbKeySeg::StringSeg(epoch),
DbKeySeg::StringSeg(token),
] if prefix == MASP_SCHEDULED_REWARD_PRECISION_KEY => {
MaspEpoch::from_str(epoch)
.ok()
.zip(Address::from_str(token).ok())
}
_ => None,
}
}
pub fn is_masp_scheduled_base_native_precision_key(
key: &storage::Key,
) -> Option<MaspEpoch> {
match &key.segments[..] {
[
DbKeySeg::AddressSeg(address::MASP),
DbKeySeg::StringSeg(prefix),
DbKeySeg::StringSeg(epoch),
] if prefix == MASP_SCHEDULED_BASE_NATIVE_PRECISION_KEY => {
MaspEpoch::from_str(epoch).ok()
}
_ => None,
}
}
pub fn masp_scheduled_reward_precision_key(
epoch: &MaspEpoch,
token_address: &Address,
) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.with_segment(MASP_SCHEDULED_REWARD_PRECISION_KEY.to_owned())
.with_segment(epoch.to_string())
.with_segment(token_address.to_string().to_db_key())
}
pub fn masp_scheduled_reward_precision_key_prefix(
ep: &MaspEpoch,
) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_SCHEDULED_REWARD_PRECISION_KEY.to_owned())
.expect("Cannot obtain a storage key")
.push(&ep.to_string())
.expect("Cannot obtain a storage key")
}
pub fn masp_scheduled_base_native_precision_key(
ep: &MaspEpoch,
) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_SCHEDULED_BASE_NATIVE_PRECISION_KEY.to_owned())
.expect("Cannot obtain a storage key")
.push(&ep.to_string())
.expect("Cannot obtain a storage key")
}
pub fn is_masp_undated_balance_key(key: &storage::Key) -> Option<Address> {
match &key.segments[..] {
[
DbKeySeg::AddressSeg(address::MASP),
DbKeySeg::StringSeg(prefix),
DbKeySeg::StringSeg(token),
] if prefix == MASP_UNDATED_BALANCE_KEY => {
Address::from_str(token).ok()
}
_ => None,
}
}
pub fn masp_undated_balance_key(token_address: &Address) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.with_segment(MASP_UNDATED_BALANCE_KEY.to_owned())
.with_segment(token_address.to_string().to_db_key())
}
pub fn is_masp_balance_key(key: &storage::Key) -> bool {
matches!(
&key.segments[..],
[DbKeySeg::AddressSeg(addr), DbKeySeg::AddressSeg(_token), DbKeySeg::StringSeg(balance), DbKeySeg::AddressSeg(owner)]
if *addr
== Address::Internal(address::InternalAddress::Multitoken)
&& balance == BALANCE_STORAGE_KEY
&& *owner == address::MASP
)
}
pub fn is_masp_key(key: &storage::Key) -> bool {
match &key.segments[..] {
[DbKeySeg::AddressSeg(addr), ..] if *addr == address::MASP => true,
_ => is_masp_balance_key(key),
}
}
pub fn is_masp_governance_key(key: &storage::Key) -> bool {
is_masp_token_map_key(key)
|| is_masp_conversion_key(key).is_some()
|| is_masp_scheduled_reward_precision_key(key).is_some()
|| is_masp_base_native_precision_key(key)
|| is_masp_scheduled_base_native_precision_key(key).is_some()
}
pub fn is_masp_transfer_key(key: &storage::Key) -> bool {
is_masp_commitment_tree_key(key)
|| is_masp_nullifier_key(key)
|| is_masp_balance_key(key)
|| is_masp_undated_balance_key(key).is_some()
}
pub fn is_masp_commitment_tree_key(key: &storage::Key) -> bool {
matches!(&key.segments[..],
[DbKeySeg::AddressSeg(addr), DbKeySeg::StringSeg(key)]
if *addr == address::MASP
&& key == MASP_NOTE_COMMITMENT_TREE_KEY)
}
pub fn is_masp_nullifier_key(key: &storage::Key) -> bool {
matches!(&key.segments[..],
[DbKeySeg::AddressSeg(addr),
DbKeySeg::StringSeg(prefix),
DbKeySeg::StringSeg(_nullifier),
] if *addr == address::MASP && prefix == MASP_NULLIFIERS_KEY)
}
pub fn is_masp_commitment_anchor_key(key: &storage::Key) -> Option<Node> {
match &key.segments[..] {
[
DbKeySeg::AddressSeg(addr),
DbKeySeg::StringSeg(prefix),
DbKeySeg::StringSeg(anchor),
] if *addr == address::MASP
&& prefix == MASP_NOTE_COMMITMENT_ANCHOR_PREFIX =>
{
Hash::from_str(anchor).map(|x| Node::new(x.0)).ok()
}
_ => None,
}
}
pub fn is_masp_token_map_key(key: &storage::Key) -> bool {
matches!(&key.segments[..],
[DbKeySeg::AddressSeg(addr),
DbKeySeg::StringSeg(prefix),
] if *addr == address::MASP && prefix == MASP_TOKEN_MAP_KEY)
}
pub fn is_masp_base_native_precision_key(key: &storage::Key) -> bool {
matches!(&key.segments[..],
[DbKeySeg::AddressSeg(addr),
DbKeySeg::StringSeg(prefix),
] if *addr == address::MASP && prefix == MASP_BASE_NATIVE_PRECISION_KEY)
}
pub fn is_masp_conversion_key(
key: &storage::Key,
) -> Option<(MaspEpoch, AssetType)> {
match &key.segments[..] {
[
DbKeySeg::AddressSeg(address::MASP),
DbKeySeg::StringSeg(prefix),
DbKeySeg::StringSeg(epoch),
DbKeySeg::StringSeg(asset_type),
] if prefix == MASP_CONVERSIONS_KEY => MaspEpoch::from_str(epoch)
.ok()
.zip(AssetType::from_str(asset_type).ok()),
_ => None,
}
}
pub fn masp_nullifier_key(nullifier: &Nullifier) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_NULLIFIERS_KEY.to_owned())
.expect("Cannot obtain a storage key")
.push(&Hash(nullifier.0))
.expect("Cannot obtain a storage key")
}
pub fn masp_conversion_key(
ep: &MaspEpoch,
asset_type: &AssetType,
) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_CONVERSIONS_KEY.to_owned())
.expect("Cannot obtain a storage key")
.push(&ep.to_string())
.expect("Cannot obtain a storage key")
.push(&asset_type.to_string())
.expect("Cannot obtain a storage key")
}
pub fn masp_conversion_key_prefix(ep: &MaspEpoch) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_CONVERSIONS_KEY.to_owned())
.expect("Cannot obtain a storage key")
.push(&ep.to_string())
.expect("Cannot obtain a storage key")
}
pub fn masp_commitment_tree_key() -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_NOTE_COMMITMENT_TREE_KEY.to_owned())
.expect("Cannot obtain a storage key")
}
pub fn masp_commitment_anchor_key(anchor: impl Into<Scalar>) -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_NOTE_COMMITMENT_ANCHOR_PREFIX.to_owned())
.expect("Cannot obtain a storage key")
.push(&Hash(anchor.into().to_bytes_le()))
.expect("Cannot obtain a storage key")
}
pub fn masp_convert_anchor_key() -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_CONVERT_ANCHOR_KEY.to_owned())
.expect("Cannot obtain a storage key")
}
pub fn masp_token_map_key() -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_TOKEN_MAP_KEY.to_owned())
.expect("Cannot obtain a storage key")
}
pub fn masp_base_native_precision_key() -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_BASE_NATIVE_PRECISION_KEY.to_owned())
.expect("Cannot obtain a storage key")
}
pub fn masp_assets_hash_key() -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_ASSETS_HASH_KEY.to_owned())
.expect("Cannot obtain a storage key")
}
pub fn masp_total_rewards() -> storage::Key {
storage::Key::from(address::MASP.to_db_key())
.push(&MASP_TOTAL_REWARDS.to_owned())
.expect("Cannot obtain a storage key")
}