1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
use std::ops::Deref;

use crate::{
    scrt::snip20::client::msg::ContractStatusLevel,
    storage::Segment,
    prelude::{
        BlockInfo, CanonicalAddr, StdResult, Storage, Uint128,
        ViewingKey, ViewingKeyHashed, SingleItem, ItemSpace,
        TypedKey, TypedKey2
    }
};

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

crate::namespace!(pub ConstantsNs, b"N3QP0mNoPG");
pub const CONSTANTS: SingleItem<Constants, ConstantsNs> = SingleItem::new();

crate::namespace!(pub TotalSupplyNs, b"bx98UUOWYa");
pub const TOTAL_SUPPLY: TotalSupplyStore = TotalSupplyStore(SingleItem::new());

crate::namespace!(pub ContractStatusNs, b"EhYS9rzai1");
pub const STATUS: SingleItem<ContractStatusLevel, ContractStatusNs> = SingleItem::new();

crate::namespace!(pub MintersNs, b"wpitCjS7wB");
pub const MINTERS: MintersStore = MintersStore(SingleItem::new());

#[doc(hidden)]
pub struct MintersStore(pub SingleItem<Vec<CanonicalAddr>, MintersNs>);

#[doc(hidden)]
pub struct TotalSupplyStore(pub SingleItem<Uint128, TotalSupplyNs>);

// Config
#[derive(Serialize, Debug, Deserialize, Clone, PartialEq, JsonSchema)]
pub struct Constants {
    pub name: String,
    pub symbol: String,
    pub decimals: u8,
    pub prng_seed: Vec<u8>,
    // privacy configuration
    pub total_supply_is_public: bool,
    // is deposit enabled
    pub deposit_is_enabled: bool,
    // is redeem enabled
    pub redeem_is_enabled: bool,
    // is mint enabled
    pub mint_is_enabled: bool,
    // is burn enabled
    pub burn_is_enabled: bool
}

crate::namespace!(BalancesNs, b"DyCKbmlEL8");
crate::namespace!(AllowancesNs, b"eXDXajOxRG");
crate::namespace!(ViewingKeyNs, b"MLRCoHCV8x");
crate::namespace!(ReceierHashNs, b"V1SJqXtGju");

#[derive(PartialEq, Debug)]
pub struct Account {
    addr: CanonicalAddr
}

#[derive(Serialize, Debug, Deserialize, Clone, PartialEq, Default, JsonSchema)]
pub struct Allowance {
    pub amount: Uint128,
    pub expiration: Option<u64>
}

impl Allowance {
    pub fn is_expired_at(&self, block: &BlockInfo) -> bool {
        match self.expiration {
            Some(time) => block.time.seconds() >= time,
            None => false
        }
    }
}

impl TotalSupplyStore {
    #[inline]
    pub fn increase(&self, storage: &mut dyn Storage, amount: Uint128) -> StdResult<()> {
        let total_supply = self.load_or_default(storage)?;
        let new_total = total_supply.checked_add(amount)?;

        self.save(storage, &new_total)
    }

    #[inline]
    pub fn decrease(&self, storage: &mut dyn Storage, amount: Uint128) -> StdResult<()> {
        let total_supply = self.load_or_default(storage)?;
        let new_total = total_supply.checked_sub(amount)?;

        self.save(storage, &new_total)
    }
}

impl MintersStore {
    #[inline]
    pub fn add(
        &self,
        storage: &mut dyn Storage,
        new_minters: Vec<CanonicalAddr>,
    ) -> StdResult<()> {
        let mut minters = self.load_or_default(storage)?;
        minters.extend(new_minters);

        self.save(storage, &minters)
    }

    #[inline]
    pub fn remove_minters(
        &self,
        storage: &mut dyn Storage,
        to_remove: Vec<CanonicalAddr>,
    ) -> StdResult<()> {
        let mut minters = self.load_or_default(storage)?;

        for minter in to_remove {
            minters.retain(|x| *x != minter);
        }

        self.save(storage, &minters)
    }
}

impl Deref for MintersStore {
    type Target = SingleItem<Vec<CanonicalAddr>, MintersNs>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl Deref for TotalSupplyStore {
    type Target = SingleItem<Uint128, TotalSupplyNs>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[doc(hidden)]
impl Segment for Account {
    fn size(&self) -> usize {
        self.addr.len()
    }

    fn write_segment(&self, buf: &mut Vec<u8>) {
        buf.extend_from_slice(&self.addr);
    }
}

impl Account {
    const BALANCE: ItemSpace<
        Uint128,
        BalancesNs,
        TypedKey<'_, Self>
    > = ItemSpace::new();

    const ALLOWANCE: ItemSpace<
        Allowance,
        AllowancesNs,
        TypedKey2<'_, Self, CanonicalAddr>
    > = ItemSpace::new();

    const VIEWING_KEY: ItemSpace<
        ViewingKeyHashed,
        ViewingKeyNs,
        TypedKey<'_, Self>
    > = ItemSpace::new();

    const RECEIVER: ItemSpace<
        String,
        ReceierHashNs,
        TypedKey<'_, Self>
    > = ItemSpace::new();

    #[inline]
    pub fn of(addr: CanonicalAddr) -> Self {
        Self { addr }
    }

    #[inline]
    pub fn addr(&self) -> &CanonicalAddr {
        &self.addr
    }

    #[inline]
    pub fn balance(&self, storage: &dyn Storage) -> StdResult<Uint128> {
        Self::BALANCE.load_or_default(storage, self)
    }

    #[inline]
    pub fn add_balance(&self, storage: &mut dyn Storage, amount: Uint128) -> StdResult<()> {
        let account_balance = self.balance(storage)?;
        let new_balance = account_balance.checked_add(amount)?;

        Self::BALANCE.save(storage, self, &new_balance)
    }

    #[inline]
    pub fn subtract_balance(&self, storage: &mut dyn Storage, amount: Uint128) -> StdResult<()> {
        let account_balance = self.balance(storage)?;
        let new_balance = account_balance.checked_sub(amount)?;

        Self::BALANCE.save(storage, self, &new_balance)
    }

    pub fn update_allowance<F>(
        &self,
        storage: &mut dyn Storage,
        spender: &CanonicalAddr,
        func: F
    ) -> StdResult<Allowance>
    where
        F: FnOnce(&mut Allowance) -> StdResult<()>,
    {
        let key = (self, spender);
        let mut allowance = Self::ALLOWANCE.load(
            storage,
            key
        )?.unwrap_or_default();

        func(&mut allowance)?;
        Self::ALLOWANCE.save(storage, key, &allowance)?;

        Ok(allowance)
    }

    #[inline]
    pub fn allowance(
        &self,
        storage: &dyn Storage,
        spender: &CanonicalAddr
    ) -> StdResult<Allowance> {
        Self::ALLOWANCE.load_or_default(
            storage,
            (self, spender)
        )
    }

    #[inline]
    pub fn viewing_key(&self, storage: &dyn Storage) -> StdResult<Option<ViewingKeyHashed>> {
        Self::VIEWING_KEY.load(storage, self)
    }

    #[inline]
    pub fn set_viewing_key(&self, storage: &mut dyn Storage, key: &ViewingKey) -> StdResult<()> {
        Self::VIEWING_KEY.save(storage, self, &key.to_hashed())
    }

    #[inline]
    pub fn receiver_hash(&self, storage: &dyn Storage) -> StdResult<Option<String>> {
        Self::RECEIVER.load(storage, self)
    }

    #[inline]
    pub fn set_receiver_hash(&self, storage: &mut dyn Storage, code_hash: String) -> StdResult<()> {
        Self::RECEIVER.save(storage, self, &code_hash)
    }
}

impl From<CanonicalAddr> for Account {
    fn from(addr: CanonicalAddr) -> Self {
        Self { addr }
    }
}

impl From<Account> for CanonicalAddr {
    fn from(account: Account) -> Self {
        account.addr
    }
}