/home/runner/work/creditcoin/creditcoin/pallets/creditcoin/src/migrations/v1.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // First `LoanTerms` rework. `maturity` is replaced with `term_length`, |
2 | | // and `InterestRate` changed from a type alias = u64 to a new struct `InterestRate` |
3 | | |
4 | | use crate::{ |
5 | | loan_terms::{Decimals, Duration}, |
6 | | AddressId, Config, ExternalAmount, OfferId, RatePerPeriod, TransferId, |
7 | | }; |
8 | | use codec::{Decode, Encode}; |
9 | | use frame_support::generate_storage_alias; |
10 | | use frame_support::pallet_prelude::*; |
11 | | use frame_support::{Identity, Twox64Concat}; |
12 | | use sp_runtime::traits::{Saturating, UniqueSaturatedInto}; |
13 | | |
14 | | type OldInterestRate = u64; |
15 | | |
16 | | const OLD_INTEREST_RATE_DECIMALS: u64 = 4; |
17 | | |
18 | 3 | #[derive(Encode, Decode)] |
19 | | struct OldLoanTerms<Moment> { |
20 | | amount: ExternalAmount, |
21 | | interest_rate: OldInterestRate, |
22 | | maturity: Moment, |
23 | | } |
24 | | |
25 | 1 | #[derive(Encode, Decode)] |
26 | 1 | struct OldAskTerms<Moment>(OldLoanTerms<Moment>); |
27 | | |
28 | 1 | #[derive(Encode, Decode)] |
29 | 1 | struct OldBidTerms<Moment>(OldLoanTerms<Moment>); |
30 | | |
31 | 1 | #[derive(Encode, Decode)] |
32 | | struct OldAskOrder<AccountId, BlockNum, Hash, Moment> { |
33 | | blockchain: Blockchain, |
34 | | lender_address_id: AddressId<Hash>, |
35 | | terms: OldAskTerms<Moment>, |
36 | | expiration_block: BlockNum, |
37 | | block: BlockNum, |
38 | | lender: AccountId, |
39 | | } |
40 | | |
41 | 1 | #[derive(Encode, Decode)] |
42 | | struct OldBidOrder<AccountId, BlockNum, Hash, Moment> { |
43 | | blockchain: Blockchain, |
44 | | borrower_address_id: AddressId<Hash>, |
45 | | terms: OldBidTerms<Moment>, |
46 | | expiration_block: BlockNum, |
47 | | block: BlockNum, |
48 | | borrower: AccountId, |
49 | | } |
50 | | |
51 | 1 | #[derive(Encode, Decode)] |
52 | | struct OldDealOrder<AccountId, BlockNum, Hash, Moment> { |
53 | | blockchain: Blockchain, |
54 | | offer_id: OfferId<BlockNum, Hash>, |
55 | | lender_address_id: AddressId<Hash>, |
56 | | borrower_address_id: AddressId<Hash>, |
57 | | terms: OldLoanTerms<Moment>, |
58 | | expiration_block: BlockNum, |
59 | | timestamp: Moment, |
60 | | funding_transfer_id: Option<TransferId<Hash>>, |
61 | | repayment_transfer_id: Option<TransferId<Hash>>, |
62 | | lock: Option<AccountId>, |
63 | | borrower: AccountId, |
64 | | } |
65 | | |
66 | 2 | #[derive(Encode, Decode)] |
67 | 1 | #[cfg_attr(test, derive(Debug0 , PartialEq, Eq))] |
68 | | pub struct DealOrder<AccountId, BlockNum, Hash, Moment> { |
69 | | pub blockchain: Blockchain, |
70 | | pub offer_id: OfferId<BlockNum, Hash>, |
71 | | pub lender_address_id: AddressId<Hash>, |
72 | | pub borrower_address_id: AddressId<Hash>, |
73 | | pub terms: LoanTerms, |
74 | | pub expiration_block: BlockNum, |
75 | | pub timestamp: Moment, |
76 | | pub funding_transfer_id: Option<TransferId<Hash>>, |
77 | | pub repayment_transfer_id: Option<TransferId<Hash>>, |
78 | | pub lock: Option<AccountId>, |
79 | | pub borrower: AccountId, |
80 | | } |
81 | | |
82 | 8 | #[derive(Encode, Decode)] |
83 | 4 | #[cfg_attr(test, derive(Debug0 , PartialEq, Eq))] |
84 | | pub struct InterestRate { |
85 | | pub rate_per_period: RatePerPeriod, |
86 | | pub decimals: Decimals, |
87 | | pub period: Duration, |
88 | | } |
89 | | |
90 | 8 | #[derive(Encode, Decode)] |
91 | 4 | #[cfg_attr(test, derive(Debug0 , PartialEq, Eq))] |
92 | | pub struct LoanTerms { |
93 | | pub amount: ExternalAmount, |
94 | | pub interest_rate: InterestRate, |
95 | | pub term_length: Duration, |
96 | | } |
97 | | |
98 | 2 | #[derive(Encode, Decode)] |
99 | 1 | #[cfg_attr(test, derive(Debug0 , PartialEq, Eq))] |
100 | 2 | pub struct AskTerms(pub LoanTerms); |
101 | | |
102 | 2 | #[derive(Encode, Decode)] |
103 | 1 | #[cfg_attr(test, derive(Debug0 , PartialEq, Eq))] |
104 | 2 | pub struct BidTerms(pub LoanTerms); |
105 | | |
106 | 2 | #[derive(Encode, Decode)] |
107 | 1 | #[cfg_attr(test, derive(Debug0 , PartialEq, Eq))] |
108 | | pub struct AskOrder<AccountId, BlockNum, Hash> { |
109 | | pub blockchain: Blockchain, |
110 | | pub lender_address_id: AddressId<Hash>, |
111 | | pub terms: AskTerms, |
112 | | pub expiration_block: BlockNum, |
113 | | pub block: BlockNum, |
114 | | pub lender: AccountId, |
115 | | } |
116 | | |
117 | 2 | #[derive(Encode, Decode)] |
118 | 1 | #[cfg_attr(test, derive(Debug0 , PartialEq, Eq))] |
119 | | pub struct BidOrder<AccountId, BlockNum, Hash> { |
120 | | pub blockchain: Blockchain, |
121 | | pub borrower_address_id: AddressId<Hash>, |
122 | | pub terms: BidTerms, |
123 | | pub expiration_block: BlockNum, |
124 | | pub block: BlockNum, |
125 | | pub borrower: AccountId, |
126 | | } |
127 | | |
128 | | type OtherChainLen = ConstU32<256>; |
129 | | pub type OtherChain = BoundedVec<u8, OtherChainLen>; |
130 | | |
131 | 50 | #[derive(E40 ncode40 , Decode)] |
132 | 9 | #[cfg_attr(test, derive(D0 ebug0 , PartialEq, Eq, C4 lone4 ))] |
133 | | pub enum Blockchain { |
134 | | Ethereum, |
135 | | Rinkeby, |
136 | | Luniverse, |
137 | | Bitcoin, |
138 | | Other(OtherChain), |
139 | | } |
140 | | |
141 | | impl Blockchain { |
142 | | #[allow(dead_code)] |
143 | 32 | pub fn as_bytes(&self) -> &[u8] { |
144 | 32 | match self { |
145 | 24 | Blockchain::Ethereum => b"ethereum", |
146 | 8 | Blockchain::Rinkeby => b"rinkeby", |
147 | 0 | Blockchain::Luniverse => b"luniverse", |
148 | 0 | Blockchain::Bitcoin => b"bitcoin", |
149 | 0 | Blockchain::Other(chain) => chain.as_slice(), |
150 | | } |
151 | 32 | } |
152 | | } |
153 | | |
154 | | generate_storage_alias!( |
155 | | Creditcoin, |
156 | | DealOrders<T: Config> => DoubleMap<(Twox64Concat, T::BlockNumber), (Identity, T::Hash), DealOrder<T::AccountId, T::BlockNumber, T::Hash, T::Moment>> |
157 | | ); |
158 | | |
159 | | generate_storage_alias!( |
160 | | Creditcoin, |
161 | | AskOrders<T: Config> => DoubleMap<(Twox64Concat, T::BlockNumber), (Identity, T::Hash), AskOrder<T::AccountId, T::BlockNumber, T::Hash>> |
162 | | ); |
163 | | |
164 | | generate_storage_alias!( |
165 | | Creditcoin, |
166 | | BidOrders<T: Config> => DoubleMap<(Twox64Concat, T::BlockNumber), (Identity, T::Hash), BidOrder<T::AccountId, T::BlockNumber, T::Hash>> |
167 | | ); |
168 | | |
169 | 3 | pub(crate) fn migrate<T: Config>() -> Weight { |
170 | 3 | let mut weight: Weight = 0; |
171 | 3 | let weight_each = T::DbWeight::get().reads_writes(1, 1); |
172 | 3 | AskOrders::<T>::translate::<OldAskOrder<T::AccountId, T::BlockNumber, T::Hash, T::Moment>, _>( |
173 | 3 | |_expiration, _hash, ask| { |
174 | 1 | weight = weight.saturating_add(weight_each); |
175 | 1 | Some(AskOrder { |
176 | 1 | block: ask.block, |
177 | 1 | blockchain: ask.blockchain, |
178 | 1 | expiration_block: ask.expiration_block, |
179 | 1 | lender: ask.lender, |
180 | 1 | lender_address_id: ask.lender_address_id, |
181 | 1 | terms: AskTerms(LoanTerms { |
182 | 1 | amount: ask.terms.0.amount, |
183 | 1 | interest_rate: InterestRate { |
184 | 1 | rate_per_period: ask.terms.0.interest_rate, |
185 | 1 | decimals: OLD_INTEREST_RATE_DECIMALS, |
186 | 1 | period: Duration::from_millis(ask.terms.0.maturity.unique_saturated_into()), |
187 | 1 | }, |
188 | 1 | term_length: Duration::from_millis( |
189 | 1 | ask.terms.0.maturity.unique_saturated_into(), |
190 | 1 | ), |
191 | 1 | }), |
192 | 1 | }) |
193 | 3 | }, |
194 | 3 | ); |
195 | 3 | |
196 | 3 | BidOrders::<T>::translate::<OldBidOrder<T::AccountId, T::BlockNumber, T::Hash, T::Moment>, _>( |
197 | 3 | |_expiration, _hash, bid| { |
198 | 1 | weight = weight.saturating_add(weight_each); |
199 | 1 | Some(BidOrder { |
200 | 1 | block: bid.block, |
201 | 1 | blockchain: bid.blockchain, |
202 | 1 | expiration_block: bid.expiration_block, |
203 | 1 | borrower: bid.borrower, |
204 | 1 | borrower_address_id: bid.borrower_address_id, |
205 | 1 | terms: BidTerms(LoanTerms { |
206 | 1 | amount: bid.terms.0.amount, |
207 | 1 | interest_rate: InterestRate { |
208 | 1 | rate_per_period: bid.terms.0.interest_rate, |
209 | 1 | decimals: OLD_INTEREST_RATE_DECIMALS, |
210 | 1 | period: Duration::from_millis(bid.terms.0.maturity.unique_saturated_into()), |
211 | 1 | }, |
212 | 1 | term_length: Duration::from_millis( |
213 | 1 | bid.terms.0.maturity.unique_saturated_into(), |
214 | 1 | ), |
215 | 1 | }), |
216 | 1 | }) |
217 | 3 | }, |
218 | 3 | ); |
219 | 3 | |
220 | 3 | DealOrders::<T>::translate::<OldDealOrder<T::AccountId, T::BlockNumber, T::Hash, T::Moment>, _>( |
221 | 3 | |_expiration, _hash, deal| { |
222 | 1 | weight = weight.saturating_add(weight_each); |
223 | 1 | Some(DealOrder { |
224 | 1 | blockchain: deal.blockchain, |
225 | 1 | offer_id: deal.offer_id, |
226 | 1 | lender_address_id: deal.lender_address_id, |
227 | 1 | borrower_address_id: deal.borrower_address_id, |
228 | 1 | terms: LoanTerms { |
229 | 1 | amount: deal.terms.amount, |
230 | 1 | interest_rate: InterestRate { |
231 | 1 | rate_per_period: deal.terms.interest_rate, |
232 | 1 | decimals: OLD_INTEREST_RATE_DECIMALS, |
233 | 1 | period: Duration::from_millis(deal.terms.maturity.unique_saturated_into()), |
234 | 1 | }, |
235 | 1 | term_length: Duration::from_millis( |
236 | 1 | deal.terms.maturity.saturating_sub(deal.timestamp).unique_saturated_into(), |
237 | 1 | ), |
238 | 1 | }, |
239 | 1 | expiration_block: deal.expiration_block, |
240 | 1 | timestamp: deal.timestamp, |
241 | 1 | funding_transfer_id: deal.funding_transfer_id, |
242 | 1 | repayment_transfer_id: deal.repayment_transfer_id, |
243 | 1 | lock: deal.lock, |
244 | 1 | borrower: deal.borrower, |
245 | 1 | }) |
246 | 3 | }, |
247 | 3 | ); |
248 | 3 | weight |
249 | 3 | } |
250 | | |
251 | | #[cfg(test)] |
252 | | mod tests { |
253 | | use sp_core::U256; |
254 | | |
255 | | use crate::{ |
256 | | mock::{ExtBuilder, Test}, |
257 | | tests::TestInfo, |
258 | | AskOrderId, BidOrderId, DealOrderId, DoubleMapExt, OfferId, |
259 | | }; |
260 | | |
261 | | use super::{ |
262 | | generate_storage_alias, AskOrder, AskTerms, BidOrder, BidTerms, Blockchain, Config, |
263 | | Duration, Identity, InterestRate, LoanTerms, OldAskOrder, OldAskTerms, OldBidOrder, |
264 | | OldBidTerms, OldDealOrder, OldLoanTerms, Twox64Concat, OLD_INTEREST_RATE_DECIMALS, |
265 | | }; |
266 | | |
267 | | generate_storage_alias!( |
268 | | Creditcoin, |
269 | | DealOrders<T: Config> => DoubleMap<(Twox64Concat, T::BlockNumber), (Identity, T::Hash), OldDealOrder<T::AccountId, T::BlockNumber, T::Hash, T::Moment>> |
270 | | ); |
271 | | |
272 | | type OldDealOrders = DealOrders<Test>; |
273 | | |
274 | | generate_storage_alias!( |
275 | | Creditcoin, |
276 | | AskOrders<T: Config> => DoubleMap<(Twox64Concat, T::BlockNumber), (Identity, T::Hash), OldAskOrder<T::AccountId, T::BlockNumber, T::Hash, T::Moment>> |
277 | | ); |
278 | | |
279 | | type OldAskOrders = AskOrders<Test>; |
280 | | |
281 | | generate_storage_alias!( |
282 | | Creditcoin, |
283 | | BidOrders<T: Config> => DoubleMap<(Twox64Concat, T::BlockNumber), (Identity, T::Hash), OldBidOrder<T::AccountId, T::BlockNumber, T::Hash, T::Moment>> |
284 | | ); |
285 | | |
286 | | type OldBidOrders = BidOrders<Test>; |
287 | | |
288 | 1 | #[test] |
289 | 1 | fn ask_order_migrates() { |
290 | 1 | ExtBuilder::default().build_and_execute(|| { |
291 | 1 | let ask_id = AskOrderId::new::<Test>(100, "asdf".as_bytes()); |
292 | 1 | let test_info = TestInfo::new_defaults(); |
293 | 1 | let old_ask = OldAskOrder { |
294 | 1 | blockchain: Blockchain::Ethereum, |
295 | 1 | lender_address_id: test_info.lender.address_id.clone(), |
296 | 1 | terms: OldAskTerms(OldLoanTerms { |
297 | 1 | amount: 1000u64.into(), |
298 | 1 | interest_rate: 1000, |
299 | 1 | maturity: 2000, |
300 | 1 | }), |
301 | 1 | expiration_block: 100, |
302 | 1 | block: 0, |
303 | 1 | lender: test_info.lender.account_id, |
304 | 1 | }; |
305 | 1 | OldAskOrders::insert_id(&ask_id, &old_ask); |
306 | 1 | |
307 | 1 | super::migrate::<Test>(); |
308 | 1 | |
309 | 1 | let ask = super::AskOrders::<Test>::try_get_id(&ask_id).unwrap(); |
310 | 1 | |
311 | 1 | assert_eq!( |
312 | 1 | ask, |
313 | 1 | AskOrder { |
314 | 1 | blockchain: old_ask.blockchain, |
315 | 1 | lender_address_id: old_ask.lender_address_id, |
316 | 1 | terms: AskTerms(LoanTerms { |
317 | 1 | amount: old_ask.terms.0.amount, |
318 | 1 | interest_rate: InterestRate { |
319 | 1 | rate_per_period: old_ask.terms.0.interest_rate, |
320 | 1 | decimals: OLD_INTEREST_RATE_DECIMALS, |
321 | 1 | period: Duration::from_millis(old_ask.terms.0.maturity) |
322 | 1 | }, |
323 | 1 | term_length: Duration::from_millis(old_ask.terms.0.maturity) |
324 | 1 | }), |
325 | 1 | expiration_block: old_ask.expiration_block, |
326 | 1 | block: old_ask.block, |
327 | 1 | lender: old_ask.lender, |
328 | 1 | } |
329 | 1 | ) |
330 | 1 | }); |
331 | 1 | } |
332 | | |
333 | 1 | #[test] |
334 | 1 | fn bid_order_migrates() { |
335 | 1 | ExtBuilder::default().build_and_execute(|| { |
336 | 1 | let bid_id = BidOrderId::new::<Test>(100, "asdf".as_bytes()); |
337 | 1 | let test_info = TestInfo::new_defaults(); |
338 | 1 | let address_id = test_info.borrower.address_id.clone(); |
339 | 1 | let expiration_block = 100; |
340 | 1 | let block = 0; |
341 | 1 | let amount: U256 = 1000u64.into(); |
342 | 1 | |
343 | 1 | let old_bid = OldBidOrder { |
344 | 1 | blockchain: Blockchain::Ethereum, |
345 | 1 | borrower_address_id: address_id, |
346 | 1 | terms: OldBidTerms(OldLoanTerms { amount, interest_rate: 1000, maturity: 2000 }), |
347 | 1 | expiration_block, |
348 | 1 | block, |
349 | 1 | borrower: test_info.borrower.account_id.clone(), |
350 | 1 | }; |
351 | 1 | OldBidOrders::insert_id(&bid_id, &old_bid); |
352 | 1 | |
353 | 1 | super::migrate::<Test>(); |
354 | 1 | |
355 | 1 | let bid = super::BidOrders::<Test>::try_get_id(&bid_id).unwrap(); |
356 | 1 | |
357 | 1 | assert_eq!( |
358 | 1 | bid, |
359 | 1 | BidOrder { |
360 | 1 | blockchain: old_bid.blockchain, |
361 | 1 | borrower_address_id: old_bid.borrower_address_id, |
362 | 1 | terms: BidTerms(LoanTerms { |
363 | 1 | amount, |
364 | 1 | interest_rate: InterestRate { |
365 | 1 | rate_per_period: old_bid.terms.0.interest_rate, |
366 | 1 | decimals: OLD_INTEREST_RATE_DECIMALS, |
367 | 1 | period: Duration::from_millis(old_bid.terms.0.maturity) |
368 | 1 | }, |
369 | 1 | term_length: Duration::from_millis(old_bid.terms.0.maturity) |
370 | 1 | }), |
371 | 1 | expiration_block, |
372 | 1 | block, |
373 | 1 | borrower: test_info.borrower.account_id, |
374 | 1 | } |
375 | 1 | ) |
376 | 1 | }) |
377 | 1 | } |
378 | | |
379 | 1 | #[test] |
380 | 1 | fn deal_order_migrates() { |
381 | 1 | ExtBuilder::default().build_and_execute(|| { |
382 | 1 | let offer_id = OfferId::with_expiration_hash::<Test>(100, [1; 32].into()); |
383 | 1 | let deal_id = DealOrderId::with_expiration_hash::<Test>(100, [0; 32].into()); |
384 | 1 | let test_info = TestInfo::new_defaults(); |
385 | 1 | let old_deal = OldDealOrder { |
386 | 1 | blockchain: Blockchain::Ethereum, |
387 | 1 | lender_address_id: test_info.lender.address_id.clone(), |
388 | 1 | terms: OldLoanTerms { amount: 1000u64.into(), interest_rate: 1000, maturity: 2000 }, |
389 | 1 | expiration_block: 100, |
390 | 1 | offer_id, |
391 | 1 | borrower_address_id: test_info.borrower.address_id.clone(), |
392 | 1 | timestamp: 0, |
393 | 1 | funding_transfer_id: None, |
394 | 1 | repayment_transfer_id: None, |
395 | 1 | lock: None, |
396 | 1 | borrower: test_info.borrower.account_id, |
397 | 1 | }; |
398 | 1 | |
399 | 1 | OldDealOrders::insert_id(&deal_id, &old_deal); |
400 | 1 | |
401 | 1 | super::migrate::<Test>(); |
402 | 1 | |
403 | 1 | let deal = super::DealOrders::<Test>::try_get_id(&deal_id).unwrap(); |
404 | 1 | |
405 | 1 | assert_eq!( |
406 | 1 | deal, |
407 | 1 | super::DealOrder { |
408 | 1 | blockchain: old_deal.blockchain, |
409 | 1 | lender_address_id: old_deal.lender_address_id, |
410 | 1 | terms: LoanTerms { |
411 | 1 | amount: old_deal.terms.amount, |
412 | 1 | interest_rate: InterestRate { |
413 | 1 | rate_per_period: old_deal.terms.interest_rate, |
414 | 1 | decimals: OLD_INTEREST_RATE_DECIMALS, |
415 | 1 | period: Duration::from_millis(old_deal.terms.maturity) |
416 | 1 | }, |
417 | 1 | term_length: Duration::from_millis( |
418 | 1 | old_deal.terms.maturity.saturating_sub(old_deal.timestamp) |
419 | 1 | ) |
420 | 1 | }, |
421 | 1 | offer_id: old_deal.offer_id, |
422 | 1 | borrower_address_id: old_deal.borrower_address_id, |
423 | 1 | expiration_block: old_deal.expiration_block, |
424 | 1 | timestamp: old_deal.timestamp, |
425 | 1 | funding_transfer_id: old_deal.funding_transfer_id, |
426 | 1 | repayment_transfer_id: old_deal.repayment_transfer_id, |
427 | 1 | lock: old_deal.lock, |
428 | 1 | borrower: old_deal.borrower |
429 | 1 | } |
430 | 1 | ); |
431 | 1 | }); |
432 | 1 | } |
433 | | } |