mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
commit
aa36cc09fa
@ -45,6 +45,7 @@ bip39 = "2.2.0"
|
||||
hmac-sha512 = "1.1.7"
|
||||
chrono = "0.4.41"
|
||||
borsh = "1.5.7"
|
||||
base58 = "0.2.0"
|
||||
|
||||
rocksdb = { version = "0.21.0", default-features = false, features = [
|
||||
"snappy",
|
||||
|
||||
@ -8,3 +8,5 @@ pub mod transaction;
|
||||
//TODO: Compile only for tests
|
||||
pub mod test_utils;
|
||||
pub type HashType = [u8; 32];
|
||||
|
||||
pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7";
|
||||
|
||||
@ -8,49 +8,49 @@
|
||||
"port": 3040,
|
||||
"initial_accounts": [
|
||||
{
|
||||
"addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||
"addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
|
||||
"balance": 10000
|
||||
},
|
||||
{
|
||||
"addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||
"addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
|
||||
"balance": 20000
|
||||
}
|
||||
],
|
||||
"initial_commitments": [
|
||||
{
|
||||
"npk": [
|
||||
193,
|
||||
209,
|
||||
150,
|
||||
113,
|
||||
47,
|
||||
241,
|
||||
48,
|
||||
145,
|
||||
250,
|
||||
79,
|
||||
235,
|
||||
51,
|
||||
119,
|
||||
40,
|
||||
184,
|
||||
232,
|
||||
5,
|
||||
63,
|
||||
202,
|
||||
178,
|
||||
231,
|
||||
183,
|
||||
82,
|
||||
237,
|
||||
212,
|
||||
216,
|
||||
221,
|
||||
36,
|
||||
21,
|
||||
201,
|
||||
106,
|
||||
90,
|
||||
210,
|
||||
129,
|
||||
106,
|
||||
71,
|
||||
99,
|
||||
208,
|
||||
215,
|
||||
255,
|
||||
153,
|
||||
75,
|
||||
215
|
||||
101,
|
||||
177,
|
||||
161,
|
||||
254,
|
||||
210,
|
||||
128,
|
||||
122,
|
||||
54,
|
||||
190,
|
||||
230,
|
||||
151,
|
||||
183,
|
||||
64,
|
||||
225,
|
||||
229,
|
||||
113,
|
||||
1,
|
||||
228,
|
||||
97
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
@ -70,38 +70,38 @@
|
||||
},
|
||||
{
|
||||
"npk": [
|
||||
27,
|
||||
250,
|
||||
192,
|
||||
251,
|
||||
166,
|
||||
243,
|
||||
167,
|
||||
236,
|
||||
84,
|
||||
249,
|
||||
35,
|
||||
136,
|
||||
142,
|
||||
88,
|
||||
128,
|
||||
138,
|
||||
21,
|
||||
49,
|
||||
183,
|
||||
118,
|
||||
160,
|
||||
117,
|
||||
114,
|
||||
110,
|
||||
47,
|
||||
136,
|
||||
87,
|
||||
60,
|
||||
70,
|
||||
59,
|
||||
60,
|
||||
18,
|
||||
223,
|
||||
23,
|
||||
147,
|
||||
241,
|
||||
5,
|
||||
184,
|
||||
103,
|
||||
130,
|
||||
172,
|
||||
219,
|
||||
225,
|
||||
105
|
||||
161,
|
||||
139,
|
||||
229,
|
||||
89,
|
||||
243,
|
||||
125,
|
||||
194,
|
||||
213,
|
||||
209,
|
||||
30,
|
||||
23,
|
||||
174,
|
||||
100,
|
||||
244,
|
||||
124,
|
||||
74,
|
||||
140,
|
||||
47
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
@ -154,4 +154,4 @@
|
||||
37,
|
||||
37
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -9,85 +9,85 @@
|
||||
"initial_accounts": [
|
||||
{
|
||||
"Public": {
|
||||
"address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||
"address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
|
||||
"pub_sign_key": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1
|
||||
16,
|
||||
162,
|
||||
106,
|
||||
154,
|
||||
236,
|
||||
125,
|
||||
52,
|
||||
184,
|
||||
35,
|
||||
100,
|
||||
238,
|
||||
174,
|
||||
69,
|
||||
197,
|
||||
41,
|
||||
77,
|
||||
187,
|
||||
10,
|
||||
118,
|
||||
75,
|
||||
0,
|
||||
11,
|
||||
148,
|
||||
238,
|
||||
185,
|
||||
181,
|
||||
133,
|
||||
17,
|
||||
220,
|
||||
72,
|
||||
124,
|
||||
77
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Public": {
|
||||
"address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||
"address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
|
||||
"pub_sign_key": [
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
113,
|
||||
121,
|
||||
64,
|
||||
177,
|
||||
204,
|
||||
85,
|
||||
229,
|
||||
214,
|
||||
178,
|
||||
6,
|
||||
109,
|
||||
191,
|
||||
29,
|
||||
154,
|
||||
63,
|
||||
38,
|
||||
242,
|
||||
18,
|
||||
244,
|
||||
219,
|
||||
8,
|
||||
208,
|
||||
35,
|
||||
136,
|
||||
23,
|
||||
127,
|
||||
207,
|
||||
237,
|
||||
216,
|
||||
169,
|
||||
190,
|
||||
27
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Private": {
|
||||
"address": "d360d6b5763f71ac6af56253687fd7d556d5c6c64312e53c0b92ef039a4375df",
|
||||
"address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw",
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
@ -105,218 +105,218 @@
|
||||
},
|
||||
"key_chain": {
|
||||
"secret_spending_key": [
|
||||
10,
|
||||
125,
|
||||
171,
|
||||
38,
|
||||
201,
|
||||
35,
|
||||
164,
|
||||
43,
|
||||
7,
|
||||
80,
|
||||
7,
|
||||
215,
|
||||
97,
|
||||
42,
|
||||
48,
|
||||
229,
|
||||
101,
|
||||
216,
|
||||
140,
|
||||
21,
|
||||
170,
|
||||
214,
|
||||
251,
|
||||
82,
|
||||
53,
|
||||
235,
|
||||
1,
|
||||
146,
|
||||
96,
|
||||
30,
|
||||
81,
|
||||
162,
|
||||
234,
|
||||
33,
|
||||
15,
|
||||
123,
|
||||
129,
|
||||
116,
|
||||
22,
|
||||
62,
|
||||
79,
|
||||
61,
|
||||
76,
|
||||
71,
|
||||
79
|
||||
0,
|
||||
84,
|
||||
136,
|
||||
176,
|
||||
70,
|
||||
190,
|
||||
224,
|
||||
161,
|
||||
54,
|
||||
134,
|
||||
142,
|
||||
154,
|
||||
1,
|
||||
18,
|
||||
251,
|
||||
242,
|
||||
189
|
||||
],
|
||||
"private_key_holder": {
|
||||
"nullifier_secret_key": [
|
||||
228,
|
||||
136,
|
||||
4,
|
||||
29,
|
||||
250,
|
||||
10,
|
||||
187,
|
||||
35,
|
||||
123,
|
||||
180,
|
||||
250,
|
||||
246,
|
||||
97,
|
||||
216,
|
||||
153,
|
||||
44,
|
||||
156,
|
||||
33,
|
||||
40,
|
||||
194,
|
||||
172,
|
||||
95,
|
||||
168,
|
||||
201,
|
||||
33,
|
||||
24,
|
||||
30,
|
||||
126,
|
||||
197,
|
||||
156,
|
||||
113,
|
||||
64,
|
||||
162,
|
||||
131,
|
||||
210,
|
||||
110,
|
||||
60,
|
||||
24,
|
||||
154,
|
||||
86,
|
||||
59,
|
||||
184,
|
||||
95,
|
||||
245,
|
||||
176
|
||||
16,
|
||||
93,
|
||||
241,
|
||||
26,
|
||||
174,
|
||||
219,
|
||||
72,
|
||||
84,
|
||||
34,
|
||||
247,
|
||||
112,
|
||||
101,
|
||||
217,
|
||||
243,
|
||||
189,
|
||||
173,
|
||||
75,
|
||||
20
|
||||
],
|
||||
"incoming_viewing_secret_key": [
|
||||
197,
|
||||
33,
|
||||
51,
|
||||
200,
|
||||
1,
|
||||
121,
|
||||
60,
|
||||
52,
|
||||
233,
|
||||
234,
|
||||
12,
|
||||
166,
|
||||
196,
|
||||
227,
|
||||
187,
|
||||
1,
|
||||
10,
|
||||
101,
|
||||
183,
|
||||
105,
|
||||
140,
|
||||
28,
|
||||
152,
|
||||
251,
|
||||
201,
|
||||
22,
|
||||
154,
|
||||
100,
|
||||
165,
|
||||
218,
|
||||
108,
|
||||
163,
|
||||
190,
|
||||
135,
|
||||
91,
|
||||
145,
|
||||
84,
|
||||
69,
|
||||
241,
|
||||
46,
|
||||
117,
|
||||
217,
|
||||
109,
|
||||
220,
|
||||
112,
|
||||
103,
|
||||
253,
|
||||
110,
|
||||
98,
|
||||
6
|
||||
197,
|
||||
248,
|
||||
91,
|
||||
193,
|
||||
14,
|
||||
104,
|
||||
88,
|
||||
103,
|
||||
67,
|
||||
153,
|
||||
182,
|
||||
158
|
||||
],
|
||||
"outgoing_viewing_secret_key": [
|
||||
147,
|
||||
34,
|
||||
193,
|
||||
29,
|
||||
39,
|
||||
173,
|
||||
222,
|
||||
25,
|
||||
67,
|
||||
121,
|
||||
76,
|
||||
175,
|
||||
100,
|
||||
30,
|
||||
118,
|
||||
199,
|
||||
44,
|
||||
204,
|
||||
43,
|
||||
232,
|
||||
107,
|
||||
223,
|
||||
249,
|
||||
207,
|
||||
245,
|
||||
183,
|
||||
63,
|
||||
209,
|
||||
129,
|
||||
48,
|
||||
254,
|
||||
66,
|
||||
22,
|
||||
199,
|
||||
81,
|
||||
145,
|
||||
126,
|
||||
92
|
||||
198,
|
||||
105,
|
||||
123,
|
||||
49,
|
||||
169,
|
||||
75,
|
||||
178,
|
||||
75,
|
||||
210,
|
||||
100,
|
||||
143,
|
||||
210,
|
||||
243,
|
||||
228,
|
||||
243,
|
||||
21,
|
||||
18,
|
||||
36,
|
||||
84,
|
||||
164,
|
||||
186,
|
||||
139,
|
||||
113,
|
||||
214,
|
||||
12
|
||||
]
|
||||
},
|
||||
"nullifer_public_key": [
|
||||
193,
|
||||
209,
|
||||
150,
|
||||
113,
|
||||
47,
|
||||
241,
|
||||
48,
|
||||
145,
|
||||
250,
|
||||
79,
|
||||
235,
|
||||
51,
|
||||
119,
|
||||
40,
|
||||
184,
|
||||
232,
|
||||
5,
|
||||
63,
|
||||
202,
|
||||
178,
|
||||
231,
|
||||
183,
|
||||
82,
|
||||
237,
|
||||
212,
|
||||
216,
|
||||
221,
|
||||
36,
|
||||
21,
|
||||
201,
|
||||
106,
|
||||
90,
|
||||
210,
|
||||
129,
|
||||
106,
|
||||
71,
|
||||
99,
|
||||
208,
|
||||
215,
|
||||
255,
|
||||
153,
|
||||
75,
|
||||
215
|
||||
101,
|
||||
177,
|
||||
161,
|
||||
254,
|
||||
210,
|
||||
128,
|
||||
122,
|
||||
54,
|
||||
190,
|
||||
230,
|
||||
151,
|
||||
183,
|
||||
64,
|
||||
225,
|
||||
229,
|
||||
113,
|
||||
1,
|
||||
228,
|
||||
97
|
||||
],
|
||||
"incoming_viewing_public_key": [
|
||||
3,
|
||||
78,
|
||||
235,
|
||||
139,
|
||||
131,
|
||||
237,
|
||||
177,
|
||||
87,
|
||||
193,
|
||||
219,
|
||||
230,
|
||||
160,
|
||||
222,
|
||||
38,
|
||||
182,
|
||||
100,
|
||||
101,
|
||||
223,
|
||||
204,
|
||||
223,
|
||||
198,
|
||||
140,
|
||||
253,
|
||||
94,
|
||||
16,
|
||||
98,
|
||||
77,
|
||||
79,
|
||||
114,
|
||||
30,
|
||||
158,
|
||||
104,
|
||||
34,
|
||||
152,
|
||||
122,
|
||||
189,
|
||||
31,
|
||||
95
|
||||
6,
|
||||
177,
|
||||
167,
|
||||
178,
|
||||
202,
|
||||
117,
|
||||
246,
|
||||
58,
|
||||
28,
|
||||
65,
|
||||
132,
|
||||
79,
|
||||
220,
|
||||
139,
|
||||
119,
|
||||
243,
|
||||
187,
|
||||
160,
|
||||
212,
|
||||
121,
|
||||
61,
|
||||
247,
|
||||
116,
|
||||
72,
|
||||
205
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Private": {
|
||||
"address": "f27087ffc29b99035303697dcf6c8e323b1847d4261e6afd49e0d71c6dfa31ea",
|
||||
"address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX",
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
@ -334,214 +334,214 @@
|
||||
},
|
||||
"key_chain": {
|
||||
"secret_spending_key": [
|
||||
153,
|
||||
109,
|
||||
202,
|
||||
226,
|
||||
97,
|
||||
212,
|
||||
77,
|
||||
147,
|
||||
75,
|
||||
107,
|
||||
153,
|
||||
106,
|
||||
89,
|
||||
167,
|
||||
49,
|
||||
230,
|
||||
122,
|
||||
238,
|
||||
171,
|
||||
241,
|
||||
69,
|
||||
111,
|
||||
217,
|
||||
85,
|
||||
64,
|
||||
19,
|
||||
82,
|
||||
18,
|
||||
189,
|
||||
32,
|
||||
91,
|
||||
78,
|
||||
167,
|
||||
146,
|
||||
14,
|
||||
180,
|
||||
206,
|
||||
175,
|
||||
107,
|
||||
96,
|
||||
193,
|
||||
255,
|
||||
122,
|
||||
207,
|
||||
30,
|
||||
142,
|
||||
99
|
||||
7,
|
||||
109,
|
||||
60,
|
||||
52,
|
||||
44,
|
||||
243,
|
||||
230,
|
||||
72,
|
||||
244,
|
||||
192,
|
||||
92,
|
||||
137,
|
||||
33,
|
||||
118,
|
||||
254
|
||||
],
|
||||
"private_key_holder": {
|
||||
"nullifier_secret_key": [
|
||||
128,
|
||||
25,
|
||||
211,
|
||||
215,
|
||||
147,
|
||||
175,
|
||||
119,
|
||||
16,
|
||||
140,
|
||||
219,
|
||||
155,
|
||||
134,
|
||||
27,
|
||||
81,
|
||||
64,
|
||||
40,
|
||||
196,
|
||||
240,
|
||||
61,
|
||||
144,
|
||||
232,
|
||||
164,
|
||||
181,
|
||||
57,
|
||||
139,
|
||||
96,
|
||||
137,
|
||||
121,
|
||||
140,
|
||||
223,
|
||||
247,
|
||||
37,
|
||||
245,
|
||||
144,
|
||||
122,
|
||||
29,
|
||||
169,
|
||||
68,
|
||||
187,
|
||||
65
|
||||
118,
|
||||
245,
|
||||
83,
|
||||
228,
|
||||
23,
|
||||
9,
|
||||
101,
|
||||
120,
|
||||
88,
|
||||
33,
|
||||
238,
|
||||
207,
|
||||
128,
|
||||
61,
|
||||
110,
|
||||
2,
|
||||
89,
|
||||
62,
|
||||
164,
|
||||
13
|
||||
],
|
||||
"incoming_viewing_secret_key": [
|
||||
185,
|
||||
121,
|
||||
146,
|
||||
213,
|
||||
13,
|
||||
3,
|
||||
93,
|
||||
206,
|
||||
25,
|
||||
127,
|
||||
155,
|
||||
21,
|
||||
155,
|
||||
115,
|
||||
193,
|
||||
181,
|
||||
14,
|
||||
196,
|
||||
142,
|
||||
84,
|
||||
15,
|
||||
65,
|
||||
128,
|
||||
101,
|
||||
70,
|
||||
196,
|
||||
241,
|
||||
47,
|
||||
130,
|
||||
27,
|
||||
57,
|
||||
5,
|
||||
116,
|
||||
80,
|
||||
62,
|
||||
214,
|
||||
67,
|
||||
228,
|
||||
147,
|
||||
189,
|
||||
28,
|
||||
200,
|
||||
62,
|
||||
152,
|
||||
178,
|
||||
103
|
||||
221,
|
||||
23,
|
||||
146,
|
||||
161,
|
||||
237,
|
||||
221,
|
||||
40,
|
||||
19,
|
||||
126,
|
||||
59,
|
||||
15,
|
||||
169,
|
||||
236,
|
||||
25,
|
||||
105,
|
||||
104,
|
||||
231
|
||||
],
|
||||
"outgoing_viewing_secret_key": [
|
||||
163,
|
||||
58,
|
||||
118,
|
||||
160,
|
||||
20,
|
||||
170,
|
||||
220,
|
||||
108,
|
||||
41,
|
||||
23,
|
||||
155,
|
||||
217,
|
||||
247,
|
||||
190,
|
||||
175,
|
||||
86,
|
||||
72,
|
||||
168,
|
||||
247,
|
||||
34,
|
||||
105,
|
||||
134,
|
||||
114,
|
||||
74,
|
||||
104,
|
||||
91,
|
||||
81,
|
||||
69,
|
||||
150,
|
||||
154,
|
||||
113,
|
||||
211,
|
||||
118,
|
||||
110,
|
||||
25,
|
||||
156,
|
||||
250,
|
||||
67,
|
||||
212,
|
||||
198,
|
||||
147,
|
||||
231,
|
||||
213,
|
||||
136,
|
||||
212,
|
||||
198,
|
||||
192,
|
||||
255,
|
||||
62,
|
||||
126,
|
||||
122
|
||||
13,
|
||||
130,
|
||||
100,
|
||||
241,
|
||||
214,
|
||||
250,
|
||||
236,
|
||||
38,
|
||||
150
|
||||
]
|
||||
},
|
||||
"nullifer_public_key": [
|
||||
27,
|
||||
250,
|
||||
192,
|
||||
251,
|
||||
166,
|
||||
243,
|
||||
167,
|
||||
236,
|
||||
84,
|
||||
249,
|
||||
35,
|
||||
136,
|
||||
142,
|
||||
88,
|
||||
128,
|
||||
138,
|
||||
21,
|
||||
49,
|
||||
183,
|
||||
118,
|
||||
160,
|
||||
117,
|
||||
114,
|
||||
110,
|
||||
47,
|
||||
136,
|
||||
87,
|
||||
60,
|
||||
70,
|
||||
59,
|
||||
60,
|
||||
18,
|
||||
223,
|
||||
23,
|
||||
147,
|
||||
241,
|
||||
5,
|
||||
184,
|
||||
103,
|
||||
130,
|
||||
172,
|
||||
219,
|
||||
225,
|
||||
105
|
||||
161,
|
||||
139,
|
||||
229,
|
||||
89,
|
||||
243,
|
||||
125,
|
||||
194,
|
||||
213,
|
||||
209,
|
||||
30,
|
||||
23,
|
||||
174,
|
||||
100,
|
||||
244,
|
||||
124,
|
||||
74,
|
||||
140,
|
||||
47
|
||||
],
|
||||
"incoming_viewing_public_key": [
|
||||
2,
|
||||
56,
|
||||
160,
|
||||
1,
|
||||
22,
|
||||
197,
|
||||
187,
|
||||
214,
|
||||
204,
|
||||
221,
|
||||
84,
|
||||
87,
|
||||
12,
|
||||
204,
|
||||
0,
|
||||
119,
|
||||
116,
|
||||
176,
|
||||
6,
|
||||
149,
|
||||
145,
|
||||
100,
|
||||
211,
|
||||
162,
|
||||
19,
|
||||
158,
|
||||
197,
|
||||
112,
|
||||
142,
|
||||
172,
|
||||
1,
|
||||
181,
|
||||
98,
|
||||
226
|
||||
93,
|
||||
216,
|
||||
241,
|
||||
241,
|
||||
110,
|
||||
58,
|
||||
198,
|
||||
119,
|
||||
174,
|
||||
250,
|
||||
184,
|
||||
1,
|
||||
204,
|
||||
200,
|
||||
173,
|
||||
44,
|
||||
238,
|
||||
37,
|
||||
247,
|
||||
170,
|
||||
156,
|
||||
100,
|
||||
254,
|
||||
116,
|
||||
242,
|
||||
28,
|
||||
183,
|
||||
187,
|
||||
77,
|
||||
255
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -32,18 +32,24 @@ struct Args {
|
||||
test_name: String,
|
||||
}
|
||||
|
||||
pub const ACC_SENDER: &str = "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44";
|
||||
pub const ACC_RECEIVER: &str = "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc";
|
||||
pub const ACC_SENDER: &str = "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
|
||||
pub const ACC_RECEIVER: &str = "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw";
|
||||
|
||||
pub const ACC_SENDER_PRIVATE: &str =
|
||||
"d360d6b5763f71ac6af56253687fd7d556d5c6c64312e53c0b92ef039a4375df";
|
||||
pub const ACC_RECEIVER_PRIVATE: &str =
|
||||
"f27087ffc29b99035303697dcf6c8e323b1847d4261e6afd49e0d71c6dfa31ea";
|
||||
pub const ACC_SENDER_PRIVATE: &str = "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw";
|
||||
pub const ACC_RECEIVER_PRIVATE: &str = "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX";
|
||||
|
||||
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
|
||||
|
||||
pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin");
|
||||
|
||||
fn make_public_account_input_from_str(addr: &str) -> String {
|
||||
format!("Public/{addr}")
|
||||
}
|
||||
|
||||
fn make_private_account_input_from_str(addr: &str) -> String {
|
||||
format!("Private/{addr}")
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub async fn pre_test(
|
||||
home_dir: PathBuf,
|
||||
@ -86,7 +92,7 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)
|
||||
seq_http_server_handle.stop(true).await;
|
||||
|
||||
let wallet_home = wallet::helperfunctions::get_home().unwrap();
|
||||
let persistent_data_home = wallet_home.join("curr_accounts.json");
|
||||
let persistent_data_home = wallet_home.join("storage.json");
|
||||
|
||||
//Removing persistent accounts after run to not affect other executions
|
||||
//Not necessary an error, if fails as there is tests for failure scenario
|
||||
@ -157,3 +163,20 @@ async fn verify_commitment_is_in_state(
|
||||
Ok(Some(_))
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{make_private_account_input_from_str, make_public_account_input_from_str};
|
||||
|
||||
#[test]
|
||||
fn correct_addr_from_prefix() {
|
||||
let addr1 = "cafecafe";
|
||||
let addr2 = "deadbeaf";
|
||||
|
||||
let addr1_pub = make_public_account_input_from_str(addr1);
|
||||
let addr2_priv = make_private_account_input_from_str(addr2);
|
||||
|
||||
assert_eq!(addr1_pub, "Public/cafecafe".to_string());
|
||||
assert_eq!(addr2_priv, "Private/deadbeaf".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,8 @@ serde.workspace = true
|
||||
k256.workspace = true
|
||||
sha2.workspace = true
|
||||
rand.workspace = true
|
||||
hex.workspace = true
|
||||
base58.workspace = true
|
||||
hex = "0.4.3"
|
||||
aes-gcm.workspace = true
|
||||
bip39.workspace = true
|
||||
hmac-sha512.workspace = true
|
||||
|
||||
@ -55,6 +55,7 @@ impl KeyChain {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use aes_gcm::aead::OsRng;
|
||||
use base58::ToBase58;
|
||||
use k256::AffinePoint;
|
||||
use k256::elliptic_curve::group::GroupEncoding;
|
||||
use rand::RngCore;
|
||||
@ -119,7 +120,7 @@ mod tests {
|
||||
|
||||
println!("======Public data======");
|
||||
println!();
|
||||
println!("Address{:?}", hex::encode(address.value()));
|
||||
println!("Address{:?}", address.value().to_base58());
|
||||
println!(
|
||||
"Nulifier public key {:?}",
|
||||
hex::encode(nullifer_public_key.to_byte_array())
|
||||
|
||||
@ -142,5 +142,10 @@ mod tests {
|
||||
let is_key_chain_generated = user_data.get_private_account(&addr_private).is_some();
|
||||
|
||||
assert!(is_key_chain_generated);
|
||||
|
||||
let addr_private_str = addr_private.to_string();
|
||||
println!("{addr_private_str:#?}");
|
||||
let key_chain = &user_data.get_private_account(&addr_private).unwrap().0;
|
||||
println!("{key_chain:#?}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,8 +10,9 @@ thiserror = { version = "2.0.12", optional = true }
|
||||
bytemuck = { version = "1.13", optional = true }
|
||||
chacha20 = { version = "0.9", default-features = false }
|
||||
k256 = { version = "0.13.3", optional = true }
|
||||
hex = { version = "0.4.3", optional = true }
|
||||
base58 = { version = "0.2.0", optional = true }
|
||||
anyhow = { version = "1.0.98", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
host = ["thiserror", "bytemuck", "k256", "hex"]
|
||||
host = ["thiserror", "bytemuck", "k256", "base58", "anyhow"]
|
||||
|
||||
@ -3,6 +3,9 @@ use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "host")]
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
use base58::{FromBase58, ToBase58};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
any(feature = "host", test),
|
||||
@ -31,8 +34,8 @@ impl AsRef<[u8]> for Address {
|
||||
#[cfg(feature = "host")]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum AddressError {
|
||||
#[error("invalid hex")]
|
||||
InvalidHex(#[from] hex::FromHexError),
|
||||
#[error("invalid base58")]
|
||||
InvalidBase58(#[from] anyhow::Error),
|
||||
#[error("invalid length: expected 32 bytes, got {0}")]
|
||||
InvalidLength(usize),
|
||||
}
|
||||
@ -41,7 +44,9 @@ pub enum AddressError {
|
||||
impl FromStr for Address {
|
||||
type Err = AddressError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let bytes = hex::decode(s)?;
|
||||
let bytes = s
|
||||
.from_base58()
|
||||
.map_err(|err| anyhow::anyhow!("Invalid base58 err {err:?}"))?;
|
||||
if bytes.len() != 32 {
|
||||
return Err(AddressError::InvalidLength(bytes.len()));
|
||||
}
|
||||
@ -54,7 +59,7 @@ impl FromStr for Address {
|
||||
#[cfg(feature = "host")]
|
||||
impl Display for Address {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", hex::encode(self.value))
|
||||
write!(f, "{}", self.value.to_base58())
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,29 +70,29 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn parse_valid_address() {
|
||||
let hex_str = "00".repeat(32); // 64 hex chars = 32 bytes
|
||||
let addr: Address = hex_str.parse().unwrap();
|
||||
let base58_str = "11111111111111111111111111111111";
|
||||
let addr: Address = base58_str.parse().unwrap();
|
||||
assert_eq!(addr.value, [0u8; 32]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_invalid_hex() {
|
||||
let hex_str = "zz".repeat(32); // invalid hex chars
|
||||
let result = hex_str.parse::<Address>().unwrap_err();
|
||||
assert!(matches!(result, AddressError::InvalidHex(_)));
|
||||
fn parse_invalid_base58() {
|
||||
let base58_str = "00".repeat(32); // invalid base58 chars
|
||||
let result = base58_str.parse::<Address>().unwrap_err();
|
||||
assert!(matches!(result, AddressError::InvalidBase58(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_wrong_length_short() {
|
||||
let hex_str = "00".repeat(31); // 62 chars = 31 bytes
|
||||
let result = hex_str.parse::<Address>().unwrap_err();
|
||||
let base58_str = "11".repeat(31); // 62 chars = 31 bytes
|
||||
let result = base58_str.parse::<Address>().unwrap_err();
|
||||
assert!(matches!(result, AddressError::InvalidLength(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_wrong_length_long() {
|
||||
let hex_str = "00".repeat(33); // 66 chars = 33 bytes
|
||||
let result = hex_str.parse::<Address>().unwrap_err();
|
||||
let base58_str = "11".repeat(33); // 66 chars = 33 bytes
|
||||
let result = base58_str.parse::<Address>().unwrap_err();
|
||||
assert!(matches!(result, AddressError::InvalidLength(_)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
hex.workspace = true
|
||||
base58.workspace = true
|
||||
anyhow.workspace = true
|
||||
serde.workspace = true
|
||||
rand.workspace = true
|
||||
|
||||
@ -194,6 +194,7 @@ impl SequencerCore {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use base58::{FromBase58, ToBase58};
|
||||
use common::test_utils::sequencer_sign_key_for_testing;
|
||||
|
||||
use crate::config::AccountInitialData;
|
||||
@ -227,23 +228,23 @@ mod tests {
|
||||
}
|
||||
|
||||
fn setup_sequencer_config() -> SequencerConfig {
|
||||
let acc1_addr = vec![
|
||||
let acc1_addr: Vec<u8> = vec![
|
||||
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115,
|
||||
84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
|
||||
];
|
||||
|
||||
let acc2_addr = vec![
|
||||
let acc2_addr: Vec<u8> = vec![
|
||||
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141,
|
||||
98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
|
||||
];
|
||||
|
||||
let initial_acc1 = AccountInitialData {
|
||||
addr: hex::encode(acc1_addr),
|
||||
addr: acc1_addr.to_base58(),
|
||||
balance: 10000,
|
||||
};
|
||||
|
||||
let initial_acc2 = AccountInitialData {
|
||||
addr: hex::encode(acc2_addr),
|
||||
addr: acc2_addr.to_base58(),
|
||||
balance: 20000,
|
||||
};
|
||||
|
||||
@ -278,11 +279,17 @@ mod tests {
|
||||
assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10);
|
||||
assert_eq!(sequencer.sequencer_config.port, 8080);
|
||||
|
||||
let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone())
|
||||
let acc1_addr = config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone())
|
||||
let acc2_addr = config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@ -304,23 +311,23 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_start_different_intial_accounts_balances() {
|
||||
let acc1_addr = vec![
|
||||
let acc1_addr: Vec<u8> = vec![
|
||||
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24,
|
||||
52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
|
||||
];
|
||||
|
||||
let acc2_addr = vec![
|
||||
let acc2_addr: Vec<u8> = vec![
|
||||
77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234,
|
||||
216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
|
||||
];
|
||||
|
||||
let initial_acc1 = AccountInitialData {
|
||||
addr: hex::encode(acc1_addr),
|
||||
addr: acc1_addr.to_base58(),
|
||||
balance: 10000,
|
||||
};
|
||||
|
||||
let initial_acc2 = AccountInitialData {
|
||||
addr: hex::encode(acc2_addr),
|
||||
addr: acc2_addr.to_base58(),
|
||||
balance: 20000,
|
||||
};
|
||||
|
||||
@ -329,11 +336,17 @@ mod tests {
|
||||
let config = setup_sequencer_config_variable_initial_accounts(initial_accounts);
|
||||
let sequencer = SequencerCore::start_from_config(config.clone());
|
||||
|
||||
let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone())
|
||||
let acc1_addr = config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone())
|
||||
let acc2_addr = config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@ -376,11 +389,17 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
||||
let acc1 = sequencer.sequencer_config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
||||
let acc2 = sequencer.sequencer_config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@ -402,11 +421,17 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
||||
let acc1 = sequencer.sequencer_config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
||||
let acc2 = sequencer.sequencer_config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@ -438,11 +463,17 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
||||
let acc1 = sequencer.sequencer_config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
||||
let acc2 = sequencer.sequencer_config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@ -474,11 +505,17 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
||||
let acc1 = sequencer.sequencer_config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
||||
let acc2 = sequencer.sequencer_config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@ -566,11 +603,17 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
||||
let acc1 = sequencer.sequencer_config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
||||
let acc2 = sequencer.sequencer_config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
@ -608,11 +651,17 @@ mod tests {
|
||||
|
||||
common_setup(&mut sequencer);
|
||||
|
||||
let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone())
|
||||
let acc1 = sequencer.sequencer_config.initial_accounts[0]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone())
|
||||
let acc2 = sequencer.sequencer_config.initial_accounts[1]
|
||||
.addr
|
||||
.clone()
|
||||
.from_base58()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
@ -33,9 +33,11 @@ impl SequecerChainStore {
|
||||
|
||||
#[cfg(feature = "testnet")]
|
||||
let state = {
|
||||
use common::PINATA_BASE58;
|
||||
|
||||
let mut this =
|
||||
nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments);
|
||||
this.add_pinata_program("cafe".repeat(16).parse().unwrap());
|
||||
this.add_pinata_program(PINATA_BASE58.parse().unwrap());
|
||||
this
|
||||
};
|
||||
|
||||
|
||||
@ -10,7 +10,8 @@ log.workspace = true
|
||||
serde.workspace = true
|
||||
actix-cors.workspace = true
|
||||
futures.workspace = true
|
||||
hex.workspace = true
|
||||
base58.workspace = true
|
||||
hex = "0.4.3"
|
||||
tempfile.workspace = true
|
||||
base64.workspace = true
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix_web::Error as HttpError;
|
||||
use base58::FromBase58;
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use nssa::{self, program::Program};
|
||||
use sequencer_core::config::AccountInitialData;
|
||||
@ -163,8 +164,10 @@ impl JsonHandler {
|
||||
/// The address must be a valid hex string of the correct length.
|
||||
async fn process_get_account_balance(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?;
|
||||
let address_bytes = hex::decode(get_account_req.address)
|
||||
.map_err(|_| RpcError::invalid_params("invalid hex".to_string()))?;
|
||||
let address_bytes = get_account_req
|
||||
.address
|
||||
.from_base58()
|
||||
.map_err(|_| RpcError::invalid_params("invalid base58".to_string()))?;
|
||||
let address = nssa::Address::new(
|
||||
address_bytes
|
||||
.try_into()
|
||||
@ -312,6 +315,7 @@ mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{JsonHandler, rpc_handler};
|
||||
use base58::ToBase58;
|
||||
use base64::{Engine, engine::general_purpose};
|
||||
use common::{
|
||||
rpc_primitives::RpcPollingConfig, test_utils::sequencer_sign_key_for_testing,
|
||||
@ -329,23 +333,23 @@ mod tests {
|
||||
fn sequencer_config_for_tests() -> SequencerConfig {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let home = tempdir.path().to_path_buf();
|
||||
let acc1_addr = vec![
|
||||
let acc1_addr: Vec<u8> = vec![
|
||||
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115,
|
||||
84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
|
||||
];
|
||||
|
||||
let acc2_addr = vec![
|
||||
let acc2_addr: Vec<u8> = vec![
|
||||
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141,
|
||||
98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
|
||||
];
|
||||
|
||||
let initial_acc1 = AccountInitialData {
|
||||
addr: hex::encode(acc1_addr),
|
||||
addr: acc1_addr.to_base58(),
|
||||
balance: 10000,
|
||||
};
|
||||
|
||||
let initial_acc2 = AccountInitialData {
|
||||
addr: hex::encode(acc2_addr),
|
||||
addr: acc2_addr.to_base58(),
|
||||
balance: 20000,
|
||||
};
|
||||
|
||||
@ -430,7 +434,7 @@ mod tests {
|
||||
let request = serde_json::json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "get_account_balance",
|
||||
"params": { "address": "efac".repeat(16) },
|
||||
"params": { "address": "11".repeat(16) },
|
||||
"id": 1
|
||||
});
|
||||
let expected_response = serde_json::json!({
|
||||
@ -447,12 +451,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_get_account_balance_for_invalid_hex() {
|
||||
async fn test_get_account_balance_for_invalid_base58() {
|
||||
let (json_handler, _, _) = components_for_tests();
|
||||
let request = serde_json::json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "get_account_balance",
|
||||
"params": { "address": "not_a_valid_hex" },
|
||||
"params": { "address": "not_a_valid_base58" },
|
||||
"id": 1
|
||||
});
|
||||
let expected_response = serde_json::json!({
|
||||
@ -461,7 +465,7 @@ mod tests {
|
||||
"error": {
|
||||
"code": -32602,
|
||||
"message": "Invalid params",
|
||||
"data": "invalid hex"
|
||||
"data": "invalid base58"
|
||||
}
|
||||
});
|
||||
let response = call_rpc_handler_with_json(json_handler, request).await;
|
||||
@ -523,7 +527,7 @@ mod tests {
|
||||
let request = serde_json::json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "get_accounts_nonces",
|
||||
"params": { "addresses": ["efac".repeat(16)] },
|
||||
"params": { "addresses": ["11".repeat(16)] },
|
||||
"id": 1
|
||||
});
|
||||
let expected_response = serde_json::json!({
|
||||
@ -571,7 +575,7 @@ mod tests {
|
||||
let request = serde_json::json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "get_account",
|
||||
"params": { "address": "efac".repeat(16) },
|
||||
"params": { "address": "11".repeat(16) },
|
||||
"id": 1
|
||||
});
|
||||
let expected_response = serde_json::json!({
|
||||
|
||||
@ -8,49 +8,49 @@
|
||||
"port": 3040,
|
||||
"initial_accounts": [
|
||||
{
|
||||
"addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||
"addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
|
||||
"balance": 10000
|
||||
},
|
||||
{
|
||||
"addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||
"addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
|
||||
"balance": 20000
|
||||
}
|
||||
],
|
||||
"initial_commitments": [
|
||||
{
|
||||
"npk": [
|
||||
193,
|
||||
209,
|
||||
150,
|
||||
113,
|
||||
47,
|
||||
241,
|
||||
48,
|
||||
145,
|
||||
250,
|
||||
79,
|
||||
235,
|
||||
51,
|
||||
119,
|
||||
40,
|
||||
184,
|
||||
232,
|
||||
5,
|
||||
63,
|
||||
202,
|
||||
178,
|
||||
231,
|
||||
183,
|
||||
82,
|
||||
237,
|
||||
212,
|
||||
216,
|
||||
221,
|
||||
36,
|
||||
21,
|
||||
201,
|
||||
106,
|
||||
90,
|
||||
210,
|
||||
129,
|
||||
106,
|
||||
71,
|
||||
99,
|
||||
208,
|
||||
215,
|
||||
255,
|
||||
153,
|
||||
75,
|
||||
215
|
||||
101,
|
||||
177,
|
||||
161,
|
||||
254,
|
||||
210,
|
||||
128,
|
||||
122,
|
||||
54,
|
||||
190,
|
||||
230,
|
||||
151,
|
||||
183,
|
||||
64,
|
||||
225,
|
||||
229,
|
||||
113,
|
||||
1,
|
||||
228,
|
||||
97
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
@ -70,38 +70,38 @@
|
||||
},
|
||||
{
|
||||
"npk": [
|
||||
27,
|
||||
250,
|
||||
192,
|
||||
251,
|
||||
166,
|
||||
243,
|
||||
167,
|
||||
236,
|
||||
84,
|
||||
249,
|
||||
35,
|
||||
136,
|
||||
142,
|
||||
88,
|
||||
128,
|
||||
138,
|
||||
21,
|
||||
49,
|
||||
183,
|
||||
118,
|
||||
160,
|
||||
117,
|
||||
114,
|
||||
110,
|
||||
47,
|
||||
136,
|
||||
87,
|
||||
60,
|
||||
70,
|
||||
59,
|
||||
60,
|
||||
18,
|
||||
223,
|
||||
23,
|
||||
147,
|
||||
241,
|
||||
5,
|
||||
184,
|
||||
103,
|
||||
130,
|
||||
172,
|
||||
219,
|
||||
225,
|
||||
105
|
||||
161,
|
||||
139,
|
||||
229,
|
||||
89,
|
||||
243,
|
||||
125,
|
||||
194,
|
||||
213,
|
||||
209,
|
||||
30,
|
||||
23,
|
||||
174,
|
||||
100,
|
||||
244,
|
||||
124,
|
||||
74,
|
||||
140,
|
||||
47
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
@ -154,4 +154,4 @@
|
||||
37,
|
||||
37
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,8 @@ nssa-core = { path = "../nssa/core" }
|
||||
base64.workspace = true
|
||||
bytemuck = "1.23.2"
|
||||
borsh.workspace = true
|
||||
hex.workspace = true
|
||||
base58.workspace = true
|
||||
hex = "0.4.3"
|
||||
rand.workspace = true
|
||||
|
||||
[dependencies.key_protocol]
|
||||
|
||||
@ -75,19 +75,91 @@ mod tests {
|
||||
use tempfile::tempdir;
|
||||
|
||||
fn create_initial_accounts() -> Vec<InitialAccountData> {
|
||||
let initial_acc1 = serde_json::from_str(r#"{
|
||||
let initial_acc1 = serde_json::from_str(
|
||||
r#"{
|
||||
"Public": {
|
||||
"address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||
"pub_sign_key": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
"address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
|
||||
"pub_sign_key": [
|
||||
16,
|
||||
162,
|
||||
106,
|
||||
154,
|
||||
236,
|
||||
125,
|
||||
52,
|
||||
184,
|
||||
35,
|
||||
100,
|
||||
238,
|
||||
174,
|
||||
69,
|
||||
197,
|
||||
41,
|
||||
77,
|
||||
187,
|
||||
10,
|
||||
118,
|
||||
75,
|
||||
0,
|
||||
11,
|
||||
148,
|
||||
238,
|
||||
185,
|
||||
181,
|
||||
133,
|
||||
17,
|
||||
220,
|
||||
72,
|
||||
124,
|
||||
77
|
||||
]
|
||||
}
|
||||
}"#).unwrap();
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let initial_acc2 = serde_json::from_str(r#"{
|
||||
let initial_acc2 = serde_json::from_str(
|
||||
r#"{
|
||||
"Public": {
|
||||
"address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||
"pub_sign_key": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
|
||||
"address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
|
||||
"pub_sign_key": [
|
||||
113,
|
||||
121,
|
||||
64,
|
||||
177,
|
||||
204,
|
||||
85,
|
||||
229,
|
||||
214,
|
||||
178,
|
||||
6,
|
||||
109,
|
||||
191,
|
||||
29,
|
||||
154,
|
||||
63,
|
||||
38,
|
||||
242,
|
||||
18,
|
||||
244,
|
||||
219,
|
||||
8,
|
||||
208,
|
||||
35,
|
||||
136,
|
||||
23,
|
||||
127,
|
||||
207,
|
||||
237,
|
||||
216,
|
||||
169,
|
||||
190,
|
||||
27
|
||||
]
|
||||
}
|
||||
}"#).unwrap();
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let initial_accounts = vec![initial_acc1, initial_acc2];
|
||||
|
||||
|
||||
@ -1,213 +1,117 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use base58::ToBase58;
|
||||
use clap::Subcommand;
|
||||
use common::transaction::NSSATransaction;
|
||||
use nssa::Address;
|
||||
use nssa::{Account, Address, program::Program};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore, cli::WalletSubcommand, helperfunctions::HumanReadableAccount,
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix},
|
||||
parse_block_range,
|
||||
};
|
||||
|
||||
const TOKEN_DEFINITION_TYPE: u8 = 0;
|
||||
const TOKEN_DEFINITION_DATA_SIZE: usize = 23;
|
||||
|
||||
const TOKEN_HOLDING_TYPE: u8 = 1;
|
||||
const TOKEN_HOLDING_DATA_SIZE: usize = 49;
|
||||
|
||||
struct TokenDefinition {
|
||||
#[allow(unused)]
|
||||
account_type: u8,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
}
|
||||
|
||||
struct TokenHolding {
|
||||
#[allow(unused)]
|
||||
account_type: u8,
|
||||
definition_id: Address,
|
||||
balance: u128,
|
||||
}
|
||||
|
||||
impl TokenDefinition {
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE {
|
||||
None
|
||||
} else {
|
||||
let account_type = data[0];
|
||||
let name = data[1..7].try_into().unwrap();
|
||||
let total_supply = u128::from_le_bytes(data[7..].try_into().unwrap());
|
||||
|
||||
Some(Self {
|
||||
account_type,
|
||||
name,
|
||||
total_supply,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenHolding {
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE {
|
||||
None
|
||||
} else {
|
||||
let account_type = data[0];
|
||||
let definition_id = Address::new(data[1..33].try_into().unwrap());
|
||||
let balance = u128::from_le_bytes(data[33..].try_into().unwrap());
|
||||
Some(Self {
|
||||
definition_id,
|
||||
balance,
|
||||
account_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Represents generic chain CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum AccountSubcommand {
|
||||
///Get
|
||||
///Get account data
|
||||
Get {
|
||||
///Flag to get raw account data
|
||||
#[arg(short, long)]
|
||||
raw: bool,
|
||||
///Valid 32 byte base58 string with privacy prefix
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Produce new public or private account
|
||||
#[command(subcommand)]
|
||||
Get(GetSubcommand),
|
||||
///Fetch
|
||||
#[command(subcommand)]
|
||||
Fetch(FetchSubcommand),
|
||||
///Register
|
||||
#[command(subcommand)]
|
||||
Register(RegisterSubcommand),
|
||||
}
|
||||
|
||||
///Represents generic getter CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum GetSubcommand {
|
||||
///Get account `addr` balance
|
||||
PublicAccountBalance {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Get account `addr` nonce
|
||||
PublicAccountNonce {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Get account at address `addr`
|
||||
PublicAccount {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Get private account with `addr` from storage
|
||||
PrivateAccount {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
}
|
||||
|
||||
///Represents generic getter CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum FetchSubcommand {
|
||||
///Fetch transaction by `hash`
|
||||
Tx {
|
||||
#[arg(short, long)]
|
||||
tx_hash: String,
|
||||
},
|
||||
///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id`
|
||||
PrivateAccount {
|
||||
///tx_hash - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
tx_hash: String,
|
||||
///acc_addr - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
acc_addr: String,
|
||||
///output_id - id of the output in the transaction
|
||||
#[arg(long)]
|
||||
output_id: usize,
|
||||
},
|
||||
New(NewSubcommand),
|
||||
///Sync private accounts
|
||||
SyncPrivate {},
|
||||
}
|
||||
|
||||
///Represents generic register CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum RegisterSubcommand {
|
||||
pub enum NewSubcommand {
|
||||
///Register new public account
|
||||
Public {},
|
||||
///Register new private account
|
||||
Private {},
|
||||
}
|
||||
|
||||
impl WalletSubcommand for GetSubcommand {
|
||||
impl WalletSubcommand for NewSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
GetSubcommand::PublicAccountBalance { addr } => {
|
||||
let addr = Address::from_str(&addr)?;
|
||||
|
||||
let balance = wallet_core.get_account_balance(addr).await?;
|
||||
println!("Accounts {addr} balance is {balance}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
GetSubcommand::PublicAccountNonce { addr } => {
|
||||
let addr = Address::from_str(&addr)?;
|
||||
|
||||
let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0];
|
||||
println!("Accounts {addr} nonce is {nonce}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
GetSubcommand::PublicAccount { addr } => {
|
||||
let addr: Address = addr.parse()?;
|
||||
let account = wallet_core.get_account_public(addr).await?;
|
||||
let account_hr: HumanReadableAccount = account.clone().into();
|
||||
println!("{}", serde_json::to_string(&account_hr).unwrap());
|
||||
|
||||
Ok(SubcommandReturnValue::Account(account))
|
||||
}
|
||||
GetSubcommand::PrivateAccount { addr } => {
|
||||
let addr: Address = addr.parse()?;
|
||||
if let Some(account) = wallet_core.get_account_private(&addr) {
|
||||
println!("{}", serde_json::to_string(&account).unwrap());
|
||||
} else {
|
||||
println!("Private account not found.");
|
||||
}
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSubcommand for FetchSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
FetchSubcommand::Tx { tx_hash } => {
|
||||
let tx_obj = wallet_core
|
||||
.sequencer_client
|
||||
.get_transaction_by_hash(tx_hash)
|
||||
.await?;
|
||||
|
||||
println!("Transaction object {tx_obj:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
FetchSubcommand::PrivateAccount {
|
||||
tx_hash,
|
||||
acc_addr,
|
||||
output_id: ciph_id,
|
||||
} => {
|
||||
let acc_addr: Address = acc_addr.parse().unwrap();
|
||||
|
||||
let account_key_chain = wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.user_private_accounts
|
||||
.get(&acc_addr);
|
||||
|
||||
let Some((account_key_chain, _)) = account_key_chain else {
|
||||
anyhow::bail!("Account not found");
|
||||
};
|
||||
|
||||
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
let to_ebc = tx.message.encrypted_private_post_states[ciph_id].clone();
|
||||
let to_comm = tx.message.new_commitments[ciph_id].clone();
|
||||
let shared_secret =
|
||||
account_key_chain.calculate_shared_secret_receiver(to_ebc.epk);
|
||||
|
||||
let res_acc_to = nssa_core::EncryptionScheme::decrypt(
|
||||
&to_ebc.ciphertext,
|
||||
&shared_secret,
|
||||
&to_comm,
|
||||
ciph_id as u32,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("RES acc to {res_acc_to:#?}");
|
||||
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(acc_addr, res_acc_to);
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSubcommand for RegisterSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
RegisterSubcommand::Public {} => {
|
||||
NewSubcommand::Public {} => {
|
||||
let addr = wallet_core.create_new_account_public();
|
||||
|
||||
println!("Generated new account with addr {addr}");
|
||||
println!("Generated new account with addr Public/{addr}");
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
Ok(SubcommandReturnValue::RegisterAccount { addr })
|
||||
}
|
||||
RegisterSubcommand::Private {} => {
|
||||
NewSubcommand::Private {} => {
|
||||
let addr = wallet_core.create_new_account_private();
|
||||
|
||||
let (key, _) = wallet_core
|
||||
@ -216,14 +120,17 @@ impl WalletSubcommand for RegisterSubcommand {
|
||||
.get_private_account(&addr)
|
||||
.unwrap();
|
||||
|
||||
println!("Generated new account with addr {addr}");
|
||||
println!("With npk {}", hex::encode(&key.nullifer_public_key));
|
||||
println!(
|
||||
"Generated new account with addr Private/{}",
|
||||
addr.to_bytes().to_base58()
|
||||
);
|
||||
println!("With npk {}", hex::encode(key.nullifer_public_key.0));
|
||||
println!(
|
||||
"With ipk {}",
|
||||
hex::encode(key.incoming_viewing_public_key.to_bytes())
|
||||
);
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -233,20 +140,155 @@ impl WalletSubcommand for RegisterSubcommand {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct AuthenticatedTransferAccountView {
|
||||
pub balance: u128,
|
||||
}
|
||||
|
||||
impl From<nssa::Account> for AuthenticatedTransferAccountView {
|
||||
fn from(value: nssa::Account) -> Self {
|
||||
Self {
|
||||
balance: value.balance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TokedDefinitionAccountView {
|
||||
pub account_type: String,
|
||||
pub name: String,
|
||||
pub total_supply: u128,
|
||||
}
|
||||
|
||||
impl From<TokenDefinition> for TokedDefinitionAccountView {
|
||||
fn from(value: TokenDefinition) -> Self {
|
||||
Self {
|
||||
account_type: "Token definition".to_string(),
|
||||
name: hex::encode(value.name),
|
||||
total_supply: value.total_supply,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TokedHoldingAccountView {
|
||||
pub account_type: String,
|
||||
pub definition_id: String,
|
||||
pub balance: u128,
|
||||
}
|
||||
|
||||
impl From<TokenHolding> for TokedHoldingAccountView {
|
||||
fn from(value: TokenHolding) -> Self {
|
||||
Self {
|
||||
account_type: "Token holding".to_string(),
|
||||
definition_id: value.definition_id.to_string(),
|
||||
balance: value.balance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSubcommand for AccountSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
AccountSubcommand::Get(get_subcommand) => {
|
||||
get_subcommand.handle_subcommand(wallet_core).await
|
||||
AccountSubcommand::Get { raw, addr } => {
|
||||
let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?;
|
||||
|
||||
let addr = addr.parse()?;
|
||||
|
||||
let account = match addr_kind {
|
||||
AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?,
|
||||
AddressPrivacyKind::Private => wallet_core
|
||||
.get_account_private(&addr)
|
||||
.ok_or(anyhow::anyhow!("Private account not found in storage"))?,
|
||||
};
|
||||
|
||||
if account == Account::default() {
|
||||
println!("Account is Uninitialized");
|
||||
|
||||
return Ok(SubcommandReturnValue::Empty);
|
||||
}
|
||||
|
||||
if raw {
|
||||
let account_hr: HumanReadableAccount = account.clone().into();
|
||||
println!("{}", serde_json::to_string(&account_hr).unwrap());
|
||||
|
||||
return Ok(SubcommandReturnValue::Empty);
|
||||
}
|
||||
|
||||
let auth_tr_prog_id = Program::authenticated_transfer_program().id();
|
||||
let token_prog_id = Program::token().id();
|
||||
|
||||
let acc_view = match &account.program_owner {
|
||||
_ if account.program_owner == auth_tr_prog_id => {
|
||||
let acc_view: AuthenticatedTransferAccountView = account.into();
|
||||
|
||||
println!("Account owned by authenticated transfer program");
|
||||
|
||||
serde_json::to_string(&acc_view)?
|
||||
}
|
||||
_ if account.program_owner == token_prog_id => {
|
||||
if let Some(token_def) = TokenDefinition::parse(&account.data) {
|
||||
let acc_view: TokedDefinitionAccountView = token_def.into();
|
||||
|
||||
println!("Definition account owned by token program");
|
||||
|
||||
serde_json::to_string(&acc_view)?
|
||||
} else if let Some(token_hold) = TokenHolding::parse(&account.data) {
|
||||
let acc_view: TokedHoldingAccountView = token_hold.into();
|
||||
|
||||
println!("Holding account owned by token program");
|
||||
|
||||
serde_json::to_string(&acc_view)?
|
||||
} else {
|
||||
anyhow::bail!("Invalid data for account {addr:#?} with token program");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let account_hr: HumanReadableAccount = account.clone().into();
|
||||
serde_json::to_string(&account_hr).unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
println!("{}", acc_view);
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
AccountSubcommand::Fetch(fetch_subcommand) => {
|
||||
fetch_subcommand.handle_subcommand(wallet_core).await
|
||||
AccountSubcommand::New(new_subcommand) => {
|
||||
new_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
AccountSubcommand::Register(register_subcommand) => {
|
||||
register_subcommand.handle_subcommand(wallet_core).await
|
||||
AccountSubcommand::SyncPrivate {} => {
|
||||
let last_synced_block = wallet_core.last_synced_block;
|
||||
let curr_last_block = wallet_core
|
||||
.sequencer_client
|
||||
.get_last_block()
|
||||
.await?
|
||||
.last_block;
|
||||
|
||||
if !wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.user_private_accounts
|
||||
.is_empty()
|
||||
{
|
||||
parse_block_range(
|
||||
last_synced_block + 1,
|
||||
curr_last_block,
|
||||
wallet_core.sequencer_client.clone(),
|
||||
wallet_core,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
wallet_core.last_synced_block = curr_last_block;
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent data at {path:#?}");
|
||||
}
|
||||
|
||||
Ok(SubcommandReturnValue::SyncedToBlock(curr_last_block))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,12 +6,16 @@ use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||
///Represents generic chain CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum ChainSubcommand {
|
||||
GetLatestBlockId {},
|
||||
GetBlockAtId {
|
||||
///Get current block id from sequencer
|
||||
CurrentBlockId {},
|
||||
///Get block at id from sequencer
|
||||
Block {
|
||||
#[arg(short, long)]
|
||||
id: u64,
|
||||
},
|
||||
GetTransactionAtHash {
|
||||
///Get transaction at hash from sequencer
|
||||
Transaction {
|
||||
///hash - valid 32 byte hex string
|
||||
#[arg(short, long)]
|
||||
hash: String,
|
||||
},
|
||||
@ -23,17 +27,17 @@ impl WalletSubcommand for ChainSubcommand {
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
ChainSubcommand::GetLatestBlockId {} => {
|
||||
ChainSubcommand::CurrentBlockId {} => {
|
||||
let latest_block_res = wallet_core.sequencer_client.get_last_block().await?;
|
||||
|
||||
println!("Last block id is {}", latest_block_res.last_block);
|
||||
}
|
||||
ChainSubcommand::GetBlockAtId { id } => {
|
||||
ChainSubcommand::Block { id } => {
|
||||
let block_res = wallet_core.sequencer_client.get_block(id).await?;
|
||||
|
||||
println!("Last block id is {:#?}", block_res.block);
|
||||
}
|
||||
ChainSubcommand::GetTransactionAtHash { hash } => {
|
||||
ChainSubcommand::Transaction { hash } => {
|
||||
let tx_res = wallet_core
|
||||
.sequencer_client
|
||||
.get_transaction_by_hash(hash)
|
||||
|
||||
@ -3,7 +3,193 @@ use clap::Subcommand;
|
||||
use common::transaction::NSSATransaction;
|
||||
use nssa::Address;
|
||||
|
||||
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
};
|
||||
|
||||
///Represents generic CLI subcommand for a wallet working with native token transfer program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum AuthTransferSubcommand {
|
||||
///Initialize account under authenticated transfer program
|
||||
Init {
|
||||
///addr - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
addr: String,
|
||||
},
|
||||
///Send native tokens from one account to another with variable privacy
|
||||
///
|
||||
///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns.
|
||||
///
|
||||
///First is used for owned accounts, second otherwise.
|
||||
Send {
|
||||
///from - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
///to - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
to: Option<String>,
|
||||
///to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: Option<String>,
|
||||
///to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: Option<String>,
|
||||
///amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
}
|
||||
|
||||
impl WalletSubcommand for AuthTransferSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
AuthTransferSubcommand::Init { addr } => {
|
||||
let (addr, addr_privacy) = parse_addr_with_privacy_prefix(&addr)?;
|
||||
|
||||
match addr_privacy {
|
||||
AddressPrivacyKind::Public => {
|
||||
let addr = addr.parse()?;
|
||||
|
||||
let res = wallet_core
|
||||
.register_account_under_authenticated_transfers_programs(addr)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
|
||||
let transfer_tx =
|
||||
wallet_core.poll_native_token_transfer(res.tx_hash).await?;
|
||||
|
||||
println!("Transaction data is {transfer_tx:?}");
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
}
|
||||
AddressPrivacyKind::Private => {
|
||||
let addr = addr.parse()?;
|
||||
|
||||
let (res, [secret]) = wallet_core
|
||||
.register_account_under_authenticated_transfers_programs_private(addr)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
let transfer_tx = wallet_core
|
||||
.poll_native_token_transfer(tx_hash.clone())
|
||||
.await?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||
let acc_decode_data = vec![(secret, addr)];
|
||||
|
||||
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||
tx,
|
||||
&acc_decode_data,
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
AuthTransferSubcommand::Send {
|
||||
from,
|
||||
to,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
} => {
|
||||
let underlying_subcommand = match (to, to_npk, to_ipk) {
|
||||
(None, None, None) => {
|
||||
anyhow::bail!(
|
||||
"Provide either account address of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(Some(_), Some(_), Some(_)) => {
|
||||
anyhow::bail!(
|
||||
"Provide only one variant: either account address of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(_, Some(_), None) | (_, None, Some(_)) => {
|
||||
anyhow::bail!("List of public keys is uncomplete");
|
||||
}
|
||||
(Some(to), None, None) => {
|
||||
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
|
||||
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
|
||||
|
||||
match (from_privacy, to_privacy) {
|
||||
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
|
||||
NativeTokenTransferProgramSubcommand::Public { from, to, amount }
|
||||
}
|
||||
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
|
||||
NativeTokenTransferProgramSubcommand::Private(
|
||||
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned {
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
|
||||
NativeTokenTransferProgramSubcommand::Deshielded {
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
}
|
||||
}
|
||||
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
|
||||
NativeTokenTransferProgramSubcommand::Shielded(
|
||||
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned {
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, Some(to_npk), Some(to_ipk)) => {
|
||||
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
|
||||
|
||||
match from_privacy {
|
||||
AddressPrivacyKind::Private => {
|
||||
NativeTokenTransferProgramSubcommand::Private(
|
||||
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
AddressPrivacyKind::Public => {
|
||||
NativeTokenTransferProgramSubcommand::Shielded(
|
||||
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Represents generic CLI subcommand for a wallet working with native token transfer program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
@ -158,7 +344,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -202,7 +388,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -252,7 +438,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -285,7 +471,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
|
||||
|
||||
let tx_hash = res.tx_hash;
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -331,7 +517,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -351,7 +537,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
|
||||
|
||||
println!("Transaction data is {transfer_tx:?}");
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
|
||||
@ -1,9 +1,59 @@
|
||||
use anyhow::Result;
|
||||
use clap::Subcommand;
|
||||
use common::transaction::NSSATransaction;
|
||||
use common::{PINATA_BASE58, transaction::NSSATransaction};
|
||||
use log::info;
|
||||
|
||||
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
};
|
||||
|
||||
///Represents generic CLI subcommand for a wallet working with pinata program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum PinataProgramAgnosticSubcommand {
|
||||
///Claim pinata
|
||||
Claim {
|
||||
///to_addr - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
to_addr: String,
|
||||
///solution - solution to pinata challenge
|
||||
#[arg(long)]
|
||||
solution: u128,
|
||||
},
|
||||
}
|
||||
|
||||
impl WalletSubcommand for PinataProgramAgnosticSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
let underlying_subcommand = match self {
|
||||
PinataProgramAgnosticSubcommand::Claim { to_addr, solution } => {
|
||||
let (to_addr, to_addr_privacy) = parse_addr_with_privacy_prefix(&to_addr)?;
|
||||
|
||||
match to_addr_privacy {
|
||||
AddressPrivacyKind::Public => {
|
||||
PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim {
|
||||
pinata_addr: PINATA_BASE58.to_string(),
|
||||
winner_addr: to_addr,
|
||||
solution,
|
||||
})
|
||||
}
|
||||
AddressPrivacyKind::Private => PinataProgramSubcommand::Private(
|
||||
PinataProgramSubcommandPrivate::ClaimPrivateOwned {
|
||||
pinata_addr: PINATA_BASE58.to_string(),
|
||||
winner_addr: to_addr,
|
||||
solution,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
}
|
||||
|
||||
///Represents generic CLI subcommand for a wallet working with pinata program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
@ -131,7 +181,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
|
||||
@ -3,7 +3,197 @@ use clap::Subcommand;
|
||||
use common::transaction::NSSATransaction;
|
||||
use nssa::Address;
|
||||
|
||||
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix},
|
||||
};
|
||||
|
||||
///Represents generic CLI subcommand for a wallet working with token program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum TokenProgramAgnosticSubcommand {
|
||||
///Produce a new token
|
||||
///
|
||||
///Currently the only supported privacy options is for public definition
|
||||
New {
|
||||
///definition_addr - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
definition_addr: String,
|
||||
///supply_addr - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
supply_addr: String,
|
||||
#[arg(short, long)]
|
||||
name: String,
|
||||
#[arg(short, long)]
|
||||
total_supply: u128,
|
||||
},
|
||||
///Send tokens from one account to another with variable privacy
|
||||
///
|
||||
///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns.
|
||||
///
|
||||
///First is used for owned accounts, second otherwise.
|
||||
Send {
|
||||
///from - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
///to - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
to: Option<String>,
|
||||
///to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: Option<String>,
|
||||
///to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: Option<String>,
|
||||
///amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
}
|
||||
|
||||
impl WalletSubcommand for TokenProgramAgnosticSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
TokenProgramAgnosticSubcommand::New {
|
||||
definition_addr,
|
||||
supply_addr,
|
||||
name,
|
||||
total_supply,
|
||||
} => {
|
||||
let (definition_addr, definition_addr_privacy) =
|
||||
parse_addr_with_privacy_prefix(&definition_addr)?;
|
||||
let (supply_addr, supply_addr_privacy) =
|
||||
parse_addr_with_privacy_prefix(&supply_addr)?;
|
||||
|
||||
let underlying_subcommand = match (definition_addr_privacy, supply_addr_privacy) {
|
||||
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
|
||||
TokenProgramSubcommand::Public(
|
||||
TokenProgramSubcommandPublic::CreateNewToken {
|
||||
definition_addr,
|
||||
supply_addr,
|
||||
name,
|
||||
total_supply,
|
||||
},
|
||||
)
|
||||
}
|
||||
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
|
||||
TokenProgramSubcommand::Private(
|
||||
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
|
||||
definition_addr,
|
||||
supply_addr,
|
||||
name,
|
||||
total_supply,
|
||||
},
|
||||
)
|
||||
}
|
||||
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
|
||||
//ToDo: maybe implement this one. It is not immediately clear why definition should be private.
|
||||
anyhow::bail!("Unavailable privacy pairing")
|
||||
}
|
||||
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
|
||||
//ToDo: Probably valid. If definition is not public, but supply is it is very suspicious.
|
||||
anyhow::bail!("Unavailable privacy pairing")
|
||||
}
|
||||
};
|
||||
|
||||
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
TokenProgramAgnosticSubcommand::Send {
|
||||
from,
|
||||
to,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
} => {
|
||||
let underlying_subcommand = match (to, to_npk, to_ipk) {
|
||||
(None, None, None) => {
|
||||
anyhow::bail!(
|
||||
"Provide either account address of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(Some(_), Some(_), Some(_)) => {
|
||||
anyhow::bail!(
|
||||
"Provide only one variant: either account address of receiver or their public keys"
|
||||
);
|
||||
}
|
||||
(_, Some(_), None) | (_, None, Some(_)) => {
|
||||
anyhow::bail!("List of public keys is uncomplete");
|
||||
}
|
||||
(Some(to), None, None) => {
|
||||
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
|
||||
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
|
||||
|
||||
match (from_privacy, to_privacy) {
|
||||
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => {
|
||||
TokenProgramSubcommand::Public(
|
||||
TokenProgramSubcommandPublic::TransferToken {
|
||||
sender_addr: from,
|
||||
recipient_addr: to,
|
||||
balance_to_move: amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => {
|
||||
TokenProgramSubcommand::Private(
|
||||
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
|
||||
sender_addr: from,
|
||||
recipient_addr: to,
|
||||
balance_to_move: amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => {
|
||||
TokenProgramSubcommand::Deshielded(
|
||||
TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
|
||||
sender_addr: from,
|
||||
recipient_addr: to,
|
||||
balance_to_move: amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => {
|
||||
TokenProgramSubcommand::Shielded(
|
||||
TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
|
||||
sender_addr: from,
|
||||
recipient_addr: to,
|
||||
balance_to_move: amount,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, Some(to_npk), Some(to_ipk)) => {
|
||||
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
|
||||
|
||||
match from_privacy {
|
||||
AddressPrivacyKind::Private => TokenProgramSubcommand::Private(
|
||||
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
|
||||
sender_addr: from,
|
||||
recipient_npk: to_npk,
|
||||
recipient_ipk: to_ipk,
|
||||
balance_to_move: amount,
|
||||
},
|
||||
),
|
||||
AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded(
|
||||
TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
|
||||
sender_addr: from,
|
||||
recipient_npk: to_npk,
|
||||
recipient_ipk: to_ipk,
|
||||
balance_to_move: amount,
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
underlying_subcommand.handle_subcommand(wallet_core).await
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Represents generic CLI subcommand for a wallet working with token_program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
@ -221,7 +411,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -278,7 +468,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -328,7 +518,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -376,7 +566,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -431,7 +621,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
@ -485,7 +675,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
||||
)?;
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
let path = wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
|
||||
@ -46,6 +46,12 @@ pub enum PersistentAccountData {
|
||||
Private(PersistentAccountDataPrivate),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistentStorage {
|
||||
pub accounts: Vec<PersistentAccountData>,
|
||||
pub last_synced_block: u64,
|
||||
}
|
||||
|
||||
impl InitialAccountData {
|
||||
pub fn address(&self) -> nssa::Address {
|
||||
match &self {
|
||||
|
||||
@ -12,8 +12,7 @@ use serde::Serialize;
|
||||
use crate::{
|
||||
HOME_DIR_ENV_VAR,
|
||||
config::{
|
||||
PersistentAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic,
|
||||
WalletConfig,
|
||||
PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage, WalletConfig,
|
||||
},
|
||||
};
|
||||
|
||||
@ -30,21 +29,24 @@ pub async fn fetch_config() -> Result<WalletConfig> {
|
||||
Ok(serde_json::from_slice(&config_contents)?)
|
||||
}
|
||||
|
||||
/// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json`
|
||||
/// Fetch data stored at `NSSA_WALLET_HOME_DIR/storage.json`
|
||||
///
|
||||
/// If file not present, it is considered as empty list of persistent accounts
|
||||
pub async fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
||||
pub async fn fetch_persistent_storage() -> Result<PersistentStorage> {
|
||||
let home = get_home()?;
|
||||
let accs_path = home.join("curr_accounts.json");
|
||||
let mut persistent_accounts_content = vec![];
|
||||
let accs_path = home.join("storage.json");
|
||||
let mut storage_content = vec![];
|
||||
|
||||
match tokio::fs::File::open(accs_path).await {
|
||||
Ok(mut file) => {
|
||||
file.read_to_end(&mut persistent_accounts_content).await?;
|
||||
Ok(serde_json::from_slice(&persistent_accounts_content)?)
|
||||
file.read_to_end(&mut storage_content).await?;
|
||||
Ok(serde_json::from_slice(&storage_content)?)
|
||||
}
|
||||
Err(err) => match err.kind() {
|
||||
std::io::ErrorKind::NotFound => Ok(vec![]),
|
||||
std::io::ErrorKind::NotFound => Ok(PersistentStorage {
|
||||
accounts: vec![],
|
||||
last_synced_block: 0,
|
||||
}),
|
||||
_ => {
|
||||
anyhow::bail!("IO error {err:#?}");
|
||||
}
|
||||
@ -52,8 +54,11 @@ pub async fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Produces a list of accounts for storage
|
||||
pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccountData> {
|
||||
/// Produces data for storage
|
||||
pub fn produce_data_for_storage(
|
||||
user_data: &NSSAUserData,
|
||||
last_synced_block: u64,
|
||||
) -> PersistentStorage {
|
||||
let mut vec_for_storage = vec![];
|
||||
|
||||
for (addr, key) in &user_data.pub_account_signing_keys {
|
||||
@ -77,7 +82,10 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccou
|
||||
);
|
||||
}
|
||||
|
||||
vec_for_storage
|
||||
PersistentStorage {
|
||||
accounts: vec_for_storage,
|
||||
last_synced_block,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn produce_random_nonces(size: usize) -> Vec<Nonce> {
|
||||
@ -86,6 +94,30 @@ pub(crate) fn produce_random_nonces(size: usize) -> Vec<Nonce> {
|
||||
result.into_iter().map(Nonce::from_le_bytes).collect()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AddressPrivacyKind {
|
||||
Public,
|
||||
Private,
|
||||
}
|
||||
|
||||
pub(crate) fn parse_addr_with_privacy_prefix(
|
||||
addr_base58: &str,
|
||||
) -> Result<(String, AddressPrivacyKind)> {
|
||||
if addr_base58.starts_with("Public/") {
|
||||
Ok((
|
||||
addr_base58.strip_prefix("Public/").unwrap().to_string(),
|
||||
AddressPrivacyKind::Public,
|
||||
))
|
||||
} else if addr_base58.starts_with("Private/") {
|
||||
Ok((
|
||||
addr_base58.strip_prefix("Private/").unwrap().to_string(),
|
||||
AddressPrivacyKind::Private,
|
||||
))
|
||||
} else {
|
||||
anyhow::bail!("Unsupported privacy kind, available variants is Public/ and Private/");
|
||||
}
|
||||
}
|
||||
|
||||
/// Human-readable representation of an account.
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct HumanReadableAccount {
|
||||
@ -126,4 +158,20 @@ mod tests {
|
||||
std::env::remove_var(HOME_DIR_ENV_VAR);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_addr_parse_with_privacy() {
|
||||
let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
|
||||
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap();
|
||||
|
||||
assert_eq!(addr_kind, AddressPrivacyKind::Public);
|
||||
|
||||
let addr_base58 = "Private/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
|
||||
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap();
|
||||
|
||||
assert_eq!(addr_kind, AddressPrivacyKind::Private);
|
||||
|
||||
let addr_base58 = "asdsada/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
|
||||
assert!(parse_addr_with_privacy_prefix(addr_base58).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,16 +20,18 @@ use clap::{Parser, Subcommand};
|
||||
use nssa_core::{Commitment, MembershipProof};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::cli::{
|
||||
WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand,
|
||||
native_token_transfer_program::NativeTokenTransferProgramSubcommand,
|
||||
pinata_program::PinataProgramSubcommand,
|
||||
use crate::{
|
||||
cli::{
|
||||
WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand,
|
||||
native_token_transfer_program::AuthTransferSubcommand,
|
||||
pinata_program::PinataProgramAgnosticSubcommand,
|
||||
token_program::TokenProgramAgnosticSubcommand,
|
||||
},
|
||||
config::PersistentStorage,
|
||||
helperfunctions::fetch_persistent_storage,
|
||||
};
|
||||
use crate::{
|
||||
cli::token_program::TokenProgramSubcommand,
|
||||
helperfunctions::{
|
||||
fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage,
|
||||
},
|
||||
helperfunctions::{fetch_config, get_home, produce_data_for_storage},
|
||||
poller::TxPoller,
|
||||
};
|
||||
|
||||
@ -49,6 +51,7 @@ pub struct WalletCore {
|
||||
pub storage: WalletChainStore,
|
||||
pub poller: TxPoller,
|
||||
pub sequencer_client: Arc<SequencerClient>,
|
||||
pub last_synced_block: u64,
|
||||
}
|
||||
|
||||
impl WalletCore {
|
||||
@ -58,7 +61,10 @@ impl WalletCore {
|
||||
|
||||
let mut storage = WalletChainStore::new(config)?;
|
||||
|
||||
let persistent_accounts = fetch_persistent_accounts().await?;
|
||||
let PersistentStorage {
|
||||
accounts: persistent_accounts,
|
||||
last_synced_block,
|
||||
} = fetch_persistent_storage().await?;
|
||||
for pers_acc_data in persistent_accounts {
|
||||
storage.insert_account_data(pers_acc_data);
|
||||
}
|
||||
@ -67,23 +73,24 @@ impl WalletCore {
|
||||
storage,
|
||||
poller: tx_poller,
|
||||
sequencer_client: client.clone(),
|
||||
last_synced_block,
|
||||
})
|
||||
}
|
||||
|
||||
///Store persistent accounts at home
|
||||
pub async fn store_persistent_accounts(&self) -> Result<PathBuf> {
|
||||
///Store persistent data at home
|
||||
pub async fn store_persistent_data(&self) -> Result<PathBuf> {
|
||||
let home = get_home()?;
|
||||
let accs_path = home.join("curr_accounts.json");
|
||||
let storage_path = home.join("storage.json");
|
||||
|
||||
let data = produce_data_for_storage(&self.storage.user_data);
|
||||
let accs = serde_json::to_vec_pretty(&data)?;
|
||||
let data = produce_data_for_storage(&self.storage.user_data, self.last_synced_block);
|
||||
let storage = serde_json::to_vec_pretty(&data)?;
|
||||
|
||||
let mut accs_file = tokio::fs::File::create(accs_path.as_path()).await?;
|
||||
accs_file.write_all(&accs).await?;
|
||||
let mut storage_file = tokio::fs::File::create(storage_path.as_path()).await?;
|
||||
storage_file.write_all(&storage).await?;
|
||||
|
||||
info!("Stored accounts data at {accs_path:#?}");
|
||||
info!("Stored data at {storage_path:#?}");
|
||||
|
||||
Ok(accs_path)
|
||||
Ok(storage_path)
|
||||
}
|
||||
|
||||
pub fn create_new_account_public(&mut self) -> Address {
|
||||
@ -191,28 +198,32 @@ impl WalletCore {
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
#[clap(about)]
|
||||
pub enum Command {
|
||||
///Transfer command
|
||||
///Authenticated transfer subcommand
|
||||
#[command(subcommand)]
|
||||
Transfer(NativeTokenTransferProgramSubcommand),
|
||||
///Chain command
|
||||
AuthTransfer(AuthTransferSubcommand),
|
||||
///Generic chain info subcommand
|
||||
#[command(subcommand)]
|
||||
Chain(ChainSubcommand),
|
||||
///Chain command
|
||||
ChainInfo(ChainSubcommand),
|
||||
///Account view and sync subcommand
|
||||
#[command(subcommand)]
|
||||
Account(AccountSubcommand),
|
||||
///Pinata command
|
||||
///Pinata program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
PinataProgram(PinataProgramSubcommand),
|
||||
///Token command
|
||||
Pinata(PinataProgramAgnosticSubcommand),
|
||||
///Token program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
TokenProgram(TokenProgramSubcommand),
|
||||
AuthenticatedTransferInitializePublicAccount {},
|
||||
// Check the wallet can connect to the node and builtin local programs
|
||||
// match the remote versions
|
||||
Token(TokenProgramAgnosticSubcommand),
|
||||
/// Check the wallet can connect to the node and builtin local programs
|
||||
/// match the remote versions
|
||||
CheckHealth {},
|
||||
}
|
||||
|
||||
///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
|
||||
///
|
||||
/// All account adresses must be valid 32 byte base58 strings.
|
||||
///
|
||||
/// All account addresses must be provided as {privacy_prefix}/{addr},
|
||||
/// where valid options for `privacy_prefix` is `Public` and `Private`
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(version, about)]
|
||||
pub struct Args {
|
||||
@ -230,6 +241,7 @@ pub enum SubcommandReturnValue {
|
||||
RegisterAccount { addr: nssa::Address },
|
||||
Account(nssa::Account),
|
||||
Empty,
|
||||
SyncedToBlock(u64),
|
||||
}
|
||||
|
||||
pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> {
|
||||
@ -237,12 +249,12 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
|
||||
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config).await?;
|
||||
|
||||
let subcommand_ret = match command {
|
||||
Command::Transfer(transfer_subcommand) => {
|
||||
Command::AuthTransfer(transfer_subcommand) => {
|
||||
transfer_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::Chain(chain_subcommand) => {
|
||||
Command::ChainInfo(chain_subcommand) => {
|
||||
chain_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||
}
|
||||
Command::Account(account_subcommand) => {
|
||||
@ -250,7 +262,7 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
}
|
||||
Command::PinataProgram(pinata_subcommand) => {
|
||||
Command::Pinata(pinata_subcommand) => {
|
||||
pinata_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
.await?
|
||||
@ -285,26 +297,7 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::AuthenticatedTransferInitializePublicAccount {} => {
|
||||
let addr = wallet_core.create_new_account_public();
|
||||
|
||||
println!("Generated new account with addr {addr}");
|
||||
|
||||
let path = wallet_core.store_persistent_accounts().await?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
let res = wallet_core
|
||||
.register_account_under_authenticated_transfers_programs(addr)
|
||||
.await?;
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
|
||||
let _transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?;
|
||||
|
||||
SubcommandReturnValue::RegisterAccount { addr }
|
||||
}
|
||||
Command::TokenProgram(token_subcommand) => {
|
||||
Command::Token(token_subcommand) => {
|
||||
token_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||
}
|
||||
};
|
||||
@ -312,6 +305,80 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
|
||||
Ok(subcommand_ret)
|
||||
}
|
||||
|
||||
pub async fn parse_block_range(
|
||||
start: u64,
|
||||
stop: u64,
|
||||
seq_client: Arc<SequencerClient>,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<()> {
|
||||
for block_id in start..(stop + 1) {
|
||||
let block =
|
||||
borsh::from_slice::<HashableBlockData>(&seq_client.get_block(block_id).await?.block)?;
|
||||
|
||||
for tx in block.transactions {
|
||||
let nssa_tx = NSSATransaction::try_from(&tx)?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
|
||||
let mut affected_accounts = vec![];
|
||||
|
||||
for (acc_addr, (key_chain, _)) in
|
||||
&wallet_core.storage.user_data.user_private_accounts
|
||||
{
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
key_chain.incoming_viewing_public_key.clone(),
|
||||
);
|
||||
|
||||
for (ciph_id, encrypted_data) in tx
|
||||
.message()
|
||||
.encrypted_private_post_states
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if encrypted_data.view_tag == view_tag {
|
||||
let ciphertext = &encrypted_data.ciphertext;
|
||||
let commitment = &tx.message.new_commitments[ciph_id];
|
||||
let shared_secret = key_chain
|
||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||
|
||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||
ciphertext,
|
||||
&shared_secret,
|
||||
commitment,
|
||||
ciph_id as u32,
|
||||
);
|
||||
|
||||
if let Some(res_acc) = res_acc {
|
||||
println!(
|
||||
"Received new account for addr {acc_addr:#?} with account object {res_acc:#?}"
|
||||
);
|
||||
|
||||
affected_accounts.push((*acc_addr, res_acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (affected_addr, new_acc) in affected_accounts {
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(affected_addr, new_acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wallet_core.last_synced_block = block_id;
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
println!(
|
||||
"Block at id {block_id} with timestamp {} parsed",
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn execute_continious_run() -> Result<()> {
|
||||
let config = fetch_config().await?;
|
||||
let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
||||
@ -321,70 +388,13 @@ pub async fn execute_continious_run() -> Result<()> {
|
||||
let mut curr_last_block = latest_block_num;
|
||||
|
||||
loop {
|
||||
for block_id in curr_last_block..(latest_block_num + 1) {
|
||||
let block = borsh::from_slice::<HashableBlockData>(
|
||||
&seq_client.get_block(block_id).await?.block,
|
||||
)?;
|
||||
|
||||
for tx in block.transactions {
|
||||
let nssa_tx = NSSATransaction::try_from(&tx)?;
|
||||
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
|
||||
let mut affected_accounts = vec![];
|
||||
|
||||
for (acc_addr, (key_chain, _)) in
|
||||
&wallet_core.storage.user_data.user_private_accounts
|
||||
{
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
key_chain.incoming_viewing_public_key.clone(),
|
||||
);
|
||||
|
||||
for (ciph_id, encrypted_data) in tx
|
||||
.message()
|
||||
.encrypted_private_post_states
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if encrypted_data.view_tag == view_tag {
|
||||
let ciphertext = &encrypted_data.ciphertext;
|
||||
let commitment = &tx.message.new_commitments[ciph_id];
|
||||
let shared_secret = key_chain
|
||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||
|
||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||
ciphertext,
|
||||
&shared_secret,
|
||||
commitment,
|
||||
ciph_id as u32,
|
||||
);
|
||||
|
||||
if let Some(res_acc) = res_acc {
|
||||
println!(
|
||||
"Received new account for addr {acc_addr:#?} with account object {res_acc:#?}"
|
||||
);
|
||||
|
||||
affected_accounts.push((*acc_addr, res_acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (affected_addr, new_acc) in affected_accounts {
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(affected_addr, new_acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wallet_core.store_persistent_accounts().await?;
|
||||
|
||||
println!(
|
||||
"Block at id {block_id} with timestamp {} parsed",
|
||||
block.timestamp
|
||||
);
|
||||
}
|
||||
parse_block_range(
|
||||
curr_last_block,
|
||||
latest_block_num,
|
||||
seq_client.clone(),
|
||||
&mut wallet_core,
|
||||
)
|
||||
.await?;
|
||||
|
||||
curr_last_block = latest_block_num + 1;
|
||||
|
||||
|
||||
@ -537,4 +537,53 @@ impl WalletCore {
|
||||
|
||||
Ok(self.sequencer_client.send_tx_private(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn register_account_under_authenticated_transfers_programs_private(
|
||||
&self,
|
||||
from: Address,
|
||||
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
|
||||
let AccountPreparedData {
|
||||
nsk: _,
|
||||
npk: from_npk,
|
||||
ipk: from_ipk,
|
||||
auth_acc: sender_pre,
|
||||
proof: _,
|
||||
} = self.private_acc_preparation(from, false, false).await?;
|
||||
|
||||
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
|
||||
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
|
||||
|
||||
let instruction: u128 = 0;
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre],
|
||||
&Program::serialize_instruction(instruction).unwrap(),
|
||||
&[2],
|
||||
&produce_random_nonces(1),
|
||||
&[(from_npk.clone(), shared_secret_from.clone())],
|
||||
&[],
|
||||
&Program::authenticated_transfer_program(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message = Message::try_from_circuit_output(
|
||||
vec![],
|
||||
vec![],
|
||||
vec![(
|
||||
from_npk.clone(),
|
||||
from_ipk.clone(),
|
||||
eph_holder_from.generate_ephemeral_public_key(),
|
||||
)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
[shared_secret_from],
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user