Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install Linux dependencies
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libudev-dev pkg-config

- name: Install cargo-near
run: cargo install --locked cargo-near
run: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/cargo-near/releases/latest/download/cargo-near-installer.sh | sh

- name: Install and test modules
run: |
Expand Down
19 changes: 15 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
borsh = "1.5.7"
bs58 = "0.5.1"
near-sdk = { version = "5.17.1", features = ["global-contracts", "unstable"] }
near-sdk = { version = "5.24.0", features = ["global-contracts"] }

[dev-dependencies]
near-sdk = { version = "5.17.1", features = ["global-contracts", "unit-testing"] }
near-workspaces = { version = "0.21", features = ["unstable"] }
tokio = { version = "1.12.0", features = ["full"] }
near-sdk = { version = "5.24.0", features = ["unit-testing"] }
near-sandbox = "0.3"
near-api = "0.8"
cargo-near-build = "=0.10"
tokio = { version = "1.48.0", features = ["full"] }
serde_json = "1"
testresult = "0.4.1"
anyhow = "1.0"
# This is temporary fix for the build error since those crates with a higher version require a higher version of Rust compiler (1.88.0)
cargo-platform = "=0.3.1"
darling = "=0.20.11"
bon = "=3.8.1"
home = "=0.5.9"
time = "=0.3.44"
time-core = "=0.1.6"

[profile.release]
codegen-units = 1
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ impl GlobalFactoryContract {
"Using global contract with code hash: {:?}",
code_hash
));
promise.use_global_contract(bs58::decode(code_hash).into_vec().unwrap())
let code_hash_vec = bs58::decode(code_hash).into_vec().unwrap();
let code_hash_vec_array: [u8; 32] = code_hash_vec.try_into().unwrap();
promise.use_global_contract(code_hash_vec_array)
}
}
}
Expand Down
180 changes: 180 additions & 0 deletions tests/test_basics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use factory_contract_global::GlobalContractId;
use near_api::AccountId;
use near_sdk::{serde_json::json, NearToken};

const DEFAULT_GLOBAL_CONTRACT_ACCOUNT_ID: &str = "ft.globals.primitives.testnet";

const TEST_GLOBAL_CONTRACT_ACCOUNT_ID: &str = "ft.globals.primitives.testnet";
const TEST_GLOBAL_CONTRACT_HASH: &str = "3vaopJ7aRoivvzZLngPQRBEd8VJr2zPLTxQfnRCoFgNX";
const TEST_DEPOSIT_AMOUNT: u128 = 100; // 0.1 NEAR

/// TODO: add tests for deploy method as soon as near-workspaces-rs supports deploying global contracts.
/// Currently it does not, therefore it's impossible to deploy global contract to use it in tests.

/// Test management of global contract ID
#[tokio::test]
async fn test_manager() -> anyhow::Result<()> {
let sandbox = near_sandbox::Sandbox::start_sandbox().await?;
let sandbox_network =
near_api::NetworkConfig::from_rpc_url("sandbox", sandbox.rpc_addr.parse()?);
let factory_wasm_path = cargo_near_build::build_with_cli(Default::default()).unwrap();
let factory_wasm = std::fs::read(factory_wasm_path)?;

let factory_contract = create_subaccount(&sandbox, "factory.sandbox")
.await
.unwrap()
.as_contract();

// Initialize signer for the contract deployment
let signer = near_api::Signer::from_secret_key(
near_sandbox::config::DEFAULT_GENESIS_ACCOUNT_PRIVATE_KEY
.parse()
.unwrap(),
)?;

// Deploy the base contract
near_api::Contract::deploy(factory_contract.account_id().clone())
.use_code(factory_wasm)
.without_init_call()
.with_signer(signer.clone())
.send_to(&sandbox_network)
.await?
.assert_success();

let default_contract_id: GlobalContractId = factory_contract
.call_function("get_global_contract_id", ())
.read_only()
.fetch_from(&sandbox_network)
.await?
.data;
assert_eq!(
default_contract_id,
GlobalContractId::AccountId(DEFAULT_GLOBAL_CONTRACT_ACCOUNT_ID.parse().unwrap())
);

factory_contract
.call_function(
"update_global_contract_id",
json!({
"contract_id": GlobalContractId::CodeHash(TEST_GLOBAL_CONTRACT_HASH.to_string()),
"min_deposit": NearToken::from_millinear(TEST_DEPOSIT_AMOUNT)
}),
)
.transaction()
.max_gas()
.with_signer(factory_contract.account_id().clone(), signer.clone())
.send_to(&sandbox_network)
.await?
.assert_success();

let global_contract_id: GlobalContractId = factory_contract
.call_function("get_global_contract_id", ())
.read_only()
.fetch_from(&sandbox_network)
.await?
.data;
assert_eq!(
global_contract_id,
GlobalContractId::CodeHash(TEST_GLOBAL_CONTRACT_HASH.to_string())
);

factory_contract
.call_function("update_global_contract_id", json!({
"contract_id": GlobalContractId::AccountId(TEST_GLOBAL_CONTRACT_ACCOUNT_ID.parse().unwrap()),
"min_deposit": NearToken::from_millinear(TEST_DEPOSIT_AMOUNT)
}))
.transaction()
.max_gas()
.with_signer(factory_contract.account_id().clone(), signer.clone())
.send_to(&sandbox_network)
.await?
.assert_success();

let global_contract_id: GlobalContractId = factory_contract
.call_function("get_global_contract_id", ())
.read_only()
.fetch_from(&sandbox_network)
.await?
.data;
assert_eq!(
global_contract_id,
GlobalContractId::AccountId(TEST_GLOBAL_CONTRACT_ACCOUNT_ID.parse().unwrap())
);

let min_deposit: NearToken = factory_contract
.call_function("get_min_deposit", ())
.read_only()
.fetch_from(&sandbox_network)
.await?
.data;
assert!(min_deposit.eq(&NearToken::from_millinear(TEST_DEPOSIT_AMOUNT)));
Ok(())
}

/// Test error cases and edge conditions
#[tokio::test]
async fn test_global_contract_edge_cases() -> anyhow::Result<()> {
let sandbox = near_sandbox::Sandbox::start_sandbox().await?;
let sandbox_network =
near_api::NetworkConfig::from_rpc_url("sandbox", sandbox.rpc_addr.parse()?);
let factory_wasm_path = cargo_near_build::build_with_cli(Default::default()).unwrap();
let factory_wasm = std::fs::read(factory_wasm_path)?;

let factory_contract = create_subaccount(&sandbox, "factory.sandbox")
.await
.unwrap()
.as_contract();

// Initialize signer for the contract deployment
let signer = near_api::Signer::from_secret_key(
near_sandbox::config::DEFAULT_GENESIS_ACCOUNT_PRIVATE_KEY
.parse()
.unwrap(),
)?;

// Deploy the base contract
near_api::Contract::deploy(factory_contract.account_id().clone())
.use_code(factory_wasm)
.without_init_call()
.with_signer(signer.clone())
.send_to(&sandbox_network)
.await?
.assert_success();

factory_contract
.call_function("update_global_contract_id", json!({
"contract_id": GlobalContractId::CodeHash("11111111111111111111111111111111".to_string()),
"min_deposit": NearToken::from_millinear(TEST_DEPOSIT_AMOUNT)
}))
.transaction()
.max_gas()
.with_signer(factory_contract.account_id().clone(), signer.clone())
.send_to(&sandbox_network)
.await?
.assert_success();

// Test using non-existent global contract
factory_contract
.call_function("deploy", json!({ "name": "new_ft" }))
.transaction()
.max_gas()
.with_signer(factory_contract.account_id().clone(), signer.clone())
.send_to(&sandbox_network)
.await?
.assert_failure();

Ok(())
}

async fn create_subaccount(
sandbox: &near_sandbox::Sandbox,
name: &str,
) -> testresult::TestResult<near_api::Account> {
let account_id: AccountId = name.parse().unwrap();
sandbox
.create_account(account_id.clone())
.initial_balance(NearToken::from_near(10))
.send()
.await?;
Ok(near_api::Account(account_id))
}
118 changes: 0 additions & 118 deletions tests/workspaces.rs

This file was deleted.