mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
Merge branch 'main' into schouhy/add-token-program
This commit is contained in:
commit
36beca9c7c
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -33,4 +33,4 @@ jobs:
|
||||
run: chmod 777 ./ci_scripts/lint-ubuntu.sh && ./ci_scripts/lint-ubuntu.sh
|
||||
- name: test ubuntu-latest
|
||||
if: success() || failure()
|
||||
run: chmod 777 ./ci_scripts/test-ubuntu.sh && ./ci_scripts/test-ubuntu.sh
|
||||
run: chmod 777 ./ci_scripts/test-ubuntu.sh && ./ci_scripts/test-ubuntu.sh
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,4 +6,4 @@ data/
|
||||
.idea/
|
||||
.vscode/
|
||||
rocksdb
|
||||
Cargo.lock
|
||||
Cargo.lock
|
||||
@ -41,9 +41,9 @@ ark-bn254 = "0.5.0"
|
||||
ark-ff = "0.5.0"
|
||||
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
||||
base64 = "0.22.1"
|
||||
chrono = "0.4.41"
|
||||
bip39 = "2.2.0"
|
||||
hmac-sha512 = "1.1.7"
|
||||
chrono = "0.4.41"
|
||||
|
||||
rocksdb = { version = "0.21.0", default-features = false, features = [
|
||||
"snappy",
|
||||
|
||||
@ -6,5 +6,4 @@ cargo install taplo-cli --locked
|
||||
cargo fmt -- --check
|
||||
taplo fmt --check
|
||||
|
||||
export RISC0_SKIP_BUILD=1
|
||||
cargo clippy --workspace --all-targets -- -D warnings
|
||||
RISC0_SKIP_BUILD=1 cargo clippy --workspace --all-targets -- -D warnings
|
||||
|
||||
@ -10,6 +10,10 @@ cd integration_tests
|
||||
export NSSA_WALLET_HOME_DIR=$(pwd)/configs/debug/wallet/
|
||||
export RUST_LOG=info
|
||||
cargo run $(pwd)/configs/debug all
|
||||
echo "Try test valid proof at least once"
|
||||
cargo run $(pwd)/configs/debug test_success_private_transfer_to_another_owned_account
|
||||
echo "Continuing in dev mode"
|
||||
RISC0_DEV_MODE=1 cargo run $(pwd)/configs/debug all
|
||||
cd ..
|
||||
|
||||
cd nssa/program_methods/guest && cargo test --release
|
||||
|
||||
@ -16,6 +16,7 @@ sha2.workspace = true
|
||||
log.workspace = true
|
||||
elliptic-curve.workspace = true
|
||||
hex.workspace = true
|
||||
nssa-core = { path = "../nssa/core", features = ["host"] }
|
||||
|
||||
[dependencies.secp256k1-zkp]
|
||||
workspace = true
|
||||
|
||||
@ -53,6 +53,11 @@ pub struct GetAccountRequest {
|
||||
pub address: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GetProofByCommitmentRequest {
|
||||
pub commitment: nssa_core::Commitment,
|
||||
}
|
||||
|
||||
parse_request!(HelloRequest);
|
||||
parse_request!(RegisterAccountRequest);
|
||||
parse_request!(SendTxRequest);
|
||||
@ -63,6 +68,7 @@ parse_request!(GetInitialTestnetAccountsRequest);
|
||||
parse_request!(GetAccountBalanceRequest);
|
||||
parse_request!(GetTransactionByHashRequest);
|
||||
parse_request!(GetAccountsNoncesRequest);
|
||||
parse_request!(GetProofByCommitmentRequest);
|
||||
parse_request!(GetAccountRequest);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@ -115,3 +121,8 @@ pub struct GetTransactionByHashResponse {
|
||||
pub struct GetAccountResponse {
|
||||
pub account: nssa::Account,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GetProofByCommitmentResponse {
|
||||
pub membership_proof: Option<nssa_core::MembershipProof>,
|
||||
}
|
||||
|
||||
@ -9,7 +9,8 @@ use serde_json::Value;
|
||||
|
||||
use crate::rpc_primitives::requests::{
|
||||
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
|
||||
GetTransactionByHashRequest, GetTransactionByHashResponse,
|
||||
GetProofByCommitmentRequest, GetProofByCommitmentResponse, GetTransactionByHashRequest,
|
||||
GetTransactionByHashResponse,
|
||||
};
|
||||
use crate::sequencer_client::json::AccountInitialData;
|
||||
use crate::transaction::{EncodedTransaction, NSSATransaction};
|
||||
@ -162,6 +163,26 @@ impl SequencerClient {
|
||||
Ok(resp_deser)
|
||||
}
|
||||
|
||||
///Send transaction to sequencer
|
||||
pub async fn send_tx_private(
|
||||
&self,
|
||||
transaction: nssa::PrivacyPreservingTransaction,
|
||||
) -> Result<SendTxResponse, SequencerClientError> {
|
||||
let transaction = EncodedTransaction::from(NSSATransaction::PrivacyPreserving(transaction));
|
||||
|
||||
let tx_req = SendTxRequest {
|
||||
transaction: transaction.to_bytes(),
|
||||
};
|
||||
|
||||
let req = serde_json::to_value(tx_req)?;
|
||||
|
||||
let resp = self.call_method_with_payload("send_tx", req).await?;
|
||||
|
||||
let resp_deser = serde_json::from_value(resp)?;
|
||||
|
||||
Ok(resp_deser)
|
||||
}
|
||||
|
||||
///Get genesis id from sequencer
|
||||
pub async fn get_genesis_id(&self) -> Result<GetGenesisIdResponse, SequencerClientError> {
|
||||
let genesis_req = GetGenesisIdRequest {};
|
||||
@ -195,4 +216,25 @@ impl SequencerClient {
|
||||
|
||||
Ok(resp_deser)
|
||||
}
|
||||
|
||||
///Get proof for commitment
|
||||
pub async fn get_proof_for_commitment(
|
||||
&self,
|
||||
commitment: nssa_core::Commitment,
|
||||
) -> Result<Option<nssa_core::MembershipProof>, SequencerClientError> {
|
||||
let acc_req = GetProofByCommitmentRequest { commitment };
|
||||
|
||||
let req = serde_json::to_value(acc_req).unwrap();
|
||||
|
||||
let resp = self
|
||||
.call_method_with_payload("get_proof_for_commitment", req)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let resp_deser = serde_json::from_value::<GetProofByCommitmentResponse>(resp)
|
||||
.unwrap()
|
||||
.membership_proof;
|
||||
|
||||
Ok(resp_deser)
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,8 @@ tokio.workspace = true
|
||||
hex.workspace = true
|
||||
tempfile.workspace = true
|
||||
|
||||
nssa-core = { path = "../nssa/core", features = ["host"] }
|
||||
|
||||
[dependencies.clap]
|
||||
features = ["derive", "env"]
|
||||
workspace = true
|
||||
|
||||
@ -16,6 +16,142 @@
|
||||
"balance": 20000
|
||||
}
|
||||
],
|
||||
"signing_key": [37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
|
||||
37, 37, 37, 37, 37, 37]
|
||||
}
|
||||
"initial_commitments": [
|
||||
{
|
||||
"npk": [
|
||||
193,
|
||||
209,
|
||||
150,
|
||||
113,
|
||||
47,
|
||||
241,
|
||||
48,
|
||||
145,
|
||||
250,
|
||||
79,
|
||||
235,
|
||||
51,
|
||||
119,
|
||||
40,
|
||||
184,
|
||||
232,
|
||||
5,
|
||||
221,
|
||||
36,
|
||||
21,
|
||||
201,
|
||||
106,
|
||||
90,
|
||||
210,
|
||||
129,
|
||||
106,
|
||||
71,
|
||||
99,
|
||||
208,
|
||||
153,
|
||||
75,
|
||||
215
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"balance": 10000,
|
||||
"data": [],
|
||||
"nonce": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"npk": [
|
||||
27,
|
||||
250,
|
||||
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,
|
||||
225,
|
||||
105
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"balance": 20000,
|
||||
"data": [],
|
||||
"nonce": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"signing_key": [
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
37
|
||||
]
|
||||
}
|
||||
@ -8,109 +8,540 @@
|
||||
"seq_poll_retry_delay_millis": 500,
|
||||
"initial_accounts": [
|
||||
{
|
||||
"address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||
"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
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"balance": 10000,
|
||||
"nonce": 0,
|
||||
"data": []
|
||||
"Public": {
|
||||
"address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||
"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": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||
"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
|
||||
],
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"balance": 20000,
|
||||
"nonce": 0,
|
||||
"data": []
|
||||
"Public": {
|
||||
"address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||
"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
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Private": {
|
||||
"address": "6ffe0893c4b2c956fdb769b11fe4e3b2dd36ac4bd0ad90c810844051747c8c04",
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"balance": 10000,
|
||||
"data": [],
|
||||
"nonce": 0
|
||||
},
|
||||
"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,
|
||||
82,
|
||||
53,
|
||||
116,
|
||||
22,
|
||||
62,
|
||||
79,
|
||||
61,
|
||||
76,
|
||||
71,
|
||||
79
|
||||
],
|
||||
"private_key_holder": {
|
||||
"nullifier_secret_key": [
|
||||
228,
|
||||
136,
|
||||
4,
|
||||
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
|
||||
],
|
||||
"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,
|
||||
217,
|
||||
109,
|
||||
220,
|
||||
112,
|
||||
103,
|
||||
253,
|
||||
110,
|
||||
98,
|
||||
6
|
||||
],
|
||||
"outgoing_viewing_secret_key": [
|
||||
147,
|
||||
34,
|
||||
193,
|
||||
29,
|
||||
39,
|
||||
173,
|
||||
222,
|
||||
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
|
||||
]
|
||||
},
|
||||
"nullifer_public_key": [
|
||||
193,
|
||||
209,
|
||||
150,
|
||||
113,
|
||||
47,
|
||||
241,
|
||||
48,
|
||||
145,
|
||||
250,
|
||||
79,
|
||||
235,
|
||||
51,
|
||||
119,
|
||||
40,
|
||||
184,
|
||||
232,
|
||||
5,
|
||||
221,
|
||||
36,
|
||||
21,
|
||||
201,
|
||||
106,
|
||||
90,
|
||||
210,
|
||||
129,
|
||||
106,
|
||||
71,
|
||||
99,
|
||||
208,
|
||||
153,
|
||||
75,
|
||||
215
|
||||
],
|
||||
"incoming_viewing_public_key": [
|
||||
3,
|
||||
78,
|
||||
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,
|
||||
189,
|
||||
31,
|
||||
95
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Private": {
|
||||
"address": "4ee9de60e33da96fd72929f1485fb365bcc9c1634dd44e4ba55b1ab96692674b",
|
||||
"account": {
|
||||
"program_owner": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"balance": 20000,
|
||||
"data": [],
|
||||
"nonce": 0
|
||||
},
|
||||
"key_chain": {
|
||||
"secret_spending_key": [
|
||||
153,
|
||||
109,
|
||||
202,
|
||||
226,
|
||||
97,
|
||||
212,
|
||||
77,
|
||||
147,
|
||||
75,
|
||||
107,
|
||||
153,
|
||||
106,
|
||||
89,
|
||||
167,
|
||||
49,
|
||||
230,
|
||||
122,
|
||||
78,
|
||||
167,
|
||||
146,
|
||||
14,
|
||||
180,
|
||||
206,
|
||||
107,
|
||||
96,
|
||||
193,
|
||||
255,
|
||||
122,
|
||||
207,
|
||||
30,
|
||||
142,
|
||||
99
|
||||
],
|
||||
"private_key_holder": {
|
||||
"nullifier_secret_key": [
|
||||
128,
|
||||
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,
|
||||
29,
|
||||
169,
|
||||
68,
|
||||
187,
|
||||
65
|
||||
],
|
||||
"incoming_viewing_secret_key": [
|
||||
185,
|
||||
121,
|
||||
146,
|
||||
213,
|
||||
13,
|
||||
3,
|
||||
93,
|
||||
206,
|
||||
25,
|
||||
127,
|
||||
155,
|
||||
21,
|
||||
155,
|
||||
115,
|
||||
130,
|
||||
27,
|
||||
57,
|
||||
5,
|
||||
116,
|
||||
80,
|
||||
62,
|
||||
214,
|
||||
67,
|
||||
228,
|
||||
147,
|
||||
189,
|
||||
28,
|
||||
200,
|
||||
62,
|
||||
152,
|
||||
178,
|
||||
103
|
||||
],
|
||||
"outgoing_viewing_secret_key": [
|
||||
163,
|
||||
58,
|
||||
118,
|
||||
160,
|
||||
175,
|
||||
86,
|
||||
72,
|
||||
91,
|
||||
81,
|
||||
69,
|
||||
150,
|
||||
154,
|
||||
113,
|
||||
211,
|
||||
118,
|
||||
110,
|
||||
25,
|
||||
156,
|
||||
250,
|
||||
67,
|
||||
212,
|
||||
198,
|
||||
147,
|
||||
231,
|
||||
213,
|
||||
136,
|
||||
212,
|
||||
198,
|
||||
192,
|
||||
255,
|
||||
126,
|
||||
122
|
||||
]
|
||||
},
|
||||
"nullifer_public_key": [
|
||||
27,
|
||||
250,
|
||||
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,
|
||||
225,
|
||||
105
|
||||
],
|
||||
"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,
|
||||
98,
|
||||
226
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,13 +6,15 @@ use clap::Parser;
|
||||
use common::sequencer_client::SequencerClient;
|
||||
use log::{info, warn};
|
||||
use nssa::program::Program;
|
||||
use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point};
|
||||
use sequencer_core::config::SequencerConfig;
|
||||
use sequencer_runner::startup_sequencer;
|
||||
use tempfile::TempDir;
|
||||
use tokio::task::JoinHandle;
|
||||
use wallet::{
|
||||
Command,
|
||||
helperfunctions::{fetch_config, fetch_persistent_accounts},
|
||||
Command, SubcommandReturnValue, WalletCore,
|
||||
config::PersistentAccountData,
|
||||
helperfunctions::{fetch_config, fetch_persistent_accounts, produce_account_addr_from_hex},
|
||||
};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
@ -27,6 +29,11 @@ struct Args {
|
||||
pub const ACC_SENDER: &str = "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f";
|
||||
pub const ACC_RECEIVER: &str = "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766";
|
||||
|
||||
pub const ACC_SENDER_PRIVATE: &str =
|
||||
"6ffe0893c4b2c956fdb769b11fe4e3b2dd36ac4bd0ad90c810844051747c8c04";
|
||||
pub const ACC_RECEIVER_PRIVATE: &str =
|
||||
"4ee9de60e33da96fd72929f1485fb365bcc9c1634dd44e4ba55b1ab96692674b";
|
||||
|
||||
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -83,7 +90,8 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)
|
||||
}
|
||||
|
||||
pub async fn test_success() {
|
||||
let command = Command::SendNativeTokenTransfer {
|
||||
info!("test_success");
|
||||
let command = Command::SendNativeTokenTransferPublic {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to: ACC_RECEIVER.to_string(),
|
||||
amount: 100,
|
||||
@ -118,7 +126,8 @@ pub async fn test_success() {
|
||||
}
|
||||
|
||||
pub async fn test_success_move_to_another_account() {
|
||||
let command = Command::RegisterAccount {};
|
||||
info!("test_success_move_to_another_account");
|
||||
let command = Command::RegisterAccountPublic {};
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
@ -131,10 +140,10 @@ pub async fn test_success_move_to_another_account() {
|
||||
let mut new_persistent_account_addr = String::new();
|
||||
|
||||
for per_acc in persistent_accounts {
|
||||
if (per_acc.address.to_string() != ACC_RECEIVER)
|
||||
&& (per_acc.address.to_string() != ACC_SENDER)
|
||||
if (per_acc.address().to_string() != ACC_RECEIVER)
|
||||
&& (per_acc.address().to_string() != ACC_SENDER)
|
||||
{
|
||||
new_persistent_account_addr = per_acc.address.to_string();
|
||||
new_persistent_account_addr = per_acc.address().to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +151,7 @@ pub async fn test_success_move_to_another_account() {
|
||||
panic!("Failed to produce new account, not present in persistent accounts");
|
||||
}
|
||||
|
||||
let command = Command::SendNativeTokenTransfer {
|
||||
let command = Command::SendNativeTokenTransferPublic {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to: new_persistent_account_addr.clone(),
|
||||
amount: 100,
|
||||
@ -173,7 +182,8 @@ pub async fn test_success_move_to_another_account() {
|
||||
}
|
||||
|
||||
pub async fn test_failure() {
|
||||
let command = Command::SendNativeTokenTransfer {
|
||||
info!("test_failure");
|
||||
let command = Command::SendNativeTokenTransferPublic {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to: ACC_RECEIVER.to_string(),
|
||||
amount: 1000000,
|
||||
@ -210,7 +220,8 @@ pub async fn test_failure() {
|
||||
}
|
||||
|
||||
pub async fn test_success_two_transactions() {
|
||||
let command = Command::SendNativeTokenTransfer {
|
||||
info!("test_success_two_transactions");
|
||||
let command = Command::SendNativeTokenTransferPublic {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to: ACC_RECEIVER.to_string(),
|
||||
amount: 100,
|
||||
@ -243,7 +254,7 @@ pub async fn test_success_two_transactions() {
|
||||
|
||||
info!("First TX Success!");
|
||||
|
||||
let command = Command::SendNativeTokenTransfer {
|
||||
let command = Command::SendNativeTokenTransferPublic {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to: ACC_RECEIVER.to_string(),
|
||||
amount: 100,
|
||||
@ -274,6 +285,7 @@ pub async fn test_success_two_transactions() {
|
||||
}
|
||||
|
||||
pub async fn test_get_account() {
|
||||
info!("test_get_account");
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
@ -298,15 +310,15 @@ pub async fn test_success_token_program() {
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
// Create new account for the token definition
|
||||
wallet::execute_subcommand(Command::RegisterAccount {})
|
||||
wallet::execute_subcommand(Command::RegisterAccountPublic {})
|
||||
.await
|
||||
.unwrap();
|
||||
// Create new account for the token supply holder
|
||||
wallet::execute_subcommand(Command::RegisterAccount {})
|
||||
wallet::execute_subcommand(Command::RegisterAccountPublic {})
|
||||
.await
|
||||
.unwrap();
|
||||
// Create new account for receiving a token transaction
|
||||
wallet::execute_subcommand(Command::RegisterAccount {})
|
||||
wallet::execute_subcommand(Command::RegisterAccountPublic {})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -315,10 +327,15 @@ pub async fn test_success_token_program() {
|
||||
let mut new_persistent_accounts_addr = Vec::new();
|
||||
|
||||
for per_acc in persistent_accounts {
|
||||
if (per_acc.address.to_string() != ACC_RECEIVER)
|
||||
&& (per_acc.address.to_string() != ACC_SENDER)
|
||||
{
|
||||
new_persistent_accounts_addr.push(per_acc.address);
|
||||
match per_acc {
|
||||
PersistentAccountData::Public(per_acc) => {
|
||||
if (per_acc.address.to_string() != ACC_RECEIVER)
|
||||
&& (per_acc.address.to_string() != ACC_SENDER)
|
||||
{
|
||||
new_persistent_accounts_addr.push(per_acc.address);
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +450,483 @@ pub async fn test_success_token_program() {
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn test_success_private_transfer_to_another_owned_account() {
|
||||
info!("test_success_private_transfer_to_another_owned_account");
|
||||
let command = Command::SendNativeTokenTransferPrivate {
|
||||
from: ACC_SENDER_PRIVATE.to_string(),
|
||||
to: ACC_RECEIVER_PRIVATE.to_string(),
|
||||
amount: 100,
|
||||
};
|
||||
|
||||
let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap();
|
||||
let to = produce_account_addr_from_hex(ACC_RECEIVER_PRIVATE.to_string()).unwrap();
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment1 = {
|
||||
let from_acc = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account_mut(&from)
|
||||
.unwrap();
|
||||
|
||||
from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
from_acc.1.balance -= 100;
|
||||
from_acc.1.nonce += 1;
|
||||
|
||||
nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1)
|
||||
};
|
||||
|
||||
let new_commitment2 = {
|
||||
let to_acc = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account_mut(&to)
|
||||
.unwrap();
|
||||
|
||||
to_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
to_acc.1.balance += 100;
|
||||
to_acc.1.nonce += 1;
|
||||
|
||||
nssa_core::Commitment::new(&to_acc.0.nullifer_public_key, &to_acc.1)
|
||||
};
|
||||
|
||||
let proof1 = seq_client
|
||||
.get_proof_for_commitment(new_commitment1)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let proof2 = seq_client
|
||||
.get_proof_for_commitment(new_commitment2)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
println!("New proof is {proof1:#?}");
|
||||
println!("New proof is {proof2:#?}");
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
pub async fn test_success_private_transfer_to_another_foreign_account() {
|
||||
info!("test_success_private_transfer_to_another_foreign_account");
|
||||
let to_npk_orig = NullifierPublicKey([42; 32]);
|
||||
let to_npk = hex::encode(to_npk_orig.0);
|
||||
let to_ipk = Secp256k1Point::from_scalar(to_npk_orig.0);
|
||||
|
||||
let command = Command::SendNativeTokenTransferPrivateForeignAccount {
|
||||
from: ACC_SENDER_PRIVATE.to_string(),
|
||||
to_npk,
|
||||
to_ipk: hex::encode(to_ipk.0),
|
||||
amount: 100,
|
||||
};
|
||||
|
||||
let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap();
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
println!("SUB RET is {sub_ret:#?}");
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment1 = {
|
||||
let from_acc = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account_mut(&from)
|
||||
.unwrap();
|
||||
|
||||
from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
from_acc.1.balance -= 100;
|
||||
from_acc.1.nonce += 1;
|
||||
|
||||
nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1)
|
||||
};
|
||||
|
||||
let new_commitment2 = {
|
||||
let to_acc = nssa_core::account::Account {
|
||||
program_owner: nssa::program::Program::authenticated_transfer_program().id(),
|
||||
balance: 100,
|
||||
data: vec![],
|
||||
nonce: 1,
|
||||
};
|
||||
|
||||
nssa_core::Commitment::new(&to_npk_orig, &to_acc)
|
||||
};
|
||||
|
||||
let proof1 = seq_client
|
||||
.get_proof_for_commitment(new_commitment1)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let proof2 = seq_client
|
||||
.get_proof_for_commitment(new_commitment2)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
println!("New proof is {proof1:#?}");
|
||||
println!("New proof is {proof2:#?}");
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
pub async fn test_success_private_transfer_to_another_owned_account_claiming_path() {
|
||||
info!("test_success_private_transfer_to_another_owned_account_claiming_path");
|
||||
let command = Command::RegisterAccountPrivate {};
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else {
|
||||
panic!("FAILED TO REGISTER ACCOUNT");
|
||||
};
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let mut wallet_storage =
|
||||
WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap();
|
||||
|
||||
let (to_keys, mut to_acc) = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.user_private_accounts
|
||||
.get(&to_addr)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
|
||||
let command = Command::SendNativeTokenTransferPrivateForeignAccount {
|
||||
from: ACC_SENDER_PRIVATE.to_string(),
|
||||
to_npk: hex::encode(to_keys.nullifer_public_key.0),
|
||||
to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0),
|
||||
amount: 100,
|
||||
};
|
||||
|
||||
let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap();
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
||||
panic!("FAILED TO SEND TX");
|
||||
};
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment1 = {
|
||||
let from_acc = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account_mut(&from)
|
||||
.unwrap();
|
||||
|
||||
from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
from_acc.1.balance -= 100;
|
||||
from_acc.1.nonce += 1;
|
||||
|
||||
nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1)
|
||||
};
|
||||
|
||||
let new_commitment2 = {
|
||||
to_acc.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
to_acc.balance = 100;
|
||||
to_acc.nonce = 1;
|
||||
|
||||
nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc)
|
||||
};
|
||||
|
||||
let proof1 = seq_client
|
||||
.get_proof_for_commitment(new_commitment1)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let proof2 = seq_client
|
||||
.get_proof_for_commitment(new_commitment2)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
println!("New proof is {proof1:#?}");
|
||||
println!("New proof is {proof2:#?}");
|
||||
|
||||
let command = Command::ClaimPrivateAccount {
|
||||
tx_hash,
|
||||
acc_addr: hex::encode(to_addr),
|
||||
ciph_id: 1,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
||||
|
||||
let (_, to_res_acc) = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account(&to_addr)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(to_res_acc.balance, 100);
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
pub async fn test_success_deshielded_transfer_to_another_account() {
|
||||
info!("test_success_deshielded_transfer_to_another_account");
|
||||
let command = Command::SendNativeTokenTransferDeshielded {
|
||||
from: ACC_SENDER_PRIVATE.to_string(),
|
||||
to: ACC_RECEIVER.to_string(),
|
||||
amount: 100,
|
||||
};
|
||||
|
||||
let from = produce_account_addr_from_hex(ACC_SENDER_PRIVATE.to_string()).unwrap();
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment1 = {
|
||||
let from_acc = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account_mut(&from)
|
||||
.unwrap();
|
||||
|
||||
from_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
from_acc.1.balance -= 100;
|
||||
from_acc.1.nonce += 1;
|
||||
|
||||
nssa_core::Commitment::new(&from_acc.0.nullifer_public_key, &from_acc.1)
|
||||
};
|
||||
|
||||
let proof1 = seq_client
|
||||
.get_proof_for_commitment(new_commitment1)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let acc_2_balance = seq_client
|
||||
.get_account_balance(ACC_RECEIVER.to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
println!("New proof is {proof1:#?}");
|
||||
assert_eq!(acc_2_balance.balance, 20100);
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
pub async fn test_success_shielded_transfer_to_another_owned_account() {
|
||||
info!("test_success_shielded_transfer_to_another_owned_account");
|
||||
let command = Command::SendNativeTokenTransferShielded {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to: ACC_RECEIVER_PRIVATE.to_string(),
|
||||
amount: 100,
|
||||
};
|
||||
|
||||
let to = produce_account_addr_from_hex(ACC_RECEIVER_PRIVATE.to_string()).unwrap();
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let mut wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment2 = {
|
||||
let to_acc = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account_mut(&to)
|
||||
.unwrap();
|
||||
|
||||
to_acc.1.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
to_acc.1.balance += 100;
|
||||
to_acc.1.nonce += 1;
|
||||
|
||||
nssa_core::Commitment::new(&to_acc.0.nullifer_public_key, &to_acc.1)
|
||||
};
|
||||
|
||||
let acc_1_balance = seq_client
|
||||
.get_account_balance(ACC_SENDER.to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proof2 = seq_client
|
||||
.get_proof_for_commitment(new_commitment2)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(acc_1_balance.balance, 9900);
|
||||
|
||||
println!("New proof is {proof2:#?}");
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
pub async fn test_success_shielded_transfer_to_another_foreign_account() {
|
||||
info!("test_success_shielded_transfer_to_another_foreign_account");
|
||||
let to_npk_orig = NullifierPublicKey([42; 32]);
|
||||
let to_npk = hex::encode(to_npk_orig.0);
|
||||
let to_ipk = Secp256k1Point::from_scalar(to_npk_orig.0);
|
||||
|
||||
let command = Command::SendNativeTokenTransferShieldedForeignAccount {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to_npk,
|
||||
to_ipk: hex::encode(to_ipk.0),
|
||||
amount: 100,
|
||||
};
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment2 = {
|
||||
let to_acc = nssa_core::account::Account {
|
||||
program_owner: nssa::program::Program::authenticated_transfer_program().id(),
|
||||
balance: 100,
|
||||
data: vec![],
|
||||
nonce: 1,
|
||||
};
|
||||
|
||||
nssa_core::Commitment::new(&to_npk_orig, &to_acc)
|
||||
};
|
||||
|
||||
let acc_1_balance = seq_client
|
||||
.get_account_balance(ACC_SENDER.to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proof2 = seq_client
|
||||
.get_proof_for_commitment(new_commitment2)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(acc_1_balance.balance, 9900);
|
||||
println!("New proof is {proof2:#?}");
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
pub async fn test_success_shielded_transfer_to_another_owned_account_claiming_path() {
|
||||
info!("test_success_shielded_transfer_to_another_owned_account_claiming_path");
|
||||
let command = Command::RegisterAccountPrivate {};
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else {
|
||||
panic!("FAILED TO REGISTER ACCOUNT");
|
||||
};
|
||||
|
||||
let wallet_config = fetch_config().unwrap();
|
||||
|
||||
let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap();
|
||||
|
||||
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()).unwrap();
|
||||
|
||||
let (to_keys, mut to_acc) = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.user_private_accounts
|
||||
.get(&to_addr)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
|
||||
let command = Command::SendNativeTokenTransferShieldedForeignAccount {
|
||||
from: ACC_SENDER.to_string(),
|
||||
to_npk: hex::encode(to_keys.nullifer_public_key.0),
|
||||
to_ipk: hex::encode(to_keys.incoming_viewing_public_key.0),
|
||||
amount: 100,
|
||||
};
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else {
|
||||
panic!("FAILED TO SEND TX");
|
||||
};
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment2 = {
|
||||
to_acc.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
to_acc.balance = 100;
|
||||
to_acc.nonce = 1;
|
||||
|
||||
nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc)
|
||||
};
|
||||
|
||||
let acc_1_balance = seq_client
|
||||
.get_account_balance(ACC_SENDER.to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let proof2 = seq_client
|
||||
.get_proof_for_commitment(new_commitment2)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(acc_1_balance.balance, 9900);
|
||||
println!("New proof is {proof2:#?}");
|
||||
|
||||
let command = Command::ClaimPrivateAccount {
|
||||
tx_hash,
|
||||
acc_addr: hex::encode(to_addr),
|
||||
ciph_id: 0,
|
||||
};
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config).unwrap();
|
||||
|
||||
let (_, to_res_acc) = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account(&to_addr)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(to_res_acc.balance, 100);
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
pub async fn test_pinata() {
|
||||
info!("test_pinata");
|
||||
let pinata_addr = "cafe".repeat(16);
|
||||
let pinata_prize = 150;
|
||||
let solution = 989106;
|
||||
@ -518,6 +1011,48 @@ pub async fn main_tests_runner() -> Result<()> {
|
||||
"test_success_two_transactions" => {
|
||||
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
||||
}
|
||||
"test_success_private_transfer_to_another_owned_account" => {
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_private_transfer_to_another_owned_account
|
||||
);
|
||||
}
|
||||
"test_success_private_transfer_to_another_foreign_account" => {
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_private_transfer_to_another_foreign_account
|
||||
);
|
||||
}
|
||||
"test_success_private_transfer_to_another_owned_account_claiming_path" => {
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_private_transfer_to_another_owned_account_claiming_path
|
||||
);
|
||||
}
|
||||
"test_success_deshielded_transfer_to_another_account" => {
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_deshielded_transfer_to_another_account
|
||||
);
|
||||
}
|
||||
"test_success_shielded_transfer_to_another_owned_account" => {
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_shielded_transfer_to_another_owned_account
|
||||
);
|
||||
}
|
||||
"test_success_shielded_transfer_to_another_foreign_account" => {
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_shielded_transfer_to_another_foreign_account
|
||||
);
|
||||
}
|
||||
"test_success_shielded_transfer_to_another_owned_account_claiming_path" => {
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_shielded_transfer_to_another_owned_account_claiming_path
|
||||
);
|
||||
}
|
||||
"test_pinata" => {
|
||||
test_cleanup_wrap!(home_dir, test_pinata);
|
||||
}
|
||||
@ -527,8 +1062,35 @@ pub async fn main_tests_runner() -> Result<()> {
|
||||
test_cleanup_wrap!(home_dir, test_failure);
|
||||
test_cleanup_wrap!(home_dir, test_success_two_transactions);
|
||||
test_cleanup_wrap!(home_dir, test_success_token_program);
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_private_transfer_to_another_owned_account
|
||||
);
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_private_transfer_to_another_foreign_account
|
||||
);
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_deshielded_transfer_to_another_account
|
||||
);
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_shielded_transfer_to_another_owned_account
|
||||
);
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_shielded_transfer_to_another_foreign_account
|
||||
);
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_private_transfer_to_another_owned_account_claiming_path
|
||||
);
|
||||
test_cleanup_wrap!(
|
||||
home_dir,
|
||||
test_success_shielded_transfer_to_another_owned_account_claiming_path
|
||||
);
|
||||
test_cleanup_wrap!(home_dir, test_pinata);
|
||||
test_cleanup_wrap!(home_dir, test_get_account);
|
||||
}
|
||||
_ => {
|
||||
anyhow::bail!("Unknown test name");
|
||||
|
||||
@ -3,6 +3,7 @@ use nssa_core::{
|
||||
NullifierPublicKey, SharedSecretKey,
|
||||
encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey},
|
||||
};
|
||||
use rand::{RngCore, rngs::OsRng};
|
||||
use sha2::Digest;
|
||||
|
||||
use crate::key_management::secret_holders::OutgoingViewingSecretKey;
|
||||
@ -13,6 +14,17 @@ pub struct EphemeralKeyHolder {
|
||||
ephemeral_secret_key: EphemeralSecretKey,
|
||||
}
|
||||
|
||||
pub fn produce_one_sided_shared_secret_receiver(
|
||||
ipk: &IncomingViewingPublicKey,
|
||||
) -> (SharedSecretKey, EphemeralPublicKey) {
|
||||
let mut esk = [0; 32];
|
||||
OsRng.fill_bytes(&mut esk);
|
||||
(
|
||||
SharedSecretKey::new(&esk, ipk),
|
||||
EphemeralPublicKey::from_scalar(esk),
|
||||
)
|
||||
}
|
||||
|
||||
impl EphemeralKeyHolder {
|
||||
pub fn new(
|
||||
receiver_nullifier_public_key: NullifierPublicKey,
|
||||
|
||||
@ -22,6 +22,18 @@ pub struct KeyChain {
|
||||
pub incoming_viewing_public_key: IncomingViewingPublicKey,
|
||||
}
|
||||
|
||||
pub fn produce_user_address_foreign_account(
|
||||
npk: &NullifierPublicKey,
|
||||
ipk: &IncomingViewingPublicKey,
|
||||
) -> [u8; 32] {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
|
||||
hasher.update(npk);
|
||||
hasher.update(ipk.to_bytes());
|
||||
|
||||
<TreeHashType>::from(hasher.finalize_fixed())
|
||||
}
|
||||
|
||||
impl KeyChain {
|
||||
pub fn new_os_random() -> Self {
|
||||
//Currently dropping SeedHolder at the end of initialization.
|
||||
|
||||
@ -26,9 +26,9 @@ pub type OutgoingViewingSecretKey = Scalar;
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
///Private key holder. Produces public keys. Can produce address. Can produce shared secret for recepient.
|
||||
pub struct PrivateKeyHolder {
|
||||
pub(crate) nullifier_secret_key: NullifierSecretKey,
|
||||
pub nullifier_secret_key: NullifierSecretKey,
|
||||
pub(crate) incoming_viewing_secret_key: IncomingViewingSecretKey,
|
||||
pub(crate) outgoing_viewing_secret_key: OutgoingViewingSecretKey,
|
||||
pub outgoing_viewing_secret_key: OutgoingViewingSecretKey,
|
||||
}
|
||||
|
||||
impl SeedHolder {
|
||||
|
||||
@ -13,7 +13,7 @@ pub struct NSSAUserData {
|
||||
///Map for all user public accounts
|
||||
pub pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||
///Map for all user private accounts
|
||||
user_private_accounts: HashMap<nssa::Address, KeyChain>,
|
||||
pub user_private_accounts: HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
}
|
||||
|
||||
impl NSSAUserData {
|
||||
@ -30,10 +30,10 @@ impl NSSAUserData {
|
||||
}
|
||||
|
||||
fn valid_private_key_transaction_pairing_check(
|
||||
accounts_keys_map: &HashMap<nssa::Address, KeyChain>,
|
||||
accounts_keys_map: &HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
) -> bool {
|
||||
let mut check_res = true;
|
||||
for (addr, key) in accounts_keys_map {
|
||||
for (addr, (key, _)) in accounts_keys_map {
|
||||
if nssa::Address::new(key.produce_user_address()) != *addr {
|
||||
check_res = false;
|
||||
}
|
||||
@ -43,7 +43,7 @@ impl NSSAUserData {
|
||||
|
||||
pub fn new_with_accounts(
|
||||
accounts_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||
accounts_key_chains: HashMap<nssa::Address, KeyChain>,
|
||||
accounts_key_chains: HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
) -> Result<Self> {
|
||||
if !Self::valid_public_key_transaction_pairing_check(&accounts_keys) {
|
||||
anyhow::bail!(
|
||||
@ -90,15 +90,27 @@ impl NSSAUserData {
|
||||
let key_chain = KeyChain::new_os_random();
|
||||
let address = nssa::Address::new(key_chain.produce_user_address());
|
||||
|
||||
self.user_private_accounts.insert(address, key_chain);
|
||||
self.user_private_accounts
|
||||
.insert(address, (key_chain, nssa_core::account::Account::default()));
|
||||
|
||||
address
|
||||
}
|
||||
|
||||
/// Returns the signing key for public transaction signatures
|
||||
pub fn get_private_account_key_chain(&self, address: &nssa::Address) -> Option<&KeyChain> {
|
||||
pub fn get_private_account(
|
||||
&self,
|
||||
address: &nssa::Address,
|
||||
) -> Option<&(KeyChain, nssa_core::account::Account)> {
|
||||
self.user_private_accounts.get(address)
|
||||
}
|
||||
|
||||
/// Returns the signing key for public transaction signatures
|
||||
pub fn get_private_account_mut(
|
||||
&mut self,
|
||||
address: &nssa::Address,
|
||||
) -> Option<&mut (KeyChain, nssa_core::account::Account)> {
|
||||
self.user_private_accounts.get_mut(address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NSSAUserData {
|
||||
@ -123,9 +135,7 @@ mod tests {
|
||||
|
||||
assert!(is_private_key_generated);
|
||||
|
||||
let is_key_chain_generated = user_data
|
||||
.get_private_account_key_chain(&addr_private)
|
||||
.is_some();
|
||||
let is_key_chain_generated = user_data.get_private_account(&addr_private).is_some();
|
||||
|
||||
assert!(is_key_chain_generated);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "2.0.12"
|
||||
risc0-zkvm = "3.0.3"
|
||||
risc0-zkvm = { version = "3.0.3", features = ['std'] }
|
||||
nssa-core = { path = "core", features = ["host"] }
|
||||
program-methods = { path = "program_methods" }
|
||||
serde = "1.0.219"
|
||||
|
||||
@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
risc0-zkvm = { version = "3.0.3" }
|
||||
risc0-zkvm = { version = "3.0.3", features = ['std'] }
|
||||
serde = { version = "1.0", default-features = false }
|
||||
thiserror = { version = "2.0.12", optional = true }
|
||||
bytemuck = { version = "1.13", optional = true }
|
||||
|
||||
@ -6,7 +6,7 @@ use risc0_zkvm::sha::{Impl, Sha256};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
pub(crate) mod shared_key_derivation;
|
||||
pub mod shared_key_derivation;
|
||||
|
||||
#[cfg(feature = "host")]
|
||||
pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey};
|
||||
@ -16,7 +16,7 @@ use crate::{Commitment, account::Account};
|
||||
pub type Scalar = [u8; 32];
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct SharedSecretKey([u8; 32]);
|
||||
pub struct SharedSecretKey(pub [u8; 32]);
|
||||
|
||||
pub struct EncryptionScheme;
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ use k256::{
|
||||
use crate::{SharedSecretKey, encryption::Scalar};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub struct Secp256k1Point(pub(crate) Vec<u8>);
|
||||
pub struct Secp256k1Point(pub Vec<u8>);
|
||||
|
||||
impl Secp256k1Point {
|
||||
pub fn from_scalar(value: Scalar) -> Secp256k1Point {
|
||||
|
||||
@ -5,7 +5,7 @@ use crate::{Commitment, account::AccountId};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, Clone, Hash))]
|
||||
pub struct NullifierPublicKey(pub(super) [u8; 32]);
|
||||
pub struct NullifierPublicKey(pub [u8; 32]);
|
||||
|
||||
impl From<&NullifierPublicKey> for AccountId {
|
||||
fn from(value: &NullifierPublicKey) -> Self {
|
||||
|
||||
@ -6,6 +6,6 @@ edition = "2024"
|
||||
[workspace]
|
||||
|
||||
[dependencies]
|
||||
risc0-zkvm = { version = "3.0.3", default-features = false, features = ['std'] }
|
||||
risc0-zkvm = { version = "3.0.3", features = ['std'] }
|
||||
nssa-core = { path = "../../core" }
|
||||
serde = { version = "1.0.219", default-features = false }
|
||||
|
||||
@ -2,7 +2,7 @@ pub mod address;
|
||||
pub mod encoding;
|
||||
pub mod error;
|
||||
mod merkle_tree;
|
||||
mod privacy_preserving_transaction;
|
||||
pub mod privacy_preserving_transaction;
|
||||
pub mod program;
|
||||
pub mod public_transaction;
|
||||
mod signature;
|
||||
|
||||
@ -11,9 +11,9 @@ pub type ViewTag = u8;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EncryptedAccountData {
|
||||
pub(crate) ciphertext: Ciphertext,
|
||||
pub(crate) epk: EphemeralPublicKey,
|
||||
pub(crate) view_tag: ViewTag,
|
||||
pub ciphertext: Ciphertext,
|
||||
pub epk: EphemeralPublicKey,
|
||||
pub view_tag: ViewTag,
|
||||
}
|
||||
|
||||
impl EncryptedAccountData {
|
||||
@ -47,8 +47,8 @@ pub struct Message {
|
||||
pub(crate) public_addresses: Vec<Address>,
|
||||
pub(crate) nonces: Vec<Nonce>,
|
||||
pub(crate) public_post_states: Vec<Account>,
|
||||
pub(crate) encrypted_private_post_states: Vec<EncryptedAccountData>,
|
||||
pub(crate) new_commitments: Vec<Commitment>,
|
||||
pub encrypted_private_post_states: Vec<EncryptedAccountData>,
|
||||
pub new_commitments: Vec<Commitment>,
|
||||
pub(crate) new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)>,
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ use super::witness_set::WitnessSet;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct PrivacyPreservingTransaction {
|
||||
message: Message,
|
||||
pub message: Message,
|
||||
witness_set: WitnessSet,
|
||||
}
|
||||
|
||||
|
||||
@ -141,7 +141,7 @@ pub mod tests {
|
||||
fn state_for_tests() -> V01State {
|
||||
let (_, _, addr1, addr2) = keys_for_tests();
|
||||
let initial_data = [(addr1, 10000), (addr2, 20000)];
|
||||
V01State::new_with_genesis_accounts(&initial_data)
|
||||
V01State::new_with_genesis_accounts(&initial_data, &[])
|
||||
}
|
||||
|
||||
fn transaction_for_tests() -> PublicTransaction {
|
||||
|
||||
@ -64,7 +64,10 @@ pub struct V01State {
|
||||
}
|
||||
|
||||
impl V01State {
|
||||
pub fn new_with_genesis_accounts(initial_data: &[(Address, u128)]) -> Self {
|
||||
pub fn new_with_genesis_accounts(
|
||||
initial_data: &[(Address, u128)],
|
||||
initial_commitments: &[nssa_core::Commitment],
|
||||
) -> Self {
|
||||
let authenticated_transfer_program = Program::authenticated_transfer_program();
|
||||
let public_state = initial_data
|
||||
.iter()
|
||||
@ -79,9 +82,12 @@ impl V01State {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut private_state = CommitmentSet::with_capacity(32);
|
||||
private_state.extend(initial_commitments);
|
||||
|
||||
let mut this = Self {
|
||||
public_state,
|
||||
private_state: (CommitmentSet::with_capacity(32), NullifierSet::new()),
|
||||
private_state: (private_state, NullifierSet::new()),
|
||||
builtin_programs: HashMap::new(),
|
||||
};
|
||||
|
||||
@ -301,7 +307,7 @@ pub mod tests {
|
||||
this
|
||||
};
|
||||
|
||||
let state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
||||
|
||||
assert_eq!(state.public_state, expected_public_state);
|
||||
assert_eq!(state.builtin_programs, expected_builtin_programs);
|
||||
@ -309,7 +315,7 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_insert_program() {
|
||||
let mut state = V01State::new_with_genesis_accounts(&[]);
|
||||
let mut state = V01State::new_with_genesis_accounts(&[], &[]);
|
||||
let program_to_insert = Program::simple_balance_transfer();
|
||||
let program_id = program_to_insert.id();
|
||||
assert!(!state.builtin_programs.contains_key(&program_id));
|
||||
@ -324,7 +330,7 @@ pub mod tests {
|
||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let addr = Address::from(&PublicKey::new_from_private_key(&key));
|
||||
let initial_data = [(addr, 100u128)];
|
||||
let state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
||||
let expected_account = state.public_state.get(&addr).unwrap();
|
||||
|
||||
let account = state.get_account_by_address(&addr);
|
||||
@ -335,7 +341,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_get_account_by_address_default_account() {
|
||||
let addr2 = Address::new([0; 32]);
|
||||
let state = V01State::new_with_genesis_accounts(&[]);
|
||||
let state = V01State::new_with_genesis_accounts(&[], &[]);
|
||||
let expected_account = Account::default();
|
||||
|
||||
let account = state.get_account_by_address(&addr2);
|
||||
@ -345,7 +351,7 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_builtin_programs_getter() {
|
||||
let state = V01State::new_with_genesis_accounts(&[]);
|
||||
let state = V01State::new_with_genesis_accounts(&[], &[]);
|
||||
|
||||
let builtin_programs = state.builtin_programs();
|
||||
|
||||
@ -357,7 +363,7 @@ pub mod tests {
|
||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
||||
let initial_data = [(address, 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
||||
let from = address;
|
||||
let to = Address::new([2; 32]);
|
||||
assert_eq!(state.get_account_by_address(&to), Account::default());
|
||||
@ -377,7 +383,7 @@ pub mod tests {
|
||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
||||
let initial_data = [(address, 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
||||
let from = address;
|
||||
let from_key = key;
|
||||
let to = Address::new([2; 32]);
|
||||
@ -401,7 +407,7 @@ pub mod tests {
|
||||
let address1 = Address::from(&PublicKey::new_from_private_key(&key1));
|
||||
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||
let initial_data = [(address1, 100), (address2, 200)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
||||
let from = address2;
|
||||
let from_key = key2;
|
||||
let to = address1;
|
||||
@ -424,7 +430,7 @@ pub mod tests {
|
||||
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||
let initial_data = [(address1, 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
||||
let address3 = Address::new([3; 32]);
|
||||
let balance_to_move = 5;
|
||||
|
||||
@ -508,7 +514,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_modifies_nonces() {
|
||||
let initial_data = [(Address::new([1; 32]), 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||
let mut state =
|
||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let addresses = vec![Address::new([1; 32])];
|
||||
let program_id = Program::nonce_changer_program().id();
|
||||
let message =
|
||||
@ -524,7 +531,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_output_accounts_exceed_inputs() {
|
||||
let initial_data = [(Address::new([1; 32]), 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||
let mut state =
|
||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let addresses = vec![Address::new([1; 32])];
|
||||
let program_id = Program::extra_output_program().id();
|
||||
let message =
|
||||
@ -540,7 +548,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_with_missing_output_accounts() {
|
||||
let initial_data = [(Address::new([1; 32]), 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||
let mut state =
|
||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let addresses = vec![Address::new([1; 32]), Address::new([2; 32])];
|
||||
let program_id = Program::missing_output_program().id();
|
||||
let message =
|
||||
@ -556,7 +565,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() {
|
||||
let initial_data = [(Address::new([1; 32]), 0)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||
let mut state =
|
||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let address = Address::new([1; 32]);
|
||||
let account = state.get_account_by_address(&address);
|
||||
// Assert the target account only differs from the default account in the program owner field
|
||||
@ -578,7 +588,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_balance() {
|
||||
let initial_data = [];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
||||
.with_test_programs()
|
||||
.with_non_default_accounts_but_default_program_owners();
|
||||
let address = Address::new([255; 32]);
|
||||
@ -602,7 +612,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() {
|
||||
let initial_data = [];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
||||
.with_test_programs()
|
||||
.with_non_default_accounts_but_default_program_owners();
|
||||
let address = Address::new([254; 32]);
|
||||
@ -626,7 +636,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_data() {
|
||||
let initial_data = [];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
||||
.with_test_programs()
|
||||
.with_non_default_accounts_but_default_program_owners();
|
||||
let address = Address::new([253; 32]);
|
||||
@ -650,7 +660,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_transfers_balance_from_non_owned_account() {
|
||||
let initial_data = [(Address::new([1; 32]), 100)];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||
let mut state =
|
||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let sender_address = Address::new([1; 32]);
|
||||
let receiver_address = Address::new([2; 32]);
|
||||
let balance_to_move: u128 = 1;
|
||||
@ -677,7 +688,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_modifies_data_of_non_owned_account() {
|
||||
let initial_data = [];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
||||
.with_test_programs()
|
||||
.with_non_default_accounts_but_default_program_owners();
|
||||
let address = Address::new([255; 32]);
|
||||
@ -701,7 +712,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_does_not_preserve_total_balance_by_minting() {
|
||||
let initial_data = [];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||
let mut state =
|
||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let address = Address::new([1; 32]);
|
||||
let program_id = Program::minter().id();
|
||||
|
||||
@ -718,7 +730,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_program_should_fail_if_does_not_preserve_total_balance_by_burning() {
|
||||
let initial_data = [];
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
||||
.with_test_programs()
|
||||
.with_account_owned_by_burner_program();
|
||||
let program_id = Program::burner().id();
|
||||
@ -942,7 +954,7 @@ pub mod tests {
|
||||
let sender_keys = test_public_account_keys_1();
|
||||
let recipient_keys = test_private_account_keys_1();
|
||||
|
||||
let mut state = V01State::new_with_genesis_accounts(&[(sender_keys.address(), 200)]);
|
||||
let mut state = V01State::new_with_genesis_accounts(&[(sender_keys.address(), 200)], &[]);
|
||||
|
||||
let balance_to_move = 37;
|
||||
|
||||
@ -988,7 +1000,7 @@ pub mod tests {
|
||||
};
|
||||
let recipient_keys = test_private_account_keys_2();
|
||||
|
||||
let mut state = V01State::new_with_genesis_accounts(&[])
|
||||
let mut state = V01State::new_with_genesis_accounts(&[], &[])
|
||||
.with_private_account(&sender_keys, &sender_private_account);
|
||||
|
||||
let balance_to_move = 37;
|
||||
@ -1053,10 +1065,10 @@ pub mod tests {
|
||||
};
|
||||
let recipient_keys = test_public_account_keys_1();
|
||||
let recipient_initial_balance = 400;
|
||||
let mut state = V01State::new_with_genesis_accounts(&[(
|
||||
recipient_keys.address(),
|
||||
recipient_initial_balance,
|
||||
)])
|
||||
let mut state = V01State::new_with_genesis_accounts(
|
||||
&[(recipient_keys.address(), recipient_initial_balance)],
|
||||
&[],
|
||||
)
|
||||
.with_private_account(&sender_keys, &sender_private_account);
|
||||
|
||||
let balance_to_move = 37;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@ rand.workspace = true
|
||||
tempfile.workspace = true
|
||||
chrono.workspace = true
|
||||
log.workspace = true
|
||||
nssa-core = { path = "../nssa/core", features = ["host"] }
|
||||
|
||||
[dependencies.storage]
|
||||
path = "../storage"
|
||||
|
||||
@ -9,6 +9,13 @@ pub struct AccountInitialData {
|
||||
pub balance: u128,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
///Helperstruct to initialize commitments
|
||||
pub struct CommitmentsInitialData {
|
||||
pub npk: nssa_core::NullifierPublicKey,
|
||||
pub account: nssa_core::account::Account,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SequencerConfig {
|
||||
///Home dir of sequencer storage
|
||||
@ -27,6 +34,8 @@ pub struct SequencerConfig {
|
||||
pub port: u16,
|
||||
///List of initial accounts data
|
||||
pub initial_accounts: Vec<AccountInitialData>,
|
||||
///List of initial commitments
|
||||
pub initial_commitments: Vec<CommitmentsInitialData>,
|
||||
///Sequencer own signing key
|
||||
pub signing_key: [u8; 32],
|
||||
}
|
||||
|
||||
@ -49,12 +49,27 @@ impl std::error::Error for TransactionMalformationErrorKind {}
|
||||
|
||||
impl SequencerCore {
|
||||
pub fn start_from_config(config: SequencerConfig) -> Self {
|
||||
let mut initial_commitments = vec![];
|
||||
|
||||
for init_comm_data in config.initial_commitments.clone() {
|
||||
let npk = init_comm_data.npk;
|
||||
|
||||
let mut acc = init_comm_data.account;
|
||||
|
||||
acc.program_owner = nssa::program::Program::authenticated_transfer_program().id();
|
||||
|
||||
let comm = nssa_core::Commitment::new(&npk, &acc);
|
||||
|
||||
initial_commitments.push(comm);
|
||||
}
|
||||
|
||||
Self {
|
||||
store: SequecerChainStore::new_with_genesis(
|
||||
&config.home,
|
||||
config.genesis_id,
|
||||
config.is_genesis_random,
|
||||
&config.initial_accounts,
|
||||
&initial_commitments,
|
||||
nssa::PrivateKey::try_new(config.signing_key).unwrap(),
|
||||
),
|
||||
mempool: MemPool::default(),
|
||||
@ -209,6 +224,7 @@ mod tests {
|
||||
block_create_timeout_millis: 1000,
|
||||
port: 8080,
|
||||
initial_accounts,
|
||||
initial_commitments: vec![],
|
||||
signing_key: *sequencer_sign_key_for_testing().value(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ impl SequecerChainStore {
|
||||
genesis_id: u64,
|
||||
is_genesis_random: bool,
|
||||
initial_accounts: &[AccountInitialData],
|
||||
initial_commitments: &[nssa_core::Commitment],
|
||||
signing_key: nssa::PrivateKey,
|
||||
) -> Self {
|
||||
let init_accs: Vec<(Address, u128)> = initial_accounts
|
||||
@ -28,11 +29,12 @@ impl SequecerChainStore {
|
||||
.collect();
|
||||
|
||||
#[cfg(not(feature = "testnet"))]
|
||||
let state = nssa::V01State::new_with_genesis_accounts(&init_accs);
|
||||
let state = nssa::V01State::new_with_genesis_accounts(&init_accs, initial_commitments);
|
||||
|
||||
#[cfg(feature = "testnet")]
|
||||
let state = {
|
||||
let mut this = nssa::V01State::new_with_genesis_accounts(&init_accs);
|
||||
let mut this =
|
||||
nssa::V01State::new_with_genesis_accounts(&init_accs, initial_commitments);
|
||||
this.add_pinata_program("cafe".repeat(16).parse().unwrap());
|
||||
this
|
||||
};
|
||||
|
||||
@ -12,6 +12,7 @@ actix-cors.workspace = true
|
||||
futures.workspace = true
|
||||
hex.workspace = true
|
||||
tempfile.workspace = true
|
||||
nssa-core = { path = "../nssa/core", features = ["host"] }
|
||||
base64.workspace = true
|
||||
|
||||
actix-web.workspace = true
|
||||
|
||||
@ -14,7 +14,8 @@ use common::{
|
||||
requests::{
|
||||
GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest,
|
||||
GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
|
||||
GetInitialTestnetAccountsRequest, GetTransactionByHashRequest,
|
||||
GetInitialTestnetAccountsRequest, GetProofByCommitmentRequest,
|
||||
GetProofByCommitmentResponse, GetTransactionByHashRequest,
|
||||
GetTransactionByHashResponse,
|
||||
},
|
||||
},
|
||||
@ -38,6 +39,7 @@ pub const GET_ACCOUNT_BALANCE: &str = "get_account_balance";
|
||||
pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash";
|
||||
pub const GET_ACCOUNTS_NONCES: &str = "get_accounts_nonces";
|
||||
pub const GET_ACCOUNT: &str = "get_account";
|
||||
pub const GET_PROOF_FOR_COMMITMENT: &str = "get_proof_for_commitment";
|
||||
|
||||
pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER";
|
||||
|
||||
@ -250,6 +252,21 @@ impl JsonHandler {
|
||||
respond(helperstruct)
|
||||
}
|
||||
|
||||
/// Returns the commitment proof, corresponding to commitment
|
||||
async fn process_get_proof_by_commitment(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
let get_proof_req = GetProofByCommitmentRequest::parse(Some(request.params))?;
|
||||
|
||||
let membership_proof = {
|
||||
let state = self.sequencer_state.lock().await;
|
||||
state
|
||||
.store
|
||||
.state
|
||||
.get_proof_for_commitment(&get_proof_req.commitment)
|
||||
};
|
||||
let helperstruct = GetProofByCommitmentResponse { membership_proof };
|
||||
respond(helperstruct)
|
||||
}
|
||||
|
||||
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
match request.method.as_ref() {
|
||||
HELLO => self.process_temp_hello(request).await,
|
||||
@ -262,6 +279,7 @@ impl JsonHandler {
|
||||
GET_ACCOUNTS_NONCES => self.process_get_accounts_nonces(request).await,
|
||||
GET_ACCOUNT => self.process_get_account(request).await,
|
||||
GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await,
|
||||
GET_PROOF_FOR_COMMITMENT => self.process_get_proof_by_commitment(request).await,
|
||||
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
|
||||
}
|
||||
}
|
||||
@ -320,6 +338,7 @@ mod tests {
|
||||
block_create_timeout_millis: 1000,
|
||||
port: 8080,
|
||||
initial_accounts,
|
||||
initial_commitments: vec![],
|
||||
signing_key: *sequencer_sign_key_for_testing().value(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,9 @@ tempfile.workspace = true
|
||||
clap.workspace = true
|
||||
nssa-core = { path = "../nssa/core" }
|
||||
base64.workspace = true
|
||||
k256 = { version = "0.13.3" }
|
||||
bytemuck = "1.23.2"
|
||||
hex.workspace = true
|
||||
|
||||
[dependencies.key_protocol]
|
||||
path = "../key_protocol"
|
||||
|
||||
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use anyhow::Result;
|
||||
use key_protocol::key_protocol_core::NSSAUserData;
|
||||
|
||||
use crate::config::{PersistentAccountData, WalletConfig};
|
||||
use crate::config::{InitialAccountData, PersistentAccountData, WalletConfig};
|
||||
|
||||
pub struct WalletChainStore {
|
||||
pub user_data: NSSAUserData,
|
||||
@ -12,23 +12,50 @@ pub struct WalletChainStore {
|
||||
|
||||
impl WalletChainStore {
|
||||
pub fn new(config: WalletConfig) -> Result<Self> {
|
||||
let accounts_keys: HashMap<nssa::Address, nssa::PrivateKey> = config
|
||||
.initial_accounts
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|init_acc_data| (init_acc_data.address, init_acc_data.pub_sign_key))
|
||||
.collect();
|
||||
let mut public_init_acc_map = HashMap::new();
|
||||
let mut private_init_acc_map = HashMap::new();
|
||||
|
||||
for init_acc_data in config.initial_accounts.clone() {
|
||||
match init_acc_data {
|
||||
InitialAccountData::Public(data) => {
|
||||
public_init_acc_map.insert(data.address, data.pub_sign_key);
|
||||
}
|
||||
InitialAccountData::Private(data) => {
|
||||
private_init_acc_map.insert(data.address, (data.key_chain, data.account));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
user_data: NSSAUserData::new_with_accounts(accounts_keys, HashMap::new())?,
|
||||
user_data: NSSAUserData::new_with_accounts(public_init_acc_map, private_init_acc_map)?,
|
||||
wallet_config: config,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn insert_account_data(&mut self, acc_data: PersistentAccountData) {
|
||||
pub fn insert_private_account_data(
|
||||
&mut self,
|
||||
addr: nssa::Address,
|
||||
account: nssa_core::account::Account,
|
||||
) {
|
||||
self.user_data
|
||||
.pub_account_signing_keys
|
||||
.insert(acc_data.address, acc_data.pub_sign_key);
|
||||
.user_private_accounts
|
||||
.entry(addr)
|
||||
.and_modify(|(_, acc)| *acc = account);
|
||||
}
|
||||
|
||||
pub(crate) fn insert_account_data(&mut self, acc_data: PersistentAccountData) {
|
||||
match acc_data {
|
||||
PersistentAccountData::Public(acc_data) => {
|
||||
self.user_data
|
||||
.pub_account_signing_keys
|
||||
.insert(acc_data.address, acc_data.pub_sign_key);
|
||||
}
|
||||
PersistentAccountData::Private(acc_data) => {
|
||||
self.user_data
|
||||
.user_private_accounts
|
||||
.insert(acc_data.address, (acc_data.key_chain, acc_data.account));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,24 +69,16 @@ mod tests {
|
||||
|
||||
fn create_initial_accounts() -> Vec<InitialAccountData> {
|
||||
let initial_acc1 = serde_json::from_str(r#"{
|
||||
"address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||
"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],
|
||||
"account": {
|
||||
"program_owner": [0,0,0,0,0,0,0,0],
|
||||
"balance": 100,
|
||||
"nonce": 0,
|
||||
"data": []
|
||||
"Public": {
|
||||
"address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||
"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]
|
||||
}
|
||||
}"#).unwrap();
|
||||
|
||||
let initial_acc2 = serde_json::from_str(r#"{
|
||||
"address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||
"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],
|
||||
"account": {
|
||||
"program_owner": [0,0,0,0,0,0,0,0],
|
||||
"balance": 100,
|
||||
"nonce": 0,
|
||||
"data": []
|
||||
"Public": {
|
||||
"address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||
"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]
|
||||
}
|
||||
}"#).unwrap();
|
||||
|
||||
|
||||
@ -1,19 +1,93 @@
|
||||
use key_protocol::key_management::KeyChain;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InitialAccountData {
|
||||
pub struct InitialAccountDataPublic {
|
||||
pub address: nssa::Address,
|
||||
pub account: nssa_core::account::Account,
|
||||
pub pub_sign_key: nssa::PrivateKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistentAccountData {
|
||||
pub struct PersistentAccountDataPublic {
|
||||
pub address: nssa::Address,
|
||||
pub pub_sign_key: nssa::PrivateKey,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct InitialAccountDataPrivate {
|
||||
pub address: nssa::Address,
|
||||
pub account: nssa_core::account::Account,
|
||||
pub key_chain: KeyChain,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistentAccountDataPrivate {
|
||||
pub address: nssa::Address,
|
||||
pub account: nssa_core::account::Account,
|
||||
pub key_chain: KeyChain,
|
||||
}
|
||||
|
||||
//Big difference in enum variants sizes
|
||||
//however it is improbable, that we will have that much accounts, that it will substantialy affect memory
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum InitialAccountData {
|
||||
Public(InitialAccountDataPublic),
|
||||
Private(InitialAccountDataPrivate),
|
||||
}
|
||||
|
||||
//Big difference in enum variants sizes
|
||||
//however it is improbable, that we will have that much accounts, that it will substantialy affect memory
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PersistentAccountData {
|
||||
Public(PersistentAccountDataPublic),
|
||||
Private(PersistentAccountDataPrivate),
|
||||
}
|
||||
|
||||
impl InitialAccountData {
|
||||
pub fn address(&self) -> nssa::Address {
|
||||
match &self {
|
||||
Self::Public(acc) => acc.address,
|
||||
Self::Private(acc) => acc.address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PersistentAccountData {
|
||||
pub fn address(&self) -> nssa::Address {
|
||||
match &self {
|
||||
Self::Public(acc) => acc.address,
|
||||
Self::Private(acc) => acc.address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InitialAccountDataPublic> for InitialAccountData {
|
||||
fn from(value: InitialAccountDataPublic) -> Self {
|
||||
Self::Public(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InitialAccountDataPrivate> for InitialAccountData {
|
||||
fn from(value: InitialAccountDataPrivate) -> Self {
|
||||
Self::Private(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PersistentAccountDataPublic> for PersistentAccountData {
|
||||
fn from(value: PersistentAccountDataPublic) -> Self {
|
||||
Self::Public(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PersistentAccountDataPrivate> for PersistentAccountData {
|
||||
fn from(value: PersistentAccountDataPrivate) -> Self {
|
||||
Self::Private(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GasConfig {
|
||||
/// Gas spent per deploying one byte of data
|
||||
|
||||
@ -8,7 +8,10 @@ use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
HOME_DIR_ENV_VAR,
|
||||
config::{PersistentAccountData, WalletConfig},
|
||||
config::{
|
||||
PersistentAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic,
|
||||
WalletConfig,
|
||||
},
|
||||
};
|
||||
|
||||
/// Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed.
|
||||
@ -56,10 +59,24 @@ pub fn produce_data_for_storage(user_data: &NSSAUserData) -> Vec<PersistentAccou
|
||||
let mut vec_for_storage = vec![];
|
||||
|
||||
for (addr, key) in &user_data.pub_account_signing_keys {
|
||||
vec_for_storage.push(PersistentAccountData {
|
||||
address: *addr,
|
||||
pub_sign_key: key.clone(),
|
||||
});
|
||||
vec_for_storage.push(
|
||||
PersistentAccountDataPublic {
|
||||
address: *addr,
|
||||
pub_sign_key: key.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
for (addr, (key, acc)) in &user_data.user_private_accounts {
|
||||
vec_for_storage.push(
|
||||
PersistentAccountDataPrivate {
|
||||
address: *addr,
|
||||
account: acc.clone(),
|
||||
key_chain: key.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
vec_for_storage
|
||||
|
||||
@ -11,10 +11,9 @@ use anyhow::Result;
|
||||
use chain_storage::WalletChainStore;
|
||||
use config::WalletConfig;
|
||||
use log::info;
|
||||
use nssa::Address;
|
||||
use nssa::{Account, Address};
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use nssa_core::account::Account;
|
||||
|
||||
use crate::{
|
||||
helperfunctions::{
|
||||
@ -24,12 +23,15 @@ use crate::{
|
||||
poller::TxPoller,
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
pub const HOME_DIR_ENV_VAR: &str = "NSSA_WALLET_HOME_DIR";
|
||||
|
||||
pub mod chain_storage;
|
||||
pub mod config;
|
||||
pub mod helperfunctions;
|
||||
pub mod poller;
|
||||
pub mod token_transfers;
|
||||
|
||||
pub struct WalletCore {
|
||||
pub storage: WalletChainStore,
|
||||
@ -72,19 +74,16 @@ impl WalletCore {
|
||||
Ok(accs_path)
|
||||
}
|
||||
|
||||
pub fn create_new_account(&mut self) -> Address {
|
||||
pub fn create_new_account_public(&mut self) -> Address {
|
||||
self.storage
|
||||
.user_data
|
||||
.generate_new_public_transaction_private_key()
|
||||
}
|
||||
|
||||
pub fn search_for_initial_account(&self, acc_addr: Address) -> Option<Account> {
|
||||
for initial_acc in &self.storage.wallet_config.initial_accounts {
|
||||
if initial_acc.address == acc_addr {
|
||||
return Some(initial_acc.account.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
pub fn create_new_account_private(&mut self) -> Address {
|
||||
self.storage
|
||||
.user_data
|
||||
.generate_new_privacy_preserving_transaction_key_chain()
|
||||
}
|
||||
|
||||
pub async fn claim_pinata(
|
||||
@ -105,48 +104,6 @@ impl WalletCore {
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
|
||||
pub async fn send_public_native_token_transfer(
|
||||
&self,
|
||||
from: Address,
|
||||
to: Address,
|
||||
balance_to_move: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let Ok(balance) = self.get_account_balance(from).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
|
||||
if balance >= balance_to_move {
|
||||
let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
|
||||
let addresses = vec![from, to];
|
||||
let program_id = nssa::program::Program::authenticated_transfer_program().id();
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
addresses,
|
||||
nonces,
|
||||
balance_to_move,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_new_token_definition(
|
||||
&self,
|
||||
definition_address: Address,
|
||||
@ -229,7 +186,7 @@ impl WalletCore {
|
||||
}
|
||||
|
||||
///Poll transactions
|
||||
pub async fn poll_public_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
|
||||
pub async fn poll_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
|
||||
let transaction_encoded = self.poller.poll_tx(hash).await?;
|
||||
let tx_base64_decode = BASE64.decode(transaction_encoded)?;
|
||||
let pub_tx = EncodedTransaction::from_bytes(tx_base64_decode);
|
||||
@ -243,7 +200,9 @@ impl WalletCore {
|
||||
#[clap(about)]
|
||||
pub enum Command {
|
||||
///Send native token transfer from `from` to `to` for `amount`
|
||||
SendNativeTokenTransfer {
|
||||
///
|
||||
/// Public operation
|
||||
SendNativeTokenTransferPublic {
|
||||
///from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
@ -254,8 +213,98 @@ pub enum Command {
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
///Register new account
|
||||
RegisterAccount {},
|
||||
///Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Private operation
|
||||
SendNativeTokenTransferPrivate {
|
||||
///from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
///to - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
///amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
///Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Private operation
|
||||
SendNativeTokenTransferPrivateForeignAccount {
|
||||
///from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
///to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: String,
|
||||
///to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: String,
|
||||
///amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
///Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Deshielded operation
|
||||
SendNativeTokenTransferDeshielded {
|
||||
///from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
///to - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
///amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
///Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Shielded operation
|
||||
SendNativeTokenTransferShielded {
|
||||
///from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
///to - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to: String,
|
||||
///amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
///Send native token transfer from `from` to `to` for `amount`
|
||||
///
|
||||
/// Shielded operation
|
||||
SendNativeTokenTransferShieldedForeignAccount {
|
||||
///from - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
from: String,
|
||||
///to_npk - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
to_npk: String,
|
||||
///to_ipk - valid 33 byte hex string
|
||||
#[arg(long)]
|
||||
to_ipk: String,
|
||||
///amount - amount of balance to move
|
||||
#[arg(long)]
|
||||
amount: u128,
|
||||
},
|
||||
///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id`
|
||||
ClaimPrivateAccount {
|
||||
///tx_hash - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
tx_hash: String,
|
||||
///acc_addr - valid 32 byte hex string
|
||||
#[arg(long)]
|
||||
acc_addr: String,
|
||||
///ciph_id - id of cipher in transaction
|
||||
#[arg(long)]
|
||||
ciph_id: usize,
|
||||
},
|
||||
///Register new public account
|
||||
RegisterAccountPublic {},
|
||||
///Register new private account
|
||||
RegisterAccountPrivate {},
|
||||
///Fetch transaction by `hash`
|
||||
FetchTx {
|
||||
#[arg(short, long)]
|
||||
@ -320,12 +369,19 @@ pub struct Args {
|
||||
pub command: Command,
|
||||
}
|
||||
|
||||
pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SubcommandReturnValue {
|
||||
PrivacyPreservingTransfer { tx_hash: String },
|
||||
RegisterAccount { addr: nssa::Address },
|
||||
Empty,
|
||||
}
|
||||
|
||||
pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> {
|
||||
let wallet_config = fetch_config()?;
|
||||
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config)?;
|
||||
|
||||
match command {
|
||||
Command::SendNativeTokenTransfer { from, to, amount } => {
|
||||
let subcommand_ret = match command {
|
||||
Command::SendNativeTokenTransferPublic { from, to, amount } => {
|
||||
let from = produce_account_addr_from_hex(from)?;
|
||||
let to = produce_account_addr_from_hex(to)?;
|
||||
|
||||
@ -335,17 +391,336 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
|
||||
println!("Results of tx send is {res:#?}");
|
||||
|
||||
let transfer_tx = wallet_core
|
||||
.poll_public_native_token_transfer(res.tx_hash)
|
||||
.await?;
|
||||
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_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::RegisterAccount {} => {
|
||||
let addr = wallet_core.create_new_account();
|
||||
wallet_core.store_persistent_accounts()?;
|
||||
Command::SendNativeTokenTransferPrivate { from, to, amount } => {
|
||||
let from = produce_account_addr_from_hex(from)?;
|
||||
let to = produce_account_addr_from_hex(to)?;
|
||||
|
||||
let (res, secret) = wallet_core
|
||||
.send_private_native_token_transfer(from, to, amount)
|
||||
.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 from_ebc = tx.message.encrypted_private_post_states[0].clone();
|
||||
let from_comm = tx.message.new_commitments[0].clone();
|
||||
|
||||
let to_ebc = tx.message.encrypted_private_post_states[1].clone();
|
||||
let to_comm = tx.message.new_commitments[1].clone();
|
||||
|
||||
let res_acc_from = nssa_core::EncryptionScheme::decrypt(
|
||||
&from_ebc.ciphertext,
|
||||
&secret,
|
||||
&from_comm,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let res_acc_to =
|
||||
nssa_core::EncryptionScheme::decrypt(&to_ebc.ciphertext, &secret, &to_comm, 1)
|
||||
.unwrap();
|
||||
|
||||
println!("Received new from acc {res_acc_from:#?}");
|
||||
println!("Received new to acc {res_acc_to:#?}");
|
||||
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(from, res_acc_from);
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(to, res_acc_to);
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
||||
}
|
||||
Command::SendNativeTokenTransferPrivateForeignAccount {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
} => {
|
||||
let from = produce_account_addr_from_hex(from)?;
|
||||
let to_npk_res = hex::decode(to_npk)?;
|
||||
let mut to_npk = [0; 32];
|
||||
to_npk.copy_from_slice(&to_npk_res);
|
||||
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
||||
|
||||
let to_ipk_res = hex::decode(to_ipk)?;
|
||||
let mut to_ipk = [0u8; 33];
|
||||
to_ipk.copy_from_slice(&to_ipk_res);
|
||||
let to_ipk =
|
||||
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
||||
|
||||
let (res, secret) = wallet_core
|
||||
.send_private_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
|
||||
.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 from_ebc = tx.message.encrypted_private_post_states[0].clone();
|
||||
let from_comm = tx.message.new_commitments[0].clone();
|
||||
|
||||
let to_ebc = tx.message.encrypted_private_post_states[1].clone();
|
||||
let to_comm = tx.message.new_commitments[1].clone();
|
||||
|
||||
let res_acc_from = nssa_core::EncryptionScheme::decrypt(
|
||||
&from_ebc.ciphertext,
|
||||
&secret,
|
||||
&from_comm,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let res_acc_to =
|
||||
nssa_core::EncryptionScheme::decrypt(&to_ebc.ciphertext, &secret, &to_comm, 1)
|
||||
.unwrap();
|
||||
|
||||
println!("RES acc {res_acc_from:#?}");
|
||||
println!("RES acc to {res_acc_to:#?}");
|
||||
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(from, res_acc_from);
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
||||
}
|
||||
Command::SendNativeTokenTransferDeshielded { from, to, amount } => {
|
||||
let from = produce_account_addr_from_hex(from)?;
|
||||
let to = produce_account_addr_from_hex(to)?;
|
||||
|
||||
let (res, secret) = wallet_core
|
||||
.send_deshielded_native_token_transfer(from, to, amount)
|
||||
.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 from_ebc = tx.message.encrypted_private_post_states[0].clone();
|
||||
let from_comm = tx.message.new_commitments[0].clone();
|
||||
|
||||
let res_acc_from = nssa_core::EncryptionScheme::decrypt(
|
||||
&from_ebc.ciphertext,
|
||||
&secret,
|
||||
&from_comm,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("RES acc {res_acc_from:#?}");
|
||||
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.insert_private_account_data(from, res_acc_from);
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
||||
}
|
||||
Command::SendNativeTokenTransferShielded { from, to, amount } => {
|
||||
let from = produce_account_addr_from_hex(from)?;
|
||||
let to = produce_account_addr_from_hex(to)?;
|
||||
|
||||
let (res, secret) = wallet_core
|
||||
.send_shiedled_native_token_transfer(from, to, amount)
|
||||
.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 to_ebc = tx.message.encrypted_private_post_states[0].clone();
|
||||
let to_comm = tx.message.new_commitments[0].clone();
|
||||
|
||||
let res_acc_to =
|
||||
nssa_core::EncryptionScheme::decrypt(&to_ebc.ciphertext, &secret, &to_comm, 0)
|
||||
.unwrap();
|
||||
|
||||
println!("RES acc to {res_acc_to:#?}");
|
||||
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
||||
}
|
||||
Command::SendNativeTokenTransferShieldedForeignAccount {
|
||||
from,
|
||||
to_npk,
|
||||
to_ipk,
|
||||
amount,
|
||||
} => {
|
||||
let from = produce_account_addr_from_hex(from)?;
|
||||
|
||||
let to_npk_res = hex::decode(to_npk)?;
|
||||
let mut to_npk = [0; 32];
|
||||
to_npk.copy_from_slice(&to_npk_res);
|
||||
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
||||
|
||||
let to_ipk_res = hex::decode(to_ipk)?;
|
||||
let mut to_ipk = [0u8; 33];
|
||||
to_ipk.copy_from_slice(&to_ipk_res);
|
||||
let to_ipk =
|
||||
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
||||
|
||||
let (res, secret) = wallet_core
|
||||
.send_shielded_native_token_transfer_maybe_outer_account(
|
||||
from, to_npk, to_ipk, amount,
|
||||
)
|
||||
.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 to_ebc = tx.message.encrypted_private_post_states[0].clone();
|
||||
let to_comm = tx.message.new_commitments[0].clone();
|
||||
|
||||
let res_acc_to =
|
||||
nssa_core::EncryptionScheme::decrypt(&to_ebc.ciphertext, &secret, &to_comm, 0)
|
||||
.unwrap();
|
||||
|
||||
println!("RES acc to {res_acc_to:#?}");
|
||||
|
||||
println!("Transaction data is {:?}", tx.message);
|
||||
}
|
||||
|
||||
let path = wallet_core.store_persistent_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
||||
}
|
||||
Command::ClaimPrivateAccount {
|
||||
tx_hash,
|
||||
acc_addr,
|
||||
ciph_id,
|
||||
} => {
|
||||
let acc_addr = produce_account_addr_from_hex(acc_addr)?;
|
||||
|
||||
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()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::RegisterAccountPublic {} => {
|
||||
let addr = wallet_core.create_new_account_public();
|
||||
|
||||
println!("Generated new account with addr {addr}");
|
||||
|
||||
let path = wallet_core.store_persistent_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::RegisterAccount { addr }
|
||||
}
|
||||
Command::RegisterAccountPrivate {} => {
|
||||
let addr = wallet_core.create_new_account_private();
|
||||
|
||||
let (key, account) = wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account(&addr)
|
||||
.unwrap();
|
||||
|
||||
println!("Generated new account with addr {addr:#?}");
|
||||
println!("With key {key:#?}");
|
||||
println!("With account {account:#?}");
|
||||
|
||||
let path = wallet_core.store_persistent_accounts()?;
|
||||
|
||||
println!("Stored persistent accounts at {path:#?}");
|
||||
|
||||
SubcommandReturnValue::RegisterAccount { addr }
|
||||
}
|
||||
Command::FetchTx { tx_hash } => {
|
||||
let tx_obj = wallet_core
|
||||
@ -354,23 +729,31 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
.await?;
|
||||
|
||||
println!("Transaction object {tx_obj:#?}");
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::GetAccountBalance { addr } => {
|
||||
let addr = Address::from_str(&addr)?;
|
||||
|
||||
let balance = wallet_core.get_account_balance(addr).await?;
|
||||
println!("Accounts {addr} balance is {balance}");
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::GetAccountNonce { addr } => {
|
||||
let addr = Address::from_str(&addr)?;
|
||||
|
||||
let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0];
|
||||
println!("Accounts {addr} nonce is {nonce}");
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::GetAccount { addr } => {
|
||||
let addr: Address = addr.parse()?;
|
||||
let account: HumanReadableAccount = wallet_core.get_account(addr).await?.into();
|
||||
println!("{}", serde_json::to_string(&account).unwrap());
|
||||
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::CreateNewToken {
|
||||
definition_addr,
|
||||
@ -393,6 +776,7 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
total_supply,
|
||||
)
|
||||
.await?;
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::TransferToken {
|
||||
sender_addr,
|
||||
@ -406,6 +790,7 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
balance_to_move,
|
||||
)
|
||||
.await?;
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
Command::ClaimPinata {
|
||||
pinata_addr,
|
||||
@ -420,8 +805,10 @@ pub async fn execute_subcommand(command: Command) -> Result<()> {
|
||||
)
|
||||
.await?;
|
||||
info!("Results of tx send is {res:#?}");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
SubcommandReturnValue::Empty
|
||||
}
|
||||
};
|
||||
|
||||
Ok(subcommand_ret)
|
||||
}
|
||||
|
||||
102
wallet/src/token_transfers/deshielded.rs
Normal file
102
wallet/src/token_transfers/deshielded.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use k256::elliptic_curve::rand_core::{OsRng, RngCore};
|
||||
use nssa::Address;
|
||||
use nssa_core::{SharedSecretKey, encryption::EphemeralPublicKey};
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_deshielded_native_token_transfer(
|
||||
&self,
|
||||
from: Address,
|
||||
to: Address,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> {
|
||||
let from_data = self.storage.user_data.get_private_account(&from).cloned();
|
||||
let to_data = self.get_account(to).await;
|
||||
|
||||
let Some((from_keys, mut from_acc)) = from_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let Ok(to_acc) = to_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
if from_acc.balance >= balance_to_move {
|
||||
let program = nssa::program::Program::authenticated_transfer_program();
|
||||
|
||||
from_acc.program_owner = program.id();
|
||||
|
||||
let sender_commitment =
|
||||
nssa_core::Commitment::new(&from_keys.nullifer_public_key, &from_acc);
|
||||
|
||||
let sender_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: from_acc.clone(),
|
||||
is_authorized: true,
|
||||
account_id: (&from_keys.nullifer_public_key).into(),
|
||||
};
|
||||
let recipient_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: to_acc.clone(),
|
||||
is_authorized: false,
|
||||
account_id: (&to).into(),
|
||||
};
|
||||
|
||||
//Move into different function
|
||||
let mut esk = [0; 32];
|
||||
OsRng.fill_bytes(&mut esk);
|
||||
let shared_secret = SharedSecretKey::new(&esk, &from_keys.incoming_viewing_public_key);
|
||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 0],
|
||||
&[from_acc.nonce + 1],
|
||||
&[(from_keys.nullifer_public_key.clone(), shared_secret.clone())],
|
||||
&[(
|
||||
from_keys.private_key_holder.nullifier_secret_key,
|
||||
self.sequencer_client
|
||||
.get_proof_for_commitment(sender_commitment)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
)],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
vec![to],
|
||||
vec![],
|
||||
vec![(
|
||||
from_keys.nullifer_public_key.clone(),
|
||||
from_keys.incoming_viewing_public_key.clone(),
|
||||
epk,
|
||||
)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&[],
|
||||
);
|
||||
|
||||
let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new(
|
||||
message,
|
||||
witness_set,
|
||||
);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
shared_secret,
|
||||
))
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
wallet/src/token_transfers/mod.rs
Normal file
4
wallet/src/token_transfers/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod deshielded;
|
||||
pub mod private;
|
||||
pub mod public;
|
||||
pub mod shielded;
|
||||
234
wallet/src/token_transfers/private.rs
Normal file
234
wallet/src/token_transfers/private.rs
Normal file
@ -0,0 +1,234 @@
|
||||
use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use nssa::Address;
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_private_native_token_transfer_outer_account(
|
||||
&self,
|
||||
from: Address,
|
||||
to_npk: nssa_core::NullifierPublicKey,
|
||||
to_ipk: nssa_core::encryption::IncomingViewingPublicKey,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> {
|
||||
let from_data = self.storage.user_data.get_private_account(&from).cloned();
|
||||
|
||||
let Some((from_keys, mut from_acc)) = from_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let to_acc = nssa_core::account::Account::default();
|
||||
|
||||
if from_acc.balance >= balance_to_move {
|
||||
let program = nssa::program::Program::authenticated_transfer_program();
|
||||
|
||||
from_acc.program_owner = program.id();
|
||||
|
||||
let sender_commitment =
|
||||
nssa_core::Commitment::new(&from_keys.nullifer_public_key, &from_acc);
|
||||
|
||||
let sender_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: from_acc.clone(),
|
||||
is_authorized: true,
|
||||
account_id: (&from_keys.nullifer_public_key).into(),
|
||||
};
|
||||
|
||||
let recipient_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: to_acc.clone(),
|
||||
is_authorized: false,
|
||||
account_id: (&to_npk).into(),
|
||||
};
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(
|
||||
to_npk.clone(),
|
||||
from_keys.private_key_holder.outgoing_viewing_secret_key,
|
||||
from_acc.nonce.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let shared_secret = eph_holder.calculate_shared_secret_sender(to_ipk.clone());
|
||||
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 2],
|
||||
&[from_acc.nonce + 1, to_acc.nonce + 1],
|
||||
&[
|
||||
(from_keys.nullifer_public_key.clone(), shared_secret.clone()),
|
||||
(to_npk.clone(), shared_secret.clone()),
|
||||
],
|
||||
&[(
|
||||
from_keys.private_key_holder.nullifier_secret_key,
|
||||
self.sequencer_client
|
||||
.get_proof_for_commitment(sender_commitment)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
)],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
vec![],
|
||||
vec![],
|
||||
vec![
|
||||
(
|
||||
from_keys.nullifer_public_key.clone(),
|
||||
from_keys.incoming_viewing_public_key.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
),
|
||||
(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
),
|
||||
],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&[],
|
||||
);
|
||||
|
||||
let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new(
|
||||
message,
|
||||
witness_set,
|
||||
);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
shared_secret,
|
||||
))
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_private_native_token_transfer(
|
||||
&self,
|
||||
from: Address,
|
||||
to: Address,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> {
|
||||
let from_data = self.storage.user_data.get_private_account(&from).cloned();
|
||||
let to_data = self.storage.user_data.get_private_account(&to).cloned();
|
||||
|
||||
let Some((from_keys, mut from_acc)) = from_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let Some((to_keys, mut to_acc)) = to_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let to_npk = to_keys.nullifer_public_key.clone();
|
||||
let to_ipk = to_keys.incoming_viewing_public_key.clone();
|
||||
|
||||
if from_acc.balance >= balance_to_move {
|
||||
let program = nssa::program::Program::authenticated_transfer_program();
|
||||
|
||||
from_acc.program_owner = program.id();
|
||||
to_acc.program_owner = program.id();
|
||||
|
||||
let sender_commitment =
|
||||
nssa_core::Commitment::new(&from_keys.nullifer_public_key, &from_acc);
|
||||
let receiver_commitment =
|
||||
nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc);
|
||||
|
||||
let sender_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: from_acc.clone(),
|
||||
is_authorized: true,
|
||||
account_id: (&from_keys.nullifer_public_key).into(),
|
||||
};
|
||||
let recipient_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: to_acc.clone(),
|
||||
is_authorized: true,
|
||||
account_id: (&to_npk).into(),
|
||||
};
|
||||
|
||||
let eph_holder = EphemeralKeyHolder::new(
|
||||
to_npk.clone(),
|
||||
from_keys.private_key_holder.outgoing_viewing_secret_key,
|
||||
from_acc.nonce.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let shared_secret = eph_holder.calculate_shared_secret_sender(to_ipk.clone());
|
||||
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 1],
|
||||
&[from_acc.nonce + 1, to_acc.nonce + 1],
|
||||
&[
|
||||
(from_keys.nullifer_public_key.clone(), shared_secret.clone()),
|
||||
(to_npk.clone(), shared_secret.clone()),
|
||||
],
|
||||
&[
|
||||
(
|
||||
from_keys.private_key_holder.nullifier_secret_key,
|
||||
self.sequencer_client
|
||||
.get_proof_for_commitment(sender_commitment)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
),
|
||||
(
|
||||
to_keys.private_key_holder.nullifier_secret_key,
|
||||
self.sequencer_client
|
||||
.get_proof_for_commitment(receiver_commitment)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
),
|
||||
],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
vec![],
|
||||
vec![],
|
||||
vec![
|
||||
(
|
||||
from_keys.nullifer_public_key.clone(),
|
||||
from_keys.incoming_viewing_public_key.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
),
|
||||
(
|
||||
to_npk.clone(),
|
||||
to_ipk.clone(),
|
||||
eph_holder.generate_ephemeral_public_key(),
|
||||
),
|
||||
],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&[],
|
||||
);
|
||||
|
||||
let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new(
|
||||
message,
|
||||
witness_set,
|
||||
);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
shared_secret,
|
||||
))
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
}
|
||||
48
wallet/src/token_transfers/public.rs
Normal file
48
wallet/src/token_transfers/public.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use nssa::Address;
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_public_native_token_transfer(
|
||||
&self,
|
||||
from: Address,
|
||||
to: Address,
|
||||
balance_to_move: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let Ok(balance) = self.get_account_balance(from).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
|
||||
if balance >= balance_to_move {
|
||||
let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else {
|
||||
return Err(ExecutionFailureKind::SequencerError);
|
||||
};
|
||||
|
||||
let addresses = vec![from, to];
|
||||
let program_id = nssa::program::Program::authenticated_transfer_program().id();
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program_id,
|
||||
addresses,
|
||||
nonces,
|
||||
balance_to_move,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set =
|
||||
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.sequencer_client.send_tx_public(tx).await?)
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
}
|
||||
181
wallet/src/token_transfers/shielded.rs
Normal file
181
wallet/src/token_transfers/shielded.rs
Normal file
@ -0,0 +1,181 @@
|
||||
use common::{ExecutionFailureKind, sequencer_client::json::SendTxResponse};
|
||||
use key_protocol::key_management::ephemeral_key_holder::produce_one_sided_shared_secret_receiver;
|
||||
use nssa::Address;
|
||||
|
||||
use crate::WalletCore;
|
||||
|
||||
impl WalletCore {
|
||||
pub async fn send_shiedled_native_token_transfer(
|
||||
&self,
|
||||
from: Address,
|
||||
to: Address,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> {
|
||||
let from_data = self.get_account(from).await;
|
||||
let to_data = self.storage.user_data.get_private_account(&to).cloned();
|
||||
|
||||
let Ok(from_acc) = from_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let Some((to_keys, mut to_acc)) = to_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let to_npk = to_keys.nullifer_public_key.clone();
|
||||
let to_ipk = to_keys.incoming_viewing_public_key.clone();
|
||||
|
||||
if from_acc.balance >= balance_to_move {
|
||||
let program = nssa::program::Program::authenticated_transfer_program();
|
||||
|
||||
to_acc.program_owner = program.id();
|
||||
|
||||
let receiver_commitment =
|
||||
nssa_core::Commitment::new(&to_keys.nullifer_public_key, &to_acc);
|
||||
|
||||
let sender_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: from_acc.clone(),
|
||||
is_authorized: true,
|
||||
account_id: (&from).into(),
|
||||
};
|
||||
let recipient_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: to_acc.clone(),
|
||||
is_authorized: true,
|
||||
account_id: (&to_npk).into(),
|
||||
};
|
||||
|
||||
let (shared_secret, epk) = produce_one_sided_shared_secret_receiver(&to_ipk);
|
||||
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[0, 1],
|
||||
&[to_acc.nonce + 1],
|
||||
&[(to_npk.clone(), shared_secret.clone())],
|
||||
&[(
|
||||
to_keys.private_key_holder.nullifier_secret_key,
|
||||
self.sequencer_client
|
||||
.get_proof_for_commitment(receiver_commitment)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
)],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
vec![from],
|
||||
vec![from_acc.nonce],
|
||||
vec![(to_npk.clone(), to_ipk.clone(), epk)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&[signing_key],
|
||||
);
|
||||
|
||||
let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new(
|
||||
message,
|
||||
witness_set,
|
||||
);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
shared_secret,
|
||||
))
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_shielded_native_token_transfer_maybe_outer_account(
|
||||
&self,
|
||||
from: Address,
|
||||
to_npk: nssa_core::NullifierPublicKey,
|
||||
to_ipk: nssa_core::encryption::IncomingViewingPublicKey,
|
||||
balance_to_move: u128,
|
||||
) -> Result<(SendTxResponse, nssa_core::SharedSecretKey), ExecutionFailureKind> {
|
||||
let from_data = self.get_account(from).await;
|
||||
|
||||
let Ok(from_acc) = from_data else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let to_acc = nssa_core::account::Account::default();
|
||||
|
||||
if from_acc.balance >= balance_to_move {
|
||||
let program = nssa::program::Program::authenticated_transfer_program();
|
||||
|
||||
let sender_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: from_acc.clone(),
|
||||
is_authorized: true,
|
||||
account_id: (&from).into(),
|
||||
};
|
||||
|
||||
let recipient_pre = nssa_core::account::AccountWithMetadata {
|
||||
account: to_acc.clone(),
|
||||
is_authorized: false,
|
||||
account_id: (&to_npk).into(),
|
||||
};
|
||||
|
||||
let (shared_secret, epk) = produce_one_sided_shared_secret_receiver(&to_ipk);
|
||||
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[0, 2],
|
||||
&[to_acc.nonce + 1],
|
||||
&[(to_npk.clone(), shared_secret.clone())],
|
||||
&[],
|
||||
&program,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let message =
|
||||
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
|
||||
vec![from],
|
||||
vec![from_acc.nonce],
|
||||
vec![(to_npk.clone(), to_ipk.clone(), epk)],
|
||||
output,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||
|
||||
let Some(signing_key) = signing_key else {
|
||||
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||
};
|
||||
|
||||
let witness_set =
|
||||
nssa::privacy_preserving_transaction::witness_set::WitnessSet::for_message(
|
||||
&message,
|
||||
proof,
|
||||
&[signing_key],
|
||||
);
|
||||
|
||||
let tx = nssa::privacy_preserving_transaction::PrivacyPreservingTransaction::new(
|
||||
message,
|
||||
witness_set,
|
||||
);
|
||||
|
||||
Ok((
|
||||
self.sequencer_client.send_tx_private(tx).await?,
|
||||
shared_secret,
|
||||
))
|
||||
} else {
|
||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user