|
@@ -1,3 +1,4 @@
|
|
1
|
+use git2::{Cred, RemoteCallbacks};
|
1
|
2
|
use itertools::Itertools;
|
2
|
3
|
use near_account_id::AccountId;
|
3
|
4
|
use near_client::{
|
|
@@ -9,59 +10,33 @@ use rand_chacha::ChaChaRng;
|
9
|
10
|
use reqwest::Url;
|
10
|
11
|
use serde_json::json;
|
11
|
12
|
use std::{
|
12
|
|
- fs::{create_dir, File},
|
13
|
|
- io::{copy, Cursor, Read},
|
|
13
|
+ fs::{create_dir, read, write},
|
14
|
14
|
path::Path,
|
15
|
15
|
str::FromStr,
|
16
|
16
|
};
|
17
|
17
|
use workspaces::{network::Sandbox, types::SecretKey, Worker};
|
18
|
18
|
|
19
|
19
|
// auxiliary structs and methods
|
20
|
|
-struct InitMeta {
|
21
|
|
- worker: Worker<Sandbox>,
|
22
|
|
- client: NearClient,
|
23
|
|
- wasm: Vec<u8>,
|
24
|
|
- signer_account_id: AccountId,
|
25
|
|
-}
|
26
|
|
-
|
27
|
|
-impl InitMeta {
|
28
|
|
- async fn new() -> anyhow::Result<Self> {
|
29
|
|
- let worker = workspaces::sandbox().await?;
|
30
|
|
- let wasm = download_contract().await?;
|
31
|
|
- let rpc_url = Url::parse(format!("http://localhost:{}", worker.rpc_port()).as_str())?;
|
32
|
|
- let client = NearClient::new(rpc_url)?;
|
33
|
|
- let signer_account_id = AccountId::from_str("alice.test.near")?;
|
34
|
|
-
|
35
|
|
- Ok(InitMeta {
|
36
|
|
- worker,
|
37
|
|
- client,
|
38
|
|
- wasm,
|
39
|
|
- signer_account_id,
|
40
|
|
- })
|
41
|
|
- }
|
|
20
|
+fn near_client(worker: &Worker<Sandbox>) -> anyhow::Result<NearClient> {
|
|
21
|
+ let rpc_url = Url::parse(format!("http://localhost:{}", worker.rpc_port()).as_str())?;
|
|
22
|
+ let client = NearClient::new(rpc_url)?;
|
|
23
|
+ Ok(client)
|
42
|
24
|
}
|
43
|
25
|
|
44
|
|
-async fn create_signer(meta: &InitMeta) -> anyhow::Result<Signer> {
|
|
26
|
+async fn create_signer(
|
|
27
|
+ worker: &Worker<Sandbox>,
|
|
28
|
+ client: &NearClient,
|
|
29
|
+ signer_acc_id: &AccountId,
|
|
30
|
+) -> anyhow::Result<Signer> {
|
45
|
31
|
let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
|
46
|
32
|
let ws_secret_key_str = to_workspaces_sk(&secret_key);
|
47
|
33
|
let pk = ED25519PublicKey::from(&secret_key);
|
48
|
34
|
let ws_sk = SecretKey::from_str(&ws_secret_key_str)?;
|
49
|
|
- let _ = meta
|
50
|
|
- .worker
|
51
|
|
- .create_tla(meta.signer_account_id.clone(), ws_sk)
|
52
|
|
- .await?;
|
|
35
|
+ let _ = worker.create_tla(signer_acc_id.clone(), ws_sk).await?;
|
53
|
36
|
|
54
|
|
- let access_key_nonce = meta
|
55
|
|
- .client
|
56
|
|
- .view_access_key(&meta.signer_account_id, &pk)
|
57
|
|
- .await?
|
58
|
|
- .nonce;
|
|
37
|
+ let access_key_nonce = client.view_access_key(signer_acc_id, &pk).await?.nonce;
|
59
|
38
|
|
60
|
|
- let signer_acc = Signer::new(
|
61
|
|
- &ws_secret_key_str,
|
62
|
|
- meta.signer_account_id.clone(),
|
63
|
|
- access_key_nonce,
|
64
|
|
- )?;
|
|
39
|
+ let signer_acc = Signer::new(&ws_secret_key_str, signer_acc_id.clone(), access_key_nonce)?;
|
65
|
40
|
|
66
|
41
|
Ok(signer_acc)
|
67
|
42
|
}
|
|
@@ -72,22 +47,55 @@ async fn download_contract() -> anyhow::Result<Vec<u8>> {
|
72
|
47
|
let fname = "contract.wasm";
|
73
|
48
|
let full_dest = format!("{}/{}", target_path, fname);
|
74
|
49
|
|
75
|
|
- if !Path::new(target_path).exists() {
|
76
|
|
- create_dir(target_path)?;
|
77
|
|
- }
|
|
50
|
+ let contract_bytes = if !Path::new(&full_dest).exists() {
|
|
51
|
+ if !Path::new(&target_path).exists() {
|
|
52
|
+ create_dir(target_path)?;
|
|
53
|
+ };
|
78
|
54
|
|
79
|
|
- if !Path::new(&full_dest).exists() {
|
80
|
|
- let response = reqwest::get(target).await?;
|
81
|
|
- let mut file = File::create(&full_dest)?;
|
82
|
|
- let mut content = Cursor::new(response.bytes().await?);
|
83
|
|
- copy(&mut content, &mut file)?;
|
84
|
|
- }
|
|
55
|
+ let contract_bytes = reqwest::get(target).await?.bytes().await?;
|
|
56
|
+ write(full_dest, &contract_bytes)?;
|
|
57
|
+ contract_bytes.to_vec()
|
|
58
|
+ } else {
|
|
59
|
+ read(&full_dest)?
|
|
60
|
+ };
|
|
61
|
+
|
|
62
|
+ Ok(contract_bytes)
|
|
63
|
+}
|
|
64
|
+
|
|
65
|
+async fn clone_and_compile_wasm() -> anyhow::Result<Vec<u8>> {
|
|
66
|
+ let tmp_path = "../target/tmp-contracts";
|
|
67
|
+ let repo_path = format!("{}/near-smartcontracts", tmp_path);
|
|
68
|
+ let target_path = format!("{}/test-contract", repo_path);
|
|
69
|
+ let repo_url = "git@github.com:Relayz-io/near-smartcontracts.git";
|
|
70
|
+
|
|
71
|
+ if !Path::new(&target_path).exists() {
|
|
72
|
+ if !Path::new(&tmp_path).exists() {
|
|
73
|
+ create_dir(tmp_path)?;
|
|
74
|
+ }
|
|
75
|
+
|
|
76
|
+ // Prepare callbacks.
|
|
77
|
+ let mut callbacks = RemoteCallbacks::new();
|
|
78
|
+ callbacks.credentials(|_, username_from_url, _| {
|
|
79
|
+ let username = username_from_url
|
|
80
|
+ .ok_or_else(|| git2::Error::from_str("Parsing the given URL is failed"))?;
|
|
81
|
+ Cred::ssh_key_from_agent(username)
|
|
82
|
+ });
|
85
|
83
|
|
86
|
|
- let mut file = File::open(full_dest)?;
|
87
|
|
- let mut data = Vec::new();
|
88
|
|
- file.read_to_end(&mut data)?;
|
|
84
|
+ // Prepare fetch options.
|
|
85
|
+ let mut fo = git2::FetchOptions::new();
|
|
86
|
+ fo.remote_callbacks(callbacks);
|
89
|
87
|
|
90
|
|
- Ok(data)
|
|
88
|
+ // Prepare builder.
|
|
89
|
+ let mut builder = git2::build::RepoBuilder::new();
|
|
90
|
+ builder.fetch_options(fo);
|
|
91
|
+ builder.branch("main");
|
|
92
|
+
|
|
93
|
+ // Clone the project.
|
|
94
|
+ builder.clone(repo_url, Path::new(&repo_path))?;
|
|
95
|
+ }
|
|
96
|
+ let wasm = workspaces::compile_project(&target_path).await?;
|
|
97
|
+
|
|
98
|
+ Ok(wasm)
|
91
|
99
|
}
|
92
|
100
|
|
93
|
101
|
fn random_bits() -> [u8; 32] {
|
|
@@ -111,38 +119,146 @@ fn to_workspaces_sk(sk: &ED25519SecretKey) -> String {
|
111
|
119
|
// tests themselves
|
112
|
120
|
#[tokio::test]
|
113
|
121
|
async fn contract_creation() -> anyhow::Result<()> {
|
114
|
|
- let meta = InitMeta::new().await?;
|
115
|
|
- let mut signer = create_signer(&meta).await?;
|
116
|
|
-
|
117
|
|
- let call = meta
|
118
|
|
- .client
|
119
|
|
- .deploy_contract(&mut signer, &meta.signer_account_id, meta.wasm);
|
|
122
|
+ let worker = workspaces::sandbox().await?;
|
|
123
|
+ let client = near_client(&worker)?;
|
|
124
|
+ let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
|
|
125
|
+ let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
|
|
126
|
+ let wasm = download_contract().await?;
|
120
|
127
|
|
121
|
|
- call.commit_empty().await?;
|
|
128
|
+ client
|
|
129
|
+ .deploy_contract(&mut signer, &signer_account_id, wasm)
|
|
130
|
+ .commit_empty()
|
|
131
|
+ .await?;
|
122
|
132
|
|
123
|
133
|
Ok(())
|
124
|
134
|
}
|
125
|
135
|
|
126
|
136
|
#[tokio::test]
|
127
|
137
|
async fn contract_function_call() -> anyhow::Result<()> {
|
128
|
|
- let meta = InitMeta::new().await?;
|
129
|
|
- let mut signer = create_signer(&meta).await?;
|
|
138
|
+ let worker = workspaces::sandbox().await?;
|
|
139
|
+ let client = near_client(&worker)?;
|
|
140
|
+ let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
|
|
141
|
+ let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
|
|
142
|
+ let wasm = download_contract().await?;
|
130
|
143
|
|
131
|
|
- let call = meta
|
132
|
|
- .client
|
133
|
|
- .deploy_contract(&mut signer, &meta.signer_account_id, meta.wasm);
|
134
|
|
- call.commit_empty().await?;
|
|
144
|
+ client
|
|
145
|
+ .deploy_contract(&mut signer, &signer_account_id, wasm)
|
|
146
|
+ .commit_empty()
|
|
147
|
+ .await?;
|
135
|
148
|
|
136
|
|
- let call = meta
|
137
|
|
- .client
|
138
|
|
- .function_call(&mut signer, &meta.signer_account_id, "new_default_meta")
|
|
149
|
+ client
|
|
150
|
+ .function_call(&mut signer, &signer_account_id, "new_default_meta")
|
139
|
151
|
.args(json!({
|
140
|
|
- "owner_id": &meta.signer_account_id,
|
|
152
|
+ "owner_id": &signer_account_id,
|
141
|
153
|
"total_supply": "100",
|
142
|
154
|
}))
|
143
|
155
|
.gas(near_units::parse_gas!("300 T") as u64)
|
144
|
|
- .build()?;
|
145
|
|
- call.commit_empty().await?;
|
|
156
|
+ .build()?
|
|
157
|
+ .commit_empty()
|
|
158
|
+ .await?;
|
|
159
|
+
|
|
160
|
+ Ok(())
|
|
161
|
+}
|
|
162
|
+
|
|
163
|
+#[tokio::test]
|
|
164
|
+async fn multiple_tests() -> anyhow::Result<()> {
|
|
165
|
+ let worker = workspaces::sandbox().await?;
|
|
166
|
+ let client = near_client(&worker)?;
|
|
167
|
+ let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
|
|
168
|
+ let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
|
|
169
|
+
|
|
170
|
+ let wasm = clone_and_compile_wasm().await?;
|
|
171
|
+
|
|
172
|
+ init_contract(&client, &signer_account_id, &mut signer, wasm).await?;
|
|
173
|
+
|
|
174
|
+ fc_no_params(&client, &signer_account_id, &mut signer).await?;
|
|
175
|
+ fc_with_one_param_and_result(&client, &signer_account_id, &mut signer).await?;
|
|
176
|
+ fc_with_param_and_result(&client, &signer_account_id, &mut signer).await?;
|
|
177
|
+
|
|
178
|
+ view_no_params(&client, &signer_account_id).await?;
|
|
179
|
+ view_with_params(&client, &signer_account_id).await?;
|
|
180
|
+
|
|
181
|
+ Ok(())
|
|
182
|
+}
|
|
183
|
+
|
|
184
|
+async fn init_contract(
|
|
185
|
+ client: &NearClient,
|
|
186
|
+ contract_id: &AccountId,
|
|
187
|
+ signer: &mut Signer,
|
|
188
|
+ wasm: Vec<u8>,
|
|
189
|
+) -> anyhow::Result<()> {
|
|
190
|
+ client
|
|
191
|
+ .deploy_contract(signer, contract_id, wasm)
|
|
192
|
+ .commit_empty()
|
|
193
|
+ .await?;
|
|
194
|
+
|
|
195
|
+ Ok(())
|
|
196
|
+}
|
|
197
|
+
|
|
198
|
+async fn view_no_params(client: &NearClient, contract_id: &AccountId) -> anyhow::Result<()> {
|
|
199
|
+ client.view::<u64>(contract_id, "show_id", None).await?;
|
|
200
|
+
|
|
201
|
+ Ok(())
|
|
202
|
+}
|
|
203
|
+
|
|
204
|
+async fn view_with_params(client: &NearClient, contract_id: &AccountId) -> anyhow::Result<()> {
|
|
205
|
+ client
|
|
206
|
+ .view::<String>(contract_id, "show_type", Some(json!({"is_message": true})))
|
|
207
|
+ .await?;
|
|
208
|
+
|
|
209
|
+ Ok(())
|
|
210
|
+}
|
|
211
|
+
|
|
212
|
+// fc = function call
|
|
213
|
+async fn fc_no_params(
|
|
214
|
+ client: &NearClient,
|
|
215
|
+ contract_id: &AccountId,
|
|
216
|
+ signer: &mut Signer,
|
|
217
|
+) -> anyhow::Result<()> {
|
|
218
|
+ client
|
|
219
|
+ .function_call(signer, contract_id, "increment")
|
|
220
|
+ .gas(near_units::parse_gas!("300 T") as u64)
|
|
221
|
+ .build()?
|
|
222
|
+ .commit_empty()
|
|
223
|
+ .await?;
|
|
224
|
+
|
|
225
|
+ Ok(())
|
|
226
|
+}
|
|
227
|
+
|
|
228
|
+async fn fc_with_one_param_and_result(
|
|
229
|
+ client: &NearClient,
|
|
230
|
+ contract_id: &AccountId,
|
|
231
|
+ signer: &mut Signer,
|
|
232
|
+) -> anyhow::Result<()> {
|
|
233
|
+ let expected_result = "change message";
|
|
234
|
+ let message = client
|
|
235
|
+ .function_call(signer, contract_id, "change_message")
|
|
236
|
+ .args(json!({ "message": expected_result }))
|
|
237
|
+ .gas(near_units::parse_gas!("300 T") as u64)
|
|
238
|
+ .build()?
|
|
239
|
+ .commit::<String>()
|
|
240
|
+ .await?;
|
|
241
|
+
|
|
242
|
+ assert_eq!(message, expected_result);
|
|
243
|
+
|
|
244
|
+ Ok(())
|
|
245
|
+}
|
|
246
|
+
|
|
247
|
+async fn fc_with_param_and_result(
|
|
248
|
+ client: &NearClient,
|
|
249
|
+ contract_id: &AccountId,
|
|
250
|
+ signer: &mut Signer,
|
|
251
|
+) -> anyhow::Result<()> {
|
|
252
|
+ let expected_id = 666u64;
|
|
253
|
+ let id = client
|
|
254
|
+ .function_call(signer, contract_id, "change_id")
|
|
255
|
+ .args(json!({ "id": expected_id }))
|
|
256
|
+ .gas(near_units::parse_gas!("300 T") as u64)
|
|
257
|
+ .build()?
|
|
258
|
+ .commit::<u64>()
|
|
259
|
+ .await?;
|
|
260
|
+
|
|
261
|
+ assert_eq!(id, expected_id);
|
146
|
262
|
|
147
|
263
|
Ok(())
|
148
|
264
|
}
|