Skip to content

Commit b57132e

Browse files
committed
feat: unit tests
1 parent 6a19e64 commit b57132e

File tree

2 files changed

+224
-0
lines changed

2 files changed

+224
-0
lines changed

pallets/msa/src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod mock;
33
mod creation_tests;
44
mod delegation_tests;
55
mod governance_tests;
6+
mod msa_token_tests;
67
mod offchain_tests;
78
mod other_tests;
89
mod public_key_tests;
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
use frame_support::{
2+
assert_noop, assert_ok,
3+
traits::{Currency, tokens::{Fortitude, Preservation, fungible::Inspect}},
4+
};
5+
6+
use sp_core::{sr25519, Encode, Pair};
7+
use sp_runtime::{MultiSignature};
8+
9+
use crate::{
10+
tests::mock::*,
11+
types::AddKeyData,
12+
Config, Error,
13+
};
14+
15+
use common_primitives::{
16+
msa::{H160, MessageSourceId},
17+
node::BlockNumber,
18+
signatures::{AccountAddressMapper, EthereumAddressMapper},
19+
utils::wrap_binary_data,
20+
};
21+
22+
use pallet_balances::Event as BalancesEvent;
23+
24+
fn generate_payload(msa_id: MessageSourceId, msa_owner_keys: &sr25519::Pair, new_public_key: &sr25519::Pair, expiration: Option<BlockNumber>) -> (AddKeyData::<Test>, Vec<u8>, MultiSignature) {
25+
let payload = AddKeyData::<Test> {
26+
msa_id,
27+
expiration: match expiration {
28+
Some(block_number) => block_number,
29+
None => 10
30+
},
31+
new_public_key: new_public_key.public().into()
32+
};
33+
34+
let encoded_payload = wrap_binary_data(payload.encode());
35+
let signature: MultiSignature = msa_owner_keys.sign(&encoded_payload).into();
36+
37+
(payload, encoded_payload, signature)
38+
}
39+
40+
#[test]
41+
fn it_fails_when_caller_key_does_not_match_payload() {
42+
new_test_ext().execute_with(|| {
43+
let (msa_id, owner_key_pair) = create_account();
44+
let (origin_key_pair, _) = sr25519::Pair::generate();
45+
let (other_key_pair, _) = sr25519::Pair::generate();
46+
47+
let (payload, _, msa_signature) = generate_payload(msa_id, &owner_key_pair, &other_key_pair, None);
48+
49+
assert_noop!(
50+
Msa::withdraw_tokens(
51+
RuntimeOrigin::signed(origin_key_pair.public().into()),
52+
owner_key_pair.public().into(),
53+
msa_signature,
54+
payload
55+
),
56+
Error::<Test>::NotKeyOwner
57+
);
58+
});
59+
}
60+
61+
#[test]
62+
fn it_fails_when_payload_signature_is_invalid() {
63+
new_test_ext().execute_with(|| {
64+
let (msa_id, owner_key_pair) = create_account();
65+
let (origin_key_pair, _) = sr25519::Pair::generate();
66+
let (other_key_pair, _) = sr25519::Pair::generate();
67+
68+
let (payload, _, msa_signature) = generate_payload(msa_id, &other_key_pair, &origin_key_pair, None);
69+
70+
assert_noop!(
71+
Msa::withdraw_tokens(
72+
RuntimeOrigin::signed(origin_key_pair.public().into()),
73+
owner_key_pair.public().into(),
74+
msa_signature,
75+
payload
76+
),
77+
Error::<Test>::MsaOwnershipInvalidSignature
78+
);
79+
});
80+
}
81+
82+
#[test]
83+
fn it_fails_when_proof_is_expired() {
84+
new_test_ext().execute_with(|| {
85+
let (msa_id, owner_key_pair) = create_account();
86+
let (origin_key_pair, _) = sr25519::Pair::generate();
87+
88+
// The current block is 1, therefore setting the proof expiration to 1 should cause
89+
// the extrinsic to fail because the proof has expired.
90+
let (payload, _, msa_signature) = generate_payload(msa_id, &owner_key_pair, &origin_key_pair, Some(1));
91+
92+
assert_noop!(
93+
Msa::withdraw_tokens(
94+
RuntimeOrigin::signed(origin_key_pair.public().into()),
95+
owner_key_pair.public().into(),
96+
msa_signature,
97+
payload
98+
),
99+
Error::<Test>::ProofHasExpired
100+
);
101+
});
102+
}
103+
104+
#[test]
105+
fn it_fails_when_proof_is_not_yet_valid() {
106+
new_test_ext().execute_with(|| {
107+
let (msa_id, owner_key_pair) = create_account();
108+
let (origin_key_pair, _) = sr25519::Pair::generate();
109+
110+
// The current block is 1, therefore setting the proof expiration to the max mortality period
111+
// should cause the extrinsic to fail
112+
let (payload, _, msa_signature) = generate_payload(msa_id, &owner_key_pair, &origin_key_pair, Some(Msa::mortality_block_limit(1)));
113+
114+
assert_noop!(
115+
Msa::withdraw_tokens(
116+
RuntimeOrigin::signed(origin_key_pair.public().into()),
117+
owner_key_pair.public().into(),
118+
msa_signature,
119+
payload
120+
),
121+
Error::<Test>::ProofNotYetValid
122+
);
123+
});
124+
}
125+
126+
#[test]
127+
fn it_fails_when_msa_key_is_not_an_msa_control_key() {
128+
new_test_ext().execute_with(|| {
129+
let (msa_id, owner_key_pair) = create_account();
130+
let (origin_key_pair, _) = sr25519::Pair::generate();
131+
132+
let (payload, _, msa_signature) = generate_payload(msa_id + 1, &owner_key_pair, &origin_key_pair, None);
133+
134+
assert_noop!(
135+
Msa::withdraw_tokens(
136+
RuntimeOrigin::signed(origin_key_pair.public().into()),
137+
owner_key_pair.public().into(),
138+
msa_signature,
139+
payload
140+
),
141+
Error::<Test>::NotMsaOwner
142+
);
143+
})
144+
}
145+
146+
#[test]
147+
fn it_fails_when_msa_key_does_not_control_msa_in_payload() {
148+
new_test_ext().execute_with(|| {
149+
let (msa_id, _) = create_account();
150+
let (origin_key_pair, _) = sr25519::Pair::generate();
151+
let (other_key_pair, _) = sr25519::Pair::generate();
152+
153+
let (payload, _, msa_signature) = generate_payload(msa_id, &other_key_pair, &origin_key_pair, None);
154+
155+
assert_noop!(
156+
Msa::withdraw_tokens(
157+
RuntimeOrigin::signed(origin_key_pair.public().into()),
158+
other_key_pair.public().into(),
159+
msa_signature,
160+
payload
161+
),
162+
Error::<Test>::NoKeyExists
163+
);
164+
})
165+
}
166+
167+
#[test]
168+
fn it_fails_when_msa_does_not_have_a_balance() {
169+
new_test_ext().execute_with(|| {
170+
let (msa_id, owner_key_pair) = create_account();
171+
let (origin_key_pair, _) = sr25519::Pair::generate();
172+
173+
let (payload, _, msa_signature) = generate_payload(msa_id, &owner_key_pair, &origin_key_pair, None);
174+
175+
assert_noop!(
176+
Msa::withdraw_tokens(
177+
RuntimeOrigin::signed(origin_key_pair.public().into()),
178+
owner_key_pair.public().into(),
179+
msa_signature,
180+
payload
181+
),
182+
Error::<Test>::InsufficientBalanceToWithdraw
183+
);
184+
})
185+
}
186+
187+
#[test]
188+
fn it_succeeds_when_balance_is_sufficient() {
189+
new_test_ext().execute_with(|| {
190+
let (msa_id, owner_key_pair) = create_account();
191+
let (origin_key_pair, _) = sr25519::Pair::generate();
192+
let eth_account_id: H160 = Msa::msa_id_to_eth_address(msa_id);
193+
let bytes = EthereumAddressMapper::to_bytes32(&eth_account_id.0);
194+
let msa_account_id = <Test as frame_system::Config>::AccountId::from(bytes.clone());
195+
196+
let (payload, _, msa_signature) = generate_payload(msa_id, &owner_key_pair, &origin_key_pair, None);
197+
198+
let transfer_amount = 10_000_000;
199+
200+
// Fund MSA
201+
let _ = <Test as Config>::Currency::deposit_creating(&msa_account_id, transfer_amount);
202+
203+
assert_ok!(
204+
Msa::withdraw_tokens(
205+
RuntimeOrigin::signed(origin_key_pair.public().into()),
206+
owner_key_pair.public().into(),
207+
msa_signature,
208+
payload
209+
)
210+
);
211+
212+
let receiver_balance = <Test as Config>::Currency::reducible_balance(
213+
&origin_key_pair.public().into(),
214+
Preservation::Expendable,
215+
Fortitude::Polite
216+
);
217+
assert_eq!(receiver_balance, transfer_amount, "transfer amount {} does not equal new balance {}", transfer_amount, receiver_balance);
218+
219+
System::assert_last_event(
220+
RuntimeEvent::Balances(BalancesEvent::Transfer { from: msa_account_id, to: origin_key_pair.public().into(), amount: transfer_amount }),
221+
);
222+
})
223+
}

0 commit comments

Comments
 (0)