@@ -38,11 +38,205 @@ const SIGNATURE_TRANSFER: SignatureEd25519 = SignatureEd25519([
38
38
21 , 68 , 42 , 79 , 106 , 106 , 87 , 125 , 122 , 77 , 154 , 114 , 208 , 145 , 171 , 47 , 108 , 96 , 221 , 13 ,
39
39
] ) ;
40
40
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
+
41
48
const DUMMY_SIGNATURE : SignatureEd25519 = SignatureEd25519 ( [
42
49
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 ,
43
50
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 ,
44
51
] ) ;
45
52
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
+
46
240
/// Test permit transfer function. The signature is generated in the test case.
47
241
/// TOKEN_1 is transferred from Alice to Bob.
48
242
#[ test]
@@ -493,6 +687,61 @@ fn test_operator_can_transfer() {
493
687
] ) ;
494
688
}
495
689
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
+
496
745
/// Helper function that sets up the contract with two tokens minted to
497
746
/// Alice, `TOKEN_0` and `TOKEN_1`.
498
747
///
@@ -530,38 +779,6 @@ fn initialize_contract_with_alice_tokens(
530
779
( chain, contract_address, update, keypairs)
531
780
}
532
781
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
-
565
782
/// Setup chain and contract.
566
783
///
567
784
/// Also creates the two accounts, Alice and Bob.
0 commit comments