Skip to content

Commit 0dc9149

Browse files
committed
Add update operator test cases
1 parent a3c219c commit 0dc9149

File tree

1 file changed

+249
-32
lines changed
  • examples/cis3-nft-sponsored-txs/tests

1 file changed

+249
-32
lines changed

examples/cis3-nft-sponsored-txs/tests/tests.rs

Lines changed: 249 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,205 @@ const SIGNATURE_TRANSFER: SignatureEd25519 = SignatureEd25519([
3838
21, 68, 42, 79, 106, 106, 87, 125, 122, 77, 154, 114, 208, 145, 171, 47, 108, 96, 221, 13,
3939
]);
4040

41+
const SIGNATURE_UPDATE_OPERATOR: SignatureEd25519 = SignatureEd25519([
42+
199, 250, 51, 48, 15, 210, 20, 180, 70, 191, 98, 217, 109, 67, 115, 94, 195, 81, 16, 157, 59,
43+
26, 36, 147, 91, 196, 254, 133, 149, 27, 148, 124, 130, 206, 68, 195, 139, 189, 244, 43, 253,
44+
12, 58, 17, 102, 63, 203, 35, 159, 54, 94, 59, 12, 193, 48, 78, 144, 112, 245, 149, 12, 181,
45+
74, 10,
46+
]);
47+
4148
const DUMMY_SIGNATURE: SignatureEd25519 = SignatureEd25519([
4249
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4350
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4451
]);
4552

53+
/// Test permit update operator function. The signature is generated in the test
54+
/// case. ALICE adds BOB as an operator.
55+
#[test]
56+
fn test_inside_signature_permit_update_operator() {
57+
let (mut chain, contract_address, _update, keypairs) =
58+
initialize_contract_with_alice_tokens(true);
59+
60+
// Check operator in state
61+
let bob_is_operator_of_alice = operator_of(&chain, contract_address);
62+
63+
assert_eq!(bob_is_operator_of_alice, OperatorOfQueryResponse(vec![false]));
64+
65+
// Create input parematers for the `permit` updateOperator function.
66+
let update_operator = UpdateOperator {
67+
update: OperatorUpdate::Add,
68+
operator: BOB_ADDR,
69+
};
70+
let payload = UpdateOperatorParams(vec![update_operator]);
71+
72+
let mut inner_signature_map = BTreeMap::new();
73+
inner_signature_map.insert(0u8, concordium_std::Signature::Ed25519(DUMMY_SIGNATURE));
74+
75+
let mut signature_map = BTreeMap::new();
76+
signature_map.insert(0u8, CredentialSignatures {
77+
sigs: inner_signature_map,
78+
});
79+
80+
let mut permit_update_operator_param = PermitParam {
81+
signature: AccountSignatures {
82+
sigs: signature_map,
83+
},
84+
signer: ALICE,
85+
message: PermitMessage {
86+
timestamp: Timestamp::from_timestamp_millis(10000000000),
87+
contract_address: ContractAddress {
88+
index: 0,
89+
subindex: 0,
90+
},
91+
entry_point: OwnedEntrypointName::new_unchecked("updateOperator".into()),
92+
nonce: 0,
93+
payload: to_bytes(&payload),
94+
},
95+
};
96+
97+
let invoke = chain
98+
.contract_invoke(BOB, BOB_ADDR, Energy::from(10000), UpdateContractPayload {
99+
amount: Amount::zero(),
100+
address: contract_address,
101+
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.viewMessageHash".to_string()),
102+
message: OwnedParameter::from_serial(&permit_update_operator_param)
103+
.expect("Should be a valid inut parameter"),
104+
})
105+
.expect("Should be able to query balanceOf");
106+
107+
let message_hash: HashSha2256 =
108+
from_bytes(&invoke.return_value).expect("Should return a valid result");
109+
110+
permit_update_operator_param.signature = keypairs
111+
.expect("Should have a generated private key to sign")
112+
.sign_message(&to_bytes(&message_hash));
113+
114+
// Update operator with the permit function.
115+
let update = chain
116+
.contract_update(
117+
Signer::with_one_key(),
118+
ACC_ADDR_OWNER,
119+
Address::Account(ACC_ADDR_OWNER),
120+
Energy::from(10000),
121+
UpdateContractPayload {
122+
amount: Amount::zero(),
123+
address: contract_address,
124+
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.permit".to_string()),
125+
message: OwnedParameter::from_serial(&permit_update_operator_param)
126+
.expect("Should be a valid inut parameter"),
127+
},
128+
)
129+
.expect("Should be able to update operator with permit");
130+
131+
// Check that the correct events occurred.
132+
let events = update
133+
.events()
134+
.flat_map(|(_addr, events)| events.iter().map(|e| e.parse().expect("Deserialize event")))
135+
.collect::<Vec<Event>>();
136+
137+
assert_eq!(events, [
138+
Event::Cis2Event(Cis2Event::UpdateOperator(UpdateOperatorEvent {
139+
update: OperatorUpdate::Add,
140+
owner: ALICE_ADDR,
141+
operator: BOB_ADDR,
142+
})),
143+
Event::Nonce(NonceEvent {
144+
account: ALICE,
145+
nonce: 0,
146+
})
147+
]);
148+
149+
// Check operator in state
150+
let bob_is_operator_of_alice = operator_of(&chain, contract_address);
151+
152+
assert_eq!(bob_is_operator_of_alice, OperatorOfQueryResponse(vec![true]));
153+
}
154+
155+
/// Test permit update operator function. The signature is generated outside
156+
/// this test case (e.g. with https://cyphr.me/ed25519_tool/ed.html). ALICE adds BOB as an operator.
157+
#[test]
158+
fn test_outside_signature_permit_update_operator() {
159+
let (mut chain, contract_address, _update, _keypairs) =
160+
initialize_contract_with_alice_tokens(false);
161+
162+
// Check operator in state
163+
let bob_is_operator_of_alice = operator_of(&chain, contract_address);
164+
165+
assert_eq!(bob_is_operator_of_alice, OperatorOfQueryResponse(vec![false]));
166+
167+
// Create input parematers for the `permit` updateOperator function.
168+
let update_operator = UpdateOperator {
169+
update: OperatorUpdate::Add,
170+
operator: BOB_ADDR,
171+
};
172+
let payload = UpdateOperatorParams(vec![update_operator]);
173+
174+
let mut inner_signature_map = BTreeMap::new();
175+
inner_signature_map.insert(0u8, concordium_std::Signature::Ed25519(SIGNATURE_UPDATE_OPERATOR));
176+
177+
let mut signature_map = BTreeMap::new();
178+
signature_map.insert(0u8, CredentialSignatures {
179+
sigs: inner_signature_map,
180+
});
181+
182+
let permit_update_operator_param = PermitParam {
183+
signature: AccountSignatures {
184+
sigs: signature_map,
185+
},
186+
signer: ALICE,
187+
message: PermitMessage {
188+
timestamp: Timestamp::from_timestamp_millis(10000000000),
189+
contract_address: ContractAddress {
190+
index: 0,
191+
subindex: 0,
192+
},
193+
entry_point: OwnedEntrypointName::new_unchecked("updateOperator".into()),
194+
nonce: 0,
195+
payload: to_bytes(&payload),
196+
},
197+
};
198+
199+
// Update operator with the permit function.
200+
let update = chain
201+
.contract_update(
202+
Signer::with_one_key(),
203+
ACC_ADDR_OWNER,
204+
Address::Account(ACC_ADDR_OWNER),
205+
Energy::from(10000),
206+
UpdateContractPayload {
207+
amount: Amount::zero(),
208+
address: contract_address,
209+
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.permit".to_string()),
210+
message: OwnedParameter::from_serial(&permit_update_operator_param)
211+
.expect("Should be a valid inut parameter"),
212+
},
213+
)
214+
.expect("Should be able to update operator with permit");
215+
216+
// Check that the correct events occurred.
217+
let events = update
218+
.events()
219+
.flat_map(|(_addr, events)| events.iter().map(|e| e.parse().expect("Deserialize event")))
220+
.collect::<Vec<Event>>();
221+
222+
assert_eq!(events, [
223+
Event::Cis2Event(Cis2Event::UpdateOperator(UpdateOperatorEvent {
224+
update: OperatorUpdate::Add,
225+
owner: ALICE_ADDR,
226+
operator: BOB_ADDR,
227+
})),
228+
Event::Nonce(NonceEvent {
229+
account: ALICE,
230+
nonce: 0,
231+
})
232+
]);
233+
234+
// Check operator in state
235+
let bob_is_operator_of_alice = operator_of(&chain, contract_address);
236+
237+
assert_eq!(bob_is_operator_of_alice, OperatorOfQueryResponse(vec![true]));
238+
}
239+
46240
/// Test permit transfer function. The signature is generated in the test case.
47241
/// TOKEN_1 is transferred from Alice to Bob.
48242
#[test]
@@ -493,6 +687,61 @@ fn test_operator_can_transfer() {
493687
]);
494688
}
495689

690+
/// Get the `TOKEN_1` balances for Alice and Bob.
691+
fn get_balances(
692+
chain: &Chain,
693+
contract_address: ContractAddress,
694+
) -> ContractBalanceOfQueryResponse {
695+
let balance_of_params = ContractBalanceOfQueryParams {
696+
queries: vec![
697+
BalanceOfQuery {
698+
token_id: TOKEN_1,
699+
address: ALICE_ADDR,
700+
},
701+
BalanceOfQuery {
702+
token_id: TOKEN_1,
703+
address: BOB_ADDR,
704+
},
705+
],
706+
};
707+
708+
let invoke = chain
709+
.contract_invoke(ALICE, ALICE_ADDR, Energy::from(10000), UpdateContractPayload {
710+
amount: Amount::zero(),
711+
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.balanceOf".to_string()),
712+
address: contract_address,
713+
message: OwnedParameter::from_serial(&balance_of_params)
714+
.expect("BalanceOf params"),
715+
})
716+
.expect("Invoke balanceOf");
717+
let rv: ContractBalanceOfQueryResponse =
718+
invoke.parse_return_value().expect("BalanceOf return value");
719+
rv
720+
}
721+
722+
/// Check if Bob is an operator of Alice.
723+
fn operator_of(chain: &Chain, contract_address: ContractAddress) -> OperatorOfQueryResponse {
724+
let operator_of_params = OperatorOfQueryParams {
725+
queries: vec![OperatorOfQuery {
726+
address: BOB_ADDR,
727+
owner: ALICE_ADDR,
728+
}],
729+
};
730+
731+
// Check operator in state
732+
let invoke = chain
733+
.contract_invoke(ALICE, ALICE_ADDR, Energy::from(10000), UpdateContractPayload {
734+
amount: Amount::zero(),
735+
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.operatorOf".to_string()),
736+
address: contract_address,
737+
message: OwnedParameter::from_serial(&operator_of_params)
738+
.expect("OperatorOf params"),
739+
})
740+
.expect("Invoke operatorOf");
741+
let rv: OperatorOfQueryResponse = invoke.parse_return_value().expect("OperatorOf return value");
742+
rv
743+
}
744+
496745
/// Helper function that sets up the contract with two tokens minted to
497746
/// Alice, `TOKEN_0` and `TOKEN_1`.
498747
///
@@ -530,38 +779,6 @@ fn initialize_contract_with_alice_tokens(
530779
(chain, contract_address, update, keypairs)
531780
}
532781

533-
/// Get the `TOKEN_1` balances for Alice and Bob.
534-
fn get_balances(
535-
chain: &Chain,
536-
contract_address: ContractAddress,
537-
) -> ContractBalanceOfQueryResponse {
538-
let balance_of_params = ContractBalanceOfQueryParams {
539-
queries: vec![
540-
BalanceOfQuery {
541-
token_id: TOKEN_1,
542-
address: ALICE_ADDR,
543-
},
544-
BalanceOfQuery {
545-
token_id: TOKEN_1,
546-
address: BOB_ADDR,
547-
},
548-
],
549-
};
550-
551-
let invoke = chain
552-
.contract_invoke(ALICE, ALICE_ADDR, Energy::from(10000), UpdateContractPayload {
553-
amount: Amount::zero(),
554-
receive_name: OwnedReceiveName::new_unchecked("cis3_nft.balanceOf".to_string()),
555-
address: contract_address,
556-
message: OwnedParameter::from_serial(&balance_of_params)
557-
.expect("BalanceOf params"),
558-
})
559-
.expect("Invoke balanceOf");
560-
let rv: ContractBalanceOfQueryResponse =
561-
invoke.parse_return_value().expect("BalanceOf return value");
562-
rv
563-
}
564-
565782
/// Setup chain and contract.
566783
///
567784
/// Also creates the two accounts, Alice and Bob.

0 commit comments

Comments
 (0)