Coverage Report

Created: 2022-11-10 19:56

/home/runner/work/creditcoin/creditcoin/pallets/creditcoin/src/types.rs
Line
Count
Source (jump to first uncovered line)
1
pub mod loan_terms;
2
pub mod platform;
3
4
pub use loan_terms::*;
5
pub use platform::*;
6
7
use crate::ocw::tasks::collect_coins::GCreContract;
8
use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen};
9
use extend::ext;
10
use frame_support::{
11
  storage::types::QueryKindTrait,
12
  traits::{ConstU32, Get, StorageInstance},
13
  BoundedVec, RuntimeDebug, StorageHasher,
14
};
15
use frame_system::pallet_prelude::BlockNumberFor;
16
use scale_info::TypeInfo;
17
use sha2::Digest;
18
use sp_core::ecdsa;
19
use sp_runtime::traits::Hash;
20
use sp_std::prelude::*;
21
22
pub type ExternalAmount = sp_core::U256;
23
type GuidLen = ConstU32<256>;
24
pub type Guid = BoundedVec<u8, GuidLen>;
25
type ExternalAddressLen = ConstU32<256>;
26
pub type ExternalAddress = BoundedVec<u8, ExternalAddressLen>;
27
type ExternalTxIdLen = ConstU32<256>;
28
pub type ExternalTxId = BoundedVec<u8, ExternalTxIdLen>;
29
type OtherChainLen = ConstU32<256>;
30
pub type OtherChain = BoundedVec<u8, OtherChainLen>;
31
type OtherTransferKindLen = ConstU32<256>;
32
pub type OtherTransferKind = BoundedVec<u8, OtherTransferKindLen>;
33
34
8
#[derive(Clone, 
E3
ncod
e3
, Decode, Eq,
P0
artialE
q0
,
R2
untimeDebu
g2
,
T0
ypeInfo,
MaxEncodedLen3
)]
35
0
pub enum LegacyTransferKind {
36
  Erc20(ExternalAddress),
37
  Ethless(ExternalAddress),
38
  Native,
39
  Other(OtherTransferKind),
40
}
41
42
765
#[derive(
Clone425
,
Encode539
, Decode, Eq,
P9
artialE
q9
,
RuntimeDebug1
,
TypeInfo3
,
MaxEncodedLen1
)]
43
1
pub struct Address<AccountId> {
44
  pub blockchain: Blockchain,
45
  pub value: ExternalAddress,
46
  pub owner: AccountId,
47
}
48
49
impl<AccountId> Address<AccountId> {
50
9
  pub fn matches_chain_of(&self, other: &Address<AccountId>) -> bool {
51
9
    self.blockchain == other.blockchain
52
9
  }
53
}
54
55
16
#[derive(Clone, 
Encode15
,
D5
ecod
e5
, Eq,
P10
artialE
q10
,
RuntimeDebug1
,
TypeInfo3
,
MaxEncodedLen2
)]
56
1
pub struct CollectedCoins<Hash, Balance> {
57
  pub to: AddressId<Hash>,
58
  pub amount: Balance,
59
  pub tx_id: ExternalTxId,
60
}
61
62
136
#[derive(
Clone72
, Encode,
D53
ecod
e53
, Eq,
P21
artialE
q21
,
RuntimeDebug8
,
TypeInfo11
,
MaxEncodedLen5
)]
63
1
pub struct Transfer<AccountId, BlockNum, Hash, Moment> {
64
  pub blockchain: Blockchain,
65
  pub kind: TransferKind,
66
  pub from: AddressId<Hash>,
67
  pub to: AddressId<Hash>,
68
  pub deal_order_id: DealOrderId<BlockNum, Hash>,
69
  pub amount: ExternalAmount,
70
  pub tx_id: ExternalTxId,
71
  pub block: BlockNum,
72
  pub is_processed: bool,
73
  pub account_id: AccountId,
74
  pub timestamp: Option<Moment>,
75
}
76
77
24
#[derive(
Clone17
, Encode,
D23
ecod
e23
, Eq,
P19
artialE
q19
,
RuntimeDebug5
,
TypeInfo3
,
MaxEncodedLen3
)]
78
1
pub struct UnverifiedCollectedCoins {
79
  pub to: ExternalAddress,
80
  pub tx_id: ExternalTxId,
81
  pub contract: GCreContract,
82
}
83
84
51
#[derive(
Clone4
, Encode,
D16
ecod
e16
, Eq,
P6
artialE
q6
,
RuntimeDebug6
,
TypeInfo5
,
MaxEncodedLen3
)]
85
1
pub struct UnverifiedTransfer<AccountId, BlockNum, Hash, Moment> {
86
  pub transfer: Transfer<AccountId, BlockNum, Hash, Moment>,
87
  pub from_external: ExternalAddress,
88
  pub to_external: ExternalAddress,
89
  pub deadline: BlockNum,
90
  pub currency_to_check: CurrencyOrLegacyTransferKind,
91
}
92
93
51
#[derive(
C4
lon
e4
, Encode,
D16
ecode, Eq,
P6
artialE
q6
,
R6
untimeDebu
g6
,
T0
ypeInfo,
MaxEncodedLen3
)]
94
0
pub enum CurrencyOrLegacyTransferKind {
95
  Currency(Currency),
96
  TransferKind(LegacyTransferKind),
97
}
98
99
261
#[derive(
Clone137
,
Encode181
, Decode, Eq,
P8
artialE
q8
,
RuntimeDebug1
,
TypeInfo5
,
MaxEncodedLen1
)]
100
1
pub struct Offer<AccountId, BlockNum, Hash> {
101
  pub ask_id: AskOrderId<BlockNum, Hash>,
102
  pub bid_id: BidOrderId<BlockNum, Hash>,
103
  pub expiration_block: BlockNum,
104
  pub block: BlockNum,
105
  pub lender: AccountId,
106
}
107
108
402
#[derive(
Clone146
,
Encode191
, Decode, Eq,
P10
artialE
q10
,
RuntimeDebug1
,
TypeInfo5
,
MaxEncodedLen1
)]
109
1
pub struct AskOrder<AccountId, BlockNum, Hash> {
110
  pub lender_address_id: AddressId<Hash>,
111
  pub terms: AskTerms<Hash>,
112
  pub expiration_block: BlockNum,
113
  pub block: BlockNum,
114
  pub lender: AccountId,
115
}
116
117
402
#[derive(
Clone146
,
Encode191
, Decode, Eq,
P10
artialE
q10
,
RuntimeDebug1
,
TypeInfo5
,
MaxEncodedLen1
)]
118
1
pub struct BidOrder<AccountId, BlockNum, Hash> {
119
  pub borrower_address_id: AddressId<Hash>,
120
  pub terms: BidTerms<Hash>,
121
  pub expiration_block: BlockNum,
122
  pub block: BlockNum,
123
  pub borrower: AccountId,
124
}
125
126
295
#[derive(
Clone124
,
Encode221
, Decode, Eq,
P9
artialE
q9
,
RuntimeDebug1
,
TypeInfo11
,
MaxEncodedLen1
)]
127
1
pub struct DealOrder<AccountId, BlockNum, Hash, Moment> {
128
  pub offer_id: OfferId<BlockNum, Hash>,
129
  pub lender_address_id: AddressId<Hash>,
130
  pub borrower_address_id: AddressId<Hash>,
131
  pub terms: LoanTerms<Hash>,
132
  pub expiration_block: BlockNum,
133
  pub timestamp: Moment,
134
  pub block: Option<BlockNum>,
135
  pub funding_transfer_id: Option<TransferId<Hash>>,
136
  pub repayment_transfer_id: Option<TransferId<Hash>>,
137
  pub lock: Option<AccountId>,
138
  pub borrower: AccountId,
139
}
140
141
1.58k
#[derive(
Clone1.56k
, Encode, Decode, Eq,
PartialEq111
,
RuntimeDebug22
,
TypeInfo1
,
MaxEncodedLen17
)]
142
2.88k
pub struct AddressId<Hash>(Hash);
143
144
#[cfg(test)]
145
impl<Hash> AddressId<Hash> {
146
13
  pub fn make(hash: Hash) -> Self {
147
13
    Self(hash)
148
13
  }
149
}
150
151
#[derive(
152
559
  Clone, 
Encode226
,
D269
ecod
e269
, Eq,
P14
artialE
q14
,
RuntimeDebug2
,
TypeInfo2
,
MaxEncodedLen2
,
P0
artialOr
d0
,
O1
r
d1
,
153
)]
154
pub struct AskOrderId<BlockNum, Hash>(BlockNum, Hash);
155
156
#[derive(
157
559
  Clone, 
Encode226
,
D269
ecod
e269
, Eq,
P14
artialE
q14
,
RuntimeDebug2
,
TypeInfo2
,
MaxEncodedLen2
,
P0
artialOr
d0
,
O1
r
d1
,
158
)]
159
pub struct BidOrderId<BlockNum, Hash>(BlockNum, Hash);
160
161
468
#[derive(Clone, 
Encode202
,
D74
ecod
e74
, Eq,
P53
artialE
q53
,
RuntimeDebug9
,
TypeInfo2
,
MaxEncodedLen6
)]
162
1
pub struct DealOrderId<BlockNum, Hash>(BlockNum, Hash);
163
164
#[cfg(test)]
165
impl<B: Default, H: Default> DealOrderId<B, H> {
166
2
  pub fn dummy() -> Self {
167
2
    Self(B::default(), H::default())
168
2
  }
169
}
170
171
510
#[derive(Clone, 
Encode276
,
D313
ecod
e313
, Eq,
P18
artialE
q18
,
RuntimeDebug2
,
TypeInfo2
,
MaxEncodedLen2
)]
172
1
#[cfg_attr(feature = "std", derive(
serd0
e::Serializ0
e0
,
s0
erde::Deserializ
e0
))]
173
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
174
pub struct OfferId<BlockNum, Hash>(BlockNum, Hash);
175
176
113
#[derive(Clone, Encode, 
D65
ecod
e65
, Eq,
PartialEq28
,
RuntimeDebug12
,
TypeInfo1
,
MaxEncodedLen5
)]
177
290
pub struct TransferId<Hash>(Hash);
178
179
#[cfg(test)]
180
impl<Hash> TransferId<Hash> {
181
5
  pub fn make(hash: Hash) -> Self {
182
5
    Self(hash)
183
5
  }
184
}
185
186
54
#[derive(Clone, Encode, 
D29
ecod
e29
, Eq,
PartialEq17
,
RuntimeDebug8
,
TypeInfo1
,
MaxEncodedLen3
)]
187
125
pub struct CollectedCoinsId<Hash>(Hash);
188
189
#[cfg(test)]
190
impl<Hash> CollectedCoinsId<Hash> {
191
2
  pub fn make(hash: Hash) -> Self {
192
2
    Self(hash)
193
2
  }
194
}
195
196
macro_rules! concatenate {
197
  (@strip_plus + $($rest: tt)*) => {
198
    $($rest)*
199
  };
200
  ($($bytes: expr),+) => {
201
    {
202
      let mut buf = Vec::with_capacity($crate::types::concatenate!(@strip_plus $(+ $bytes.len())+));
203
      $(buf.extend($bytes);)+
204
      buf
205
    }
206
  };
207
}
208
pub(crate) use concatenate;
209
210
impl<H> AddressId<H> {
211
870
  pub fn new<Config>(blockchain: &Blockchain, address: &[u8]) -> AddressId<H>
212
870
  where
213
870
    Config: frame_system::Config,
214
870
    <Config as frame_system::Config>::Hashing: Hash<Output = H>,
215
870
  {
216
870
    let key = concatenate!(&*blockchain.as_bytes(), address);
217
870
    AddressId(Config::Hashing::hash(&key))
218
870
  }
219
}
220
221
impl<B, H> AskOrderId<B, H> {
222
302
  pub fn new<Config>(expiration_block: B, guid: &[u8]) -> AskOrderId<B, H>
223
302
  where
224
302
    Config: frame_system::Config<BlockNumber = B>,
225
302
    <Config as frame_system::Config>::Hashing: Hash<Output = H>,
226
302
  {
227
302
    AskOrderId(expiration_block, Config::Hashing::hash(guid))
228
302
  }
229
}
230
231
impl<B, H> BidOrderId<B, H> {
232
299
  pub fn new<Config>(expiration_block: B, guid: &[u8]) -> BidOrderId<B, H>
233
299
  where
234
299
    Config: frame_system::Config<BlockNumber = B>,
235
299
    <Config as frame_system::Config>::Hashing: Hash<Output = H>,
236
299
  {
237
299
    BidOrderId(expiration_block, Config::Hashing::hash(guid))
238
299
  }
239
}
240
241
impl<H> TransferId<H> {
242
135
  pub fn new<Config>(blockchain: &Blockchain, blockchain_tx_id: &[u8]) -> TransferId<H>
243
135
  where
244
135
    Config: frame_system::Config,
245
135
    <Config as frame_system::Config>::Hashing: Hash<Output = H>,
246
135
  {
247
135
    let key = concatenate!(&*blockchain.as_bytes(), blockchain_tx_id);
248
135
    TransferId(Config::Hashing::hash(&key))
249
135
  }
250
}
251
252
impl<H> CollectedCoinsId<H> {
253
47
  pub fn new<Config>(contract_chain: &Blockchain, blockchain_tx_id: &[u8]) -> CollectedCoinsId<H>
254
47
  where
255
47
    Config: frame_system::Config,
256
47
    <Config as frame_system::Config>::Hashing: Hash<Output = H>,
257
47
  {
258
47
    let key = concatenate!(contract_chain.as_bytes().iter(), blockchain_tx_id);
259
47
    CollectedCoinsId(Config::Hashing::hash(&key))
260
47
  }
261
}
262
263
impl<B, H> OfferId<B, H> {
264
270
  pub fn new<Config>(
265
270
    expiration_block: B,
266
270
    ask_order_id: &AskOrderId<BlockNumberFor<Config>, H>,
267
270
    bid_order_id: &BidOrderId<BlockNumberFor<Config>, H>,
268
270
  ) -> Self
269
270
  where
270
270
    Config: frame_system::Config<BlockNumber = B>,
271
270
    <Config as frame_system::Config>::Hashing: Hash<Output = H>,
272
270
    H: AsRef<[u8]>,
273
270
  {
274
270
    let ask_bytes = ask_order_id.1.as_ref();
275
270
    let bid_bytes = bid_order_id.1.as_ref();
276
270
    let key = concatenate!(ask_bytes, bid_bytes);
277
270
    OfferId(expiration_block, Config::Hashing::hash(&key))
278
270
  }
279
}
280
281
impl<B, H> DealOrderId<B, H> {
282
247
  pub fn new<Config>(expiration_block: B, offer_id: &OfferId<BlockNumberFor<Config>, H>) -> Self
283
247
  where
284
247
    Config: frame_system::Config,
285
247
    <Config as frame_system::Config>::Hashing: Hash<Output = H>,
286
247
    H: AsRef<[u8]>,
287
247
  {
288
247
    DealOrderId(expiration_block, Config::Hashing::hash(offer_id.1.as_ref()))
289
247
  }
290
}
291
292
pub(crate) trait Id<BlockNum, Hash> {
293
  fn expiration(&self) -> BlockNum;
294
  fn hash(&self) -> Hash;
295
}
296
297
macro_rules! impl_id {
298
  ($id: ident) => {
299
    impl<BlockNum, Hash> Id<BlockNum, Hash> for $id<BlockNum, Hash>
300
    where
301
      BlockNum: Clone,
302
      Hash: Clone,
303
    {
304
1.94k
      fn expiration(&self) -> BlockNum {
305
1.94k
        self.0.clone()
306
1.94k
      }
307
2.45k
      fn hash(&self) -> Hash {
308
2.45k
        self.1.clone()
309
2.45k
      }
310
    }
311
312
    impl<'a, BlockNum, Hash> Id<BlockNum, Hash> for &'a $id<BlockNum, Hash>
313
    where
314
      BlockNum: Clone,
315
      Hash: Clone,
316
    {
317
22
      fn expiration(&self) -> BlockNum {
318
22
        self.0.clone()
319
22
      }
320
22
      fn hash(&self) -> Hash {
321
22
        self.1.clone()
322
22
      }
323
    }
324
325
    impl<BlockNum, H> $id<BlockNum, H> {
326
34
      pub fn with_expiration_hash<Config>(expiration_block: BlockNum, hash: H) -> Self
327
34
      where
328
34
        Config: frame_system::Config<BlockNumber = BlockNum>,
329
34
        <Config as frame_system::Config>::Hashing: Hash<Output = H>,
330
34
      {
331
34
        Self(expiration_block, hash)
332
34
      }
333
    }
334
  };
335
}
336
337
impl_id!(DealOrderId);
338
impl_id!(AskOrderId);
339
impl_id!(BidOrderId);
340
impl_id!(OfferId);
341
342
#[ext(name = DoubleMapExt)]
343
pub(crate) impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues, IdTy>
344
  frame_support::storage::types::StorageDoubleMap<
345
    Prefix,
346
    Hasher1,
347
    Key1,
348
    Hasher2,
349
    Key2,
350
    Value,
351
    QueryKind,
352
    OnEmpty,
353
    MaxValues,
354
  > where
355
  Prefix: StorageInstance,
356
  Hasher1: StorageHasher,
357
  Hasher2: StorageHasher,
358
  Key1: FullCodec + Clone,
359
  Key2: FullCodec + Clone,
360
  Value: FullCodec,
361
  QueryKind: QueryKindTrait<Value, OnEmpty>,
362
  OnEmpty: Get<QueryKind::Query> + 'static,
363
  MaxValues: Get<Option<u32>>,
364
  IdTy: Id<Key1, Key2>,
365
{
366
563
  fn insert_id<V>(id: IdTy, val: V)
367
563
  where
368
563
    V: EncodeLike<Value>,
369
563
  {
370
563
    Self::insert(id.expiration(), id.hash(), val);
371
563
  }
372
373
697
  fn try_get_id(id: &IdTy) -> frame_support::dispatch::result::Result<Value, ()> {
374
697
    Self::try_get(id.expiration(), id.hash())
375
697
  }
376
377
564
  fn contains_id(id: &IdTy) -> bool {
378
564
    Self::contains_key(id.expiration(), id.hash())
379
564
  }
380
}
381
382
7
#[derive(
Clone2
, Encode,
D2
ecod
e2
, Eq, PartialEq,
RuntimeDebug1
,
TypeInfo1
,
MaxEncodedLen1
)]
383
5
pub struct LegacySighash([u8; 60]);
384
385
impl core::default::Default for LegacySighash {
386
7
  fn default() -> LegacySighash {
387
7
    LegacySighash([0u8; 60])
388
7
  }
389
}
390
391
impl From<&ecdsa::Public> for LegacySighash {
392
1
  fn from(public_key: &ecdsa::Public) -> Self {
393
1
    let compressed_key_hex = hex::encode(public_key.as_ref());
394
1
    let mut hasher = sha2::Sha512::new();
395
1
    hasher.update(compressed_key_hex.as_bytes());
396
1
    let key_hash = hasher.finalize();
397
1
    let key_hash_hex = hex::encode(&key_hash);
398
1
399
1
    const SKIP_TO_GET_60: usize = 512 / 8 * 2 - 60; // 512 - hash size in bits, 8 - bits in byte, 2 - hex digits for byte, 60 - merkle address length (70) without creditcoin namespace length (6) and prefix length (4)
400
1
401
1
    LegacySighash::try_from(&key_hash_hex[SKIP_TO_GET_60..])
402
1
      .expect("the output of Sha512 is 64 bytes. the hex encoding of that is 128 bytes,\
403
1
      therefore key_hash_hex[68..] must be 128-68=60 bytes long and so the conversion to [u8; 60] cannot fail; qed")
404
1
  }
405
}
406
407
impl TryFrom<&str> for LegacySighash {
408
  type Error = ();
409
410
5
  fn try_from(hex: &str) -> Result<Self, Self::Error> {
411
5
    if hex.len() == 60 {
412
3
      let mut res = LegacySighash::default();
413
3
      res.0.copy_from_slice(hex.as_bytes());
414
3
      Ok(res)
415
    } else {
416
2
      Err(())
417
    }
418
5
  }
419
}
420
421
#[cfg(feature = "std")]
422
impl serde::Serialize for LegacySighash {
423
1
  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
424
1
  where
425
1
    S: serde::Serializer,
426
1
  {
427
1
    serializer.serialize_str(
428
1
      core::str::from_utf8(self.0.as_slice())
429
1
        .expect("LegacySighash can only be constructed with valid UTF-8, through `Default` or `TryFrom`; qed"),
430
1
    )
431
1
  }
432
}
433
434
#[cfg(feature = "std")]
435
impl<'de> serde::Deserialize<'de> for LegacySighash {
436
1
  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
437
1
  where
438
1
    D: serde::Deserializer<'de>,
439
1
  {
440
1
    Self::try_from(&*String::deserialize(deserializer)
?0
)
441
1
      .map_err(|()| 
serde::de::Error::custom("expected 60 bytes")0
)
442
1
  }
443
}
444
445
63
#[derive(
C2
lon
e2
, Encode,
D35
ecode, Eq,
P7
artialE
q7
,
R8
untimeDebu
g8
,
T2
ypeInfo,
MaxEncodedLen1
)]
446
1
pub enum Task<AccountId, BlockNum, Hash, Moment> {
447
  VerifyTransfer(UnverifiedTransfer<AccountId, BlockNum, Hash, Moment>),
448
  CollectCoins(UnverifiedCollectedCoins),
449
}
450
451
impl<AccountId, BlockNum, Hash, Moment> From<UnverifiedTransfer<AccountId, BlockNum, Hash, Moment>>
452
  for Task<AccountId, BlockNum, Hash, Moment>
453
{
454
55
  fn from(transfer: UnverifiedTransfer<AccountId, BlockNum, Hash, Moment>) -> Self {
455
55
    Task::VerifyTransfer(transfer)
456
55
  }
457
}
458
459
impl<AccountId, BlockNum, Hash, Moment> From<UnverifiedCollectedCoins>
460
  for Task<AccountId, BlockNum, Hash, Moment>
461
{
462
16
  fn from(coins: UnverifiedCollectedCoins) -> Self {
463
16
    Task::CollectCoins(coins)
464
16
  }
465
}
466
467
131
#[derive(
C10
lon
e10
, Encode,
D39
ecode, Eq,
P13
artialE
q13
,
R17
untimeDebu
g17
,
T2
ypeInfo,
MaxEncodedLen1
)]
468
1
pub enum TaskId<Hash> {
469
  VerifyTransfer(TransferId<Hash>),
470
  CollectCoins(CollectedCoinsId<Hash>),
471
}
472
473
impl<Hash> From<TransferId<Hash>> for TaskId<Hash> {
474
60
  fn from(id: TransferId<Hash>) -> Self {
475
60
    TaskId::VerifyTransfer(id)
476
60
  }
477
}
478
479
impl<Hash> From<CollectedCoinsId<Hash>> for TaskId<Hash> {
480
47
  fn from(id: CollectedCoinsId<Hash>) -> Self {
481
47
    TaskId::CollectCoins(id)
482
47
  }
483
}
484
485
10
#[derive(Clone, 
E8
ncod
e8
,
D6
ecode, Eq, PartialEq,
R1
untimeDebu
g1
,
T2
ypeInfo,
MaxEncodedLen1
)]
486
1
pub enum TaskOutput<AccountId, Balance, BlockNum, Hash, Moment> {
487
  VerifyTransfer(TransferId<Hash>, Transfer<AccountId, BlockNum, Hash, Moment>),
488
  CollectCoins(CollectedCoinsId<Hash>, CollectedCoins<Hash, Balance>),
489
}
490
491
impl<AccountId, Balance, BlockNum, Hash, Moment>
492
  From<(TransferId<Hash>, Transfer<AccountId, BlockNum, Hash, Moment>)>
493
  for TaskOutput<AccountId, Balance, BlockNum, Hash, Moment>
494
{
495
8
  fn from(
496
8
    (id, transfer): (TransferId<Hash>, Transfer<AccountId, BlockNum, Hash, Moment>),
497
8
  ) -> Self {
498
8
    Self::VerifyTransfer(id, transfer)
499
8
  }
500
}
501
502
impl<AccountId, Balance, BlockNum, Hash, Moment>
503
  From<(CollectedCoinsId<Hash>, CollectedCoins<Hash, Balance>)>
504
  for TaskOutput<AccountId, Balance, BlockNum, Hash, Moment>
505
{
506
13
  fn from((id, coins): (CollectedCoinsId<Hash>, CollectedCoins<Hash, Balance>)) -> Self {
507
13
    Self::CollectCoins(id, coins)
508
13
  }
509
}
510
511
6
#[derive(
C2
lon
e2
,
E1
ncod
e1
,
D1
ecode, Eq, PartialEq,
R1
untimeDebu
g1
,
T2
ypeInfo,
MaxEncodedLen1
)]
512
1
pub enum TaskData<AccountId, Balance, BlockNum, Hash, Moment> {
513
  VerifyTransfer(UnverifiedTransfer<AccountId, BlockNum, Hash, Moment>, Option<Moment>),
514
  CollectCoins(UnverifiedCollectedCoins, Balance),
515
}
516
517
#[cfg(test)]
518
mod test {
519
  use crate::{
520
    helpers::HexToAddress, mock, ocw::tasks::collect_coins::tests::TX_HASH, tests::TestInfo, *,
521
  };
522
  use codec::{Decode, Encode};
523
  use sp_runtime::testing::H256;
524
525
  type AccountId = mock::AccountId;
526
  type Balance = mock::Balance;
527
  type BlockNum = mock::BlockNumber;
528
  type Hash = H256;
529
  type Moment = u64;
530
531
  macro_rules! implements {(
532
    $T:ty : $($bounds:tt)*
533
  ) => ({
534
    use ::core::marker::PhantomData;
535
536
    trait DefaultValue {
537
0
      fn value (self: &'_ Self) -> bool { false }
538
    }
539
    impl<T : ?Sized> DefaultValue for &'_ PhantomData<T> {}
540
    trait SpecializedValue {
541
70
      fn value (self: &'_ Self) -> bool { true }
542
    }
543
    impl<T : ?Sized> SpecializedValue for PhantomData<T>
544
    where
545
      T : $($bounds)*
546
    {}
547
    (&PhantomData::<$T>).value()
548
  })}
549
550
  macro_rules! trait_tests {
551
  ($($name:ident: $type:ty: $default_value:expr,)*) => {
552
    use codec::MaxEncodedLen;
553
    use scale_info::TypeInfo;
554
  $(
555
    mod $name {
556
      use super::*;
557
558
      #[test]
559
35
      fn test_typeinfo() {
560
35
        <$type>::type_info();
561
35
      }
562
563
      #[test]
564
35
      fn test_maxencodedlen() {
565
35
        if (implements!($type : MaxEncodedLen)) {
566
35
          let result = <$type>::max_encoded_len();
567
35
          assert!(result > 0);
568
0
        }
569
35
      }
570
571
      #[test]
572
35
      fn test_encode_decode() {
573
35
        if (implements!($type : Encode)) {
574
35
          mock::ExtBuilder::default().build_and_execute(|| {
575
            // assign $default_value to a local variable to prevent double
576
            // evaluation which leads to AddressAlreadyRegistered error
577
            let value = $default_value;
578
579
            let as_scale = value.encode();
580
            assert!(as_scale.len() > 0);
581
582
            let decoded = <$type>::decode(&mut &as_scale[..]).unwrap();
583
            assert_eq!(decoded, value);
584
35
          })
585
0
        }
586
35
      }
587
588
      #[test]
589
35
      fn test_runtimedebug() {
590
35
        mock::ExtBuilder::default().build_and_execute(|| {
591
          let value = $default_value;
592
          format!("{:?}", value);
593
35
        })
594
35
      }
595
596
      #[test]
597
35
      fn test_clone_and_partialeq() {
598
35
        mock::ExtBuilder::default().build_and_execute(|| {
599
          let a = $default_value;
600
          let b = a.clone();
601
          let c = b.clone();
602
603
          // exercise equality comparisons, see
604
          // https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
605
          // https://users.rust-lang.org/t/what-is-the-difference-between-eq-and-partialeq/15751/2
606
607
          // symmetric
608
          assert!(a == b);
609
          assert!(b == a);
610
611
          // transitive
612
          assert!(a == b);
613
          assert!(b == c);
614
          assert!(a == c);
615
35
        })
616
35
      }
617
618
    }
619
  )*}}
620
621
9
  fn create_funding_transfer() -> tests::TestTransfer {
622
9
    let test_info = TestInfo::new_defaults();
623
9
    let (deal_order_id, _) = test_info.create_deal_order();
624
9
    test_info.create_funding_transfer(&deal_order_id)
625
9
  }
626
627
3
  fn create_collected_coins() -> CollectedCoins<Hash, Balance> {
628
3
    CollectedCoins {
629
3
      to: AddressId::new::<mock::Test>(&Blockchain::RINKEBY, b"tester"),
630
3
      amount: 1000,
631
3
      tx_id: TX_HASH.hex_to_address(),
632
3
    }
633
3
  }
634
635
9
  fn create_unverified_collected_coins() -> UnverifiedCollectedCoins {
636
9
    UnverifiedCollectedCoins {
637
9
      to: b"baba".to_vec().try_into().unwrap(),
638
9
      tx_id: TX_HASH.hex_to_address(),
639
9
      contract: Default::default(),
640
9
    }
641
9
  }
642
643
3
  fn create_unverified_transfer() -> UnverifiedTransfer<AccountId, BlockNum, Hash, Moment> {
644
3
    let test_info = TestInfo::new_defaults();
645
3
    let (deal_order_id, _) = test_info.create_deal_order();
646
3
    let (_, transfer) = test_info.create_funding_transfer(&deal_order_id);
647
3
    UnverifiedTransfer {
648
3
      currency_to_check: CurrencyOrLegacyTransferKind::Currency(test_info.currency),
649
3
      transfer,
650
3
      from_external: b"lender".to_vec().try_into().unwrap(),
651
3
      to_external: b"borrower".to_vec().try_into().unwrap(),
652
3
      deadline: 1_000_000,
653
3
    }
654
3
  }
655
656
3
  fn create_address() -> Address<AccountId> {
657
3
    Address {
658
3
      blockchain: Blockchain::RINKEBY,
659
3
      value: ExternalAddress::try_from(
660
3
        hex::decode("09231da7b19A016f9e576d23B16277062F4d46A8").unwrap(),
661
3
      )
662
3
      .unwrap(),
663
3
      owner: AccountId::new([77; 32]),
664
3
    }
665
3
  }
666
667
280
  trait_tests! {
668
280
  address: Address<AccountId> : create_address(),
669
280
  collected_coins: CollectedCoins<Hash, Balance> : create_collected_coins(),
670
280
  transfer: Transfer<AccountId, BlockNum, Hash, Moment> : create_funding_transfer().1,
671
280
  unverified_collected_coins: UnverifiedCollectedCoins : create_unverified_collected_coins(),
672
280
  unverified_transfer: UnverifiedTransfer<AccountId, BlockNum, Hash, Moment> : create_unverified_transfer(),
673
280
  offer: Offer<AccountId, BlockNum, Hash> : TestInfo::new_defaults().create_offer().1,
674
280
  ask_order: AskOrder<AccountId, BlockNum, Hash> : TestInfo::new_defaults().create_ask_order().1,
675
280
  bid_order: BidOrder<AccountId, BlockNum, Hash> : TestInfo::new_defaults().create_bid_order().1,
676
280
  deal_order: DealOrder<AccountId, BlockNum, Hash, Moment> : TestInfo::new_defaults().create_deal_order().1,
677
280
  address_id: AddressId<Hash> : AddressId::new::<mock::Test>(&Blockchain::RINKEBY, b"0"),
678
280
  ask_order_id: AskOrderId<BlockNum, Hash> : TestInfo::new_defaults().create_ask_order().0,
679
280
  bid_order_id: BidOrderId<BlockNum, Hash> : TestInfo::new_defaults().create_bid_order().0,
680
280
  deal_order_id: DealOrderId<BlockNum, Hash> : TestInfo::new_defaults().create_deal_order().0,
681
280
  offer_id: OfferId<BlockNum, Hash> : TestInfo::new_defaults().create_offer().0,
682
280
  transfer_id: TransferId<Hash> : TransferId::new::<mock::Test>(&Blockchain::RINKEBY, b"0"),
683
280
  collected_coins_id: CollectedCoinsId<Hash> : CollectedCoinsId::new::<mock::Test>(&Blockchain::RINKEBY, &[0]),
684
280
  legacy_sighash: LegacySighash : LegacySighash::default(),
685
280
  task: Task<AccountId, BlockNum, Hash, Moment> : Task::<AccountId, BlockNum, Hash, Moment>::from(create_unverified_collected_coins()),
686
280
  task_id: TaskId<Hash> : TaskId::from(create_funding_transfer().0),
687
280
  task_output: TaskOutput<AccountId, Balance, BlockNum, Hash, Moment> : TaskOutput::<AccountId, Balance, BlockNum, Hash, Moment>::from(
688
280
    create_funding_transfer()
689
280
  ),
690
280
  task_data: TaskData<AccountId, Balance, BlockNum, Hash, Moment> : TaskData::<AccountId, Balance, BlockNum, Hash, Moment>::CollectCoins(
691
280
    create_unverified_collected_coins(), 2000
692
280
  ),
693
280
694
280
  // from types/loan_terms.rs
695
280
  duration: Duration : Duration::from_millis(100),
696
280
  interest_type: InterestType : InterestType::Simple,
697
280
  interest_rate: InterestRate : InterestRate::default(),
698
280
  loan_terms: LoanTerms<Hash> : TestInfo::new_defaults().loan_terms,
699
280
  ask_terms: AskTerms<Hash> : AskTerms::try_from(TestInfo::new_defaults().loan_terms).unwrap(),
700
280
  bid_terms: BidTerms<Hash> : BidTerms::try_from(TestInfo::new_defaults().loan_terms).unwrap(),
701
280
702
280
  // from types/platform.rs
703
280
  evm_chain_id: EvmChainId : EvmChainId::from(44),
704
280
  evm_info: EvmInfo : EvmInfo { chain_id: 0.into() },
705
280
  blockchain: Blockchain : Blockchain::Evm(EvmInfo { chain_id: 0.into() }),
706
280
  evm_transfer_kind: EvmTransferKind : EvmTransferKind::Erc20,
707
280
  evm_currency_type: EvmCurrencyType : match Currency::default() {
708
280
    Currency::Evm(currency_type, _) => currency_type,
709
280
  },
710
280
  currency: Currency : Currency::default(),
711
280
  transfer_kind: TransferKind : TransferKind::Evm(EvmTransferKind::Erc20),
712
280
  currency_id: CurrencyId<Hash> : CurrencyId::new::<mock::Test>(&Currency::default()),
713
280
  }
714
715
1
  #[test]
716
1
  fn test_blockchain_as_bytes() {
717
1
    let other = Blockchain::Evm(EvmInfo { chain_id: EvmChainId::new(10) });
718
1
    assert_eq!(&*other.as_bytes(), b"evm-10");
719
1
  }
720
721
1
  #[test]
722
1
  fn test_legacysighash_try_from_when_string_is_shorter_than_60_chars() {
723
1
    let result = LegacySighash::try_from("too-short");
724
1
    assert!(result.is_err());
725
1
  }
726
727
1
  #[test]
728
1
  fn test_legacysighash_try_from_when_string_is_longer_than_60_chars() {
729
1
    let result = LegacySighash::try_from(
730
1
      "this-dummy-string-is-very-very-very-long-and-cannot-be-a-legacy-sighash",
731
1
    );
732
1
    assert!(result.is_err());
733
1
  }
734
735
1
  #[test]
736
1
  fn test_legacysighash_serialize_deserialize() {
737
1
    let value = LegacySighash::default();
738
1
739
1
    let json_string = serde_json::to_string(&value).unwrap();
740
1
    let deserialized_value = serde_json::from_str(&json_string).unwrap();
741
1
    assert_eq!(value, deserialized_value);
742
1
  }
743
744
1
  #[test]
745
1
  fn test_duration_new() {
746
1
    let result = Duration::new(5u64, 4000000u32);
747
1
    assert_eq!(result, Duration::from_millis(5004));
748
1
  }
749
750
1
  #[test]
751
1
  fn test_bidterms_match_with() {
752
1
    mock::ExtBuilder::default().build_and_execute(|| {
753
1
      let loan_terms = TestInfo::new_defaults().loan_terms;
754
1
      let ask_terms = AskTerms::try_from(loan_terms.clone()).unwrap();
755
1
      let bid_terms = BidTerms::try_from(loan_terms).unwrap();
756
1
757
1
      assert!(bid_terms.match_with(&ask_terms));
758
1
    })
759
1
  }
760
761
1
  #[test]
762
1
  fn test_bidterms_agreed_terms() {
763
1
    mock::ExtBuilder::default().build_and_execute(|| {
764
1
      let loan_terms = TestInfo::new_defaults().loan_terms;
765
1
      let ask_terms = AskTerms::try_from(loan_terms.clone()).unwrap();
766
1
      let bid_terms = BidTerms::try_from(loan_terms).unwrap();
767
1
768
1
      assert_eq!(
769
1
        ask_terms.agreed_terms(bid_terms.clone()),
770
1
        bid_terms.agreed_terms(&ask_terms),
771
1
      );
772
1
    })
773
1
  }
774
775
1
  #[test]
776
1
  fn test_evmchainid_new() {
777
1
    assert_eq!(EvmChainId::new(46), EvmChainId::from(46),);
778
1
  }
779
780
1
  #[test]
781
  #[allow(clippy::clone_on_copy)]
782
1
  fn exercise_invalid_term_length_error_clone_and_runtime_debug() {
783
1
    let value = InvalidTermLengthError;
784
1
    let new_value = value.clone();
785
1
    format!("{:?}", new_value);
786
1
  }
787
}