123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- use git2::{Cred, RemoteCallbacks};
- use itertools::Itertools;
- use near_client::{
- client::{NearClient, Signer},
- types::{
- crypto::{ED25519PublicKey, ED25519SecretKey, Key},
- near::{ViewAccessKey, ViewAccessKeyResult},
- },
- };
- use rand::{RngCore, SeedableRng};
- use rand_chacha::ChaChaRng;
- use reqwest::Url;
- use serde_json::json;
- use std::{
- fs::{create_dir, read, write},
- path::Path,
- str::FromStr,
- };
- use workspaces::{network::Sandbox, types::SecretKey, AccountId, Worker};
-
- // auxiliary structs and methods
- fn near_client(worker: &Worker<Sandbox>) -> anyhow::Result<NearClient> {
- let rpc_url = Url::parse(format!("http://localhost:{}", worker.rpc_port()).as_str())?;
- let client = NearClient::new(rpc_url)?;
- Ok(client)
- }
-
- async fn create_signer(
- worker: &Worker<Sandbox>,
- client: &NearClient,
- signer_acc_id: &AccountId,
- ) -> anyhow::Result<Signer> {
- let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
- let ws_secret_key_str = to_workspaces_sk(&secret_key);
- let pk = ED25519PublicKey::from(&secret_key);
- let ws_sk = SecretKey::from_str(&ws_secret_key_str)?;
- let _ = worker.create_tla(signer_acc_id.clone(), ws_sk).await?;
-
- client
- .view_access_key(signer_acc_id, &pk)
- .await
- .map(|access_key_view| match access_key_view.result {
- ViewAccessKeyResult::Ok { nonce, .. } => {
- let signer_acc = Signer::new(&ws_secret_key_str, signer_acc_id.clone(), nonce)?;
- Ok(signer_acc)
- }
- ViewAccessKeyResult::Err { error, .. } => Err(anyhow::anyhow!(error)),
- })?
- }
-
- async fn download_contract() -> anyhow::Result<Vec<u8>> {
- let target = "https://github.com/near-examples/FT/raw/master/res/fungible_token.wasm";
- let target_path = "../target/tmp-contracts";
- let fname = "contract.wasm";
- let full_dest = format!("{}/{}", target_path, fname);
-
- let contract_bytes = if !Path::new(&full_dest).exists() {
- if !Path::new(&target_path).exists() {
- create_dir(target_path)?;
- };
-
- let contract_bytes = reqwest::get(target).await?.bytes().await?;
- write(full_dest, &contract_bytes)?;
- contract_bytes.to_vec()
- } else {
- read(&full_dest)?
- };
-
- Ok(contract_bytes)
- }
-
- async fn clone_and_compile_wasm() -> anyhow::Result<Vec<u8>> {
- let tmp_path = "../target/tmp-contracts";
- let repo_path = format!("{}/near-smartcontracts", tmp_path);
- let target_path = format!("{}/test-contract", repo_path);
- let repo_url = "git@github.com:Relayz-io/near-smartcontracts.git";
-
- if !Path::new(&target_path).exists() {
- if !Path::new(&tmp_path).exists() {
- create_dir(tmp_path)?;
- }
-
- // Prepare callbacks.
- let mut callbacks = RemoteCallbacks::new();
- callbacks.credentials(|_, username_from_url, _| {
- let username = username_from_url
- .ok_or_else(|| git2::Error::from_str("Parsing the given URL is failed"))?;
- Cred::ssh_key_from_agent(username)
- });
-
- // Prepare fetch options.
- let mut fo = git2::FetchOptions::new();
- fo.remote_callbacks(callbacks);
-
- // Prepare builder.
- let mut builder = git2::build::RepoBuilder::new();
- builder.fetch_options(fo);
- builder.branch("main");
-
- // Clone the project.
- builder.clone(repo_url, Path::new(&repo_path))?;
- }
- let wasm = workspaces::compile_project(&target_path).await?;
-
- Ok(wasm)
- }
-
- fn random_bits() -> [u8; 32] {
- let mut chacha = ChaChaRng::from_entropy();
- let mut secret_bytes = [0_u8; 32];
- chacha.fill_bytes(&mut secret_bytes);
- secret_bytes
- }
-
- fn to_workspaces_sk(sk: &ED25519SecretKey) -> String {
- let pk = ED25519PublicKey::from(sk);
- let keypair = sk
- .as_bytes()
- .iter()
- .chain(pk.as_bytes().iter())
- .copied()
- .collect_vec();
- format!("ed25519:{}", bs58::encode(keypair).into_string())
- }
-
- // tests themselves
- #[tokio::test]
- async fn contract_creation() -> anyhow::Result<()> {
- let worker = workspaces::sandbox().await?;
- let client = near_client(&worker)?;
- let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
- let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
- let wasm = download_contract().await?;
-
- client
- .deploy_contract(&mut signer, &signer_account_id, wasm)
- .commit_empty()
- .await?;
-
- Ok(())
- }
-
- #[tokio::test]
- async fn contract_function_call() -> anyhow::Result<()> {
- let worker = workspaces::sandbox().await?;
- let client = near_client(&worker)?;
- let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
- let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
- let wasm = download_contract().await?;
-
- client
- .deploy_contract(&mut signer, &signer_account_id, wasm)
- .commit_empty()
- .await?;
-
- client
- .function_call(&mut signer, &signer_account_id, "new_default_meta")
- .args(json!({
- "owner_id": &signer_account_id,
- "total_supply": "100",
- }))
- .gas(near_units::parse_gas!("300 T") as u64)
- .build()?
- .commit_empty()
- .await?;
-
- Ok(())
- }
-
- #[tokio::test]
- async fn multiple_tests() -> anyhow::Result<()> {
- let worker = workspaces::sandbox().await?;
- let client = near_client(&worker)?;
- let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
- let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
-
- let wasm = clone_and_compile_wasm().await?;
-
- init_contract(&client, &signer_account_id, &mut signer, wasm).await?;
-
- fc_no_params(&client, &signer_account_id, &mut signer).await?;
- fc_with_one_param_and_result(&client, &signer_account_id, &mut signer).await?;
- fc_with_param_and_result(&client, &signer_account_id, &mut signer).await?;
-
- view_no_params(&client, &signer_account_id).await?;
- view_with_params(&client, &signer_account_id).await?;
-
- Ok(())
- }
-
- async fn init_contract(
- client: &NearClient,
- contract_id: &AccountId,
- signer: &mut Signer,
- wasm: Vec<u8>,
- ) -> anyhow::Result<()> {
- client
- .deploy_contract(signer, contract_id, wasm)
- .commit_empty()
- .await?;
-
- Ok(())
- }
-
- async fn view_no_params(client: &NearClient, contract_id: &AccountId) -> anyhow::Result<()> {
- client.view::<u64>(contract_id, "show_id", None).await?;
-
- Ok(())
- }
-
- async fn view_with_params(client: &NearClient, contract_id: &AccountId) -> anyhow::Result<()> {
- client
- .view::<String>(contract_id, "show_type", Some(json!({"is_message": true})))
- .await?;
-
- Ok(())
- }
-
- // fc = function call
- async fn fc_no_params(
- client: &NearClient,
- contract_id: &AccountId,
- signer: &mut Signer,
- ) -> anyhow::Result<()> {
- client
- .function_call(signer, contract_id, "increment")
- .gas(near_units::parse_gas!("300 T") as u64)
- .build()?
- .commit_empty()
- .await?;
-
- Ok(())
- }
-
- async fn fc_with_one_param_and_result(
- client: &NearClient,
- contract_id: &AccountId,
- signer: &mut Signer,
- ) -> anyhow::Result<()> {
- let expected_result = "change message";
- let message = client
- .function_call(signer, contract_id, "change_message")
- .args(json!({ "message": expected_result }))
- .gas(near_units::parse_gas!("300 T") as u64)
- .build()?
- .commit::<String>()
- .await?;
-
- assert_eq!(message, expected_result);
-
- Ok(())
- }
-
- async fn fc_with_param_and_result(
- client: &NearClient,
- contract_id: &AccountId,
- signer: &mut Signer,
- ) -> anyhow::Result<()> {
- let expected_id = 666u64;
- let id = client
- .function_call(signer, contract_id, "change_id")
- .args(json!({ "id": expected_id }))
- .gas(near_units::parse_gas!("300 T") as u64)
- .build()?
- .commit::<u64>()
- .await?;
-
- assert_eq!(id, expected_id);
-
- Ok(())
- }
-
- #[tokio::test]
- async fn view_access_key_success() -> anyhow::Result<()> {
- let worker = workspaces::sandbox().await?;
- let client = near_client(&worker)?;
- let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
- let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
-
- let new_acc = AccountId::from_str("one.alice.test.near")?;
- let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
- let pk = ED25519PublicKey::from(&secret_key);
-
- let _ = client
- .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
- .commit::<serde_json::Value>()
- .await?;
-
- let access_key = client.view_access_key(&new_acc, &pk).await?;
- assert!(matches!(
- access_key,
- ViewAccessKey {
- result: ViewAccessKeyResult::Ok { .. },
- ..
- }
- ));
-
- Ok(())
- }
-
- #[tokio::test]
- async fn view_access_key_failure() -> anyhow::Result<()> {
- let worker = workspaces::sandbox().await?;
- let client = near_client(&worker)?;
-
- let new_acc = AccountId::from_str("one.alice.test.near")?;
- let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
- let pk = ED25519PublicKey::from(&secret_key);
-
- let access_key = client.view_access_key(&new_acc, &pk).await?;
- assert!(matches!(
- access_key,
- ViewAccessKey {
- result: ViewAccessKeyResult::Err { .. },
- ..
- }
- ));
-
- Ok(())
- }
-
- #[tokio::test]
- async fn create_account() -> anyhow::Result<()> {
- let worker = workspaces::sandbox().await?;
- let client = near_client(&worker)?;
- let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
- let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
-
- let new_acc = AccountId::from_str("one.alice.test.near")?;
- let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
- let pk = ED25519PublicKey::from(&secret_key);
-
- let _ = client
- .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
- .commit::<serde_json::Value>()
- .await?;
-
- let access_key = client.view_access_key(&new_acc, &pk).await?;
- assert!(matches!(
- access_key,
- ViewAccessKey {
- result: ViewAccessKeyResult::Ok { .. },
- ..
- }
- ));
-
- Ok(())
- }
-
- #[tokio::test]
- async fn delete_account() -> anyhow::Result<()> {
- let worker = workspaces::sandbox().await?;
- let client = near_client(&worker)?;
- let signer_account_id = AccountId::from_str("alice.test.near").unwrap();
- let mut signer = create_signer(&worker, &client, &signer_account_id).await?;
-
- let new_acc = AccountId::from_str("one.alice.test.near")?;
- let secret_key = ED25519SecretKey::from_bytes(&random_bits())?;
- let pk = ED25519PublicKey::from(&secret_key);
-
- client
- .create_account(&mut signer, &new_acc, pk, near_units::parse_near!("3 N"))
- .commit_empty()
- .await?;
-
- let access_key = client.view_access_key(&new_acc, &pk).await?;
-
- let nonce = if let ViewAccessKey {
- result: ViewAccessKeyResult::Ok { nonce, .. },
- ..
- } = access_key
- {
- nonce
- } else {
- panic!("Can't view access key for just created account")
- };
-
- let mut acc_signer = Signer::new(&secret_key.to_string(), new_acc.clone(), nonce)?;
- client
- .delete_account(&mut acc_signer, &new_acc, &signer_account_id)
- .commit_empty()
- .await?;
-
- let access_key = client.view_access_key(&new_acc, &pk).await?;
- assert!(matches!(
- access_key,
- ViewAccessKey {
- result: ViewAccessKeyResult::Err { .. },
- ..
- }
- ));
-
- Ok(())
- }
|