The following guide was coppied from ChatGPT 4o:
When managing multiple NEAR smart contracts within a single repository, it's common to structure the repository to facilitate organization, compilation, and deployment. Here’s a pattern you can follow for a multi-contract NEAR project in Rust:
- root directory: Contains common configuration files.
- contracts: A directory containing individual subdirectories for each contract.
- scripts: Contains scripts for building, testing, and deploying contracts.
- tests: Contains integration tests that might involve multiple contracts.
Here's an example directory structure:
my-near-project/
├── contracts/
│ ├── contract_a/
│ │ ├── src/
│ │ │ └── lib.rs
│ │ ├── Cargo.toml
│ │ └── README.md
│ ├── contract_b/
│ │ ├── src/
│ │ │ └── lib.rs
│ │ ├── Cargo.toml
│ │ └── README.md
├── scripts/
│ ├── build.sh
│ ├── deploy.sh
│ └── test.sh
├── tests/
│ ├── integration_test.rs
├── Cargo.toml
├── Cargo.lock
├── README.md
└── near-config.json
The root Cargo.toml
can be used to manage dependencies common to all contracts, and workspace configuration:
[workspace]
members = [
"contracts/contract_a",
"contracts/contract_b",
# Add other contracts here
]
[dependencies]
# Add common dependencies here, if any
[profile.release]
codegen-units = 1
incremental = false
opt-level = "s" # optimize for size
Each contract should have its own Cargo.toml
file. Here is an example for contract_a
:
[package]
name = "contract_a"
version = "0.1.0"
edition = "2018"
[dependencies]
near-sdk = "4.0.0" # Ensure this is the correct version for your project
[lib]
crate-type = ["cdylib", "rlib"]
[profile.release]
opt-level = "s" # optimize for size
In the scripts
directory, create a build.sh
script to compile all the contracts:
#!/bin/bash
set -e
echo "Building contract_a"
cd contracts/contract_a
cargo build --target wasm32-unknown-unknown --release
echo "Building contract_b"
cd ../contract_b
cargo build --target wasm32-unknown-unknown --release
echo "Build completed"
Create a deploy.sh
script for deploying the contracts:
#!/bin/bash
set -e
CONTRACT_A_WASM="contracts/contract_a/target/wasm32-unknown-unknown/release/contract_a.wasm"
CONTRACT_B_WASM="contracts/contract_b/target/wasm32-unknown-unknown/release/contract_b.wasm"
echo "Deploying contract_a"
near deploy --wasmFile $CONTRACT_A_WASM --accountId <your-contract-a-account>
echo "Deploying contract_b"
near deploy --wasmFile $CONTRACT_B_WASM --accountId <your-contract-b-account>
echo "Deployment completed"
For integration tests, you can use the tests
directory:
// tests/integration_test.rs
use near_sdk::MockedBlockchain;
use near_sdk::testing_env;
use contract_a::ContractA;
use contract_b::ContractB;
#[test]
fn test_contract_interaction() {
let context = get_context(vec![], false);
testing_env!(context);
let contract_a = ContractA::default();
let contract_b = ContractB::default();
// Write your test logic here
}
fn get_context(input: Vec<u8>, is_view: bool) -> VMContext {
VMContext {
current_account_id: "contract_a".to_string(),
signer_account_id: "signer".to_string(),
signer_account_pk: vec![0, 1, 2],
predecessor_account_id: "predecessor".to_string(),
input,
block_index: 0,
block_timestamp: 0,
account_balance: 0,
account_locked_balance: 0,
storage_usage: 0,
attached_deposit: 0,
prepaid_gas: 10u64.pow(18),
random_seed: vec![0, 1, 2],
is_view,
output_data_receivers: vec![],
epoch_height: 0,
}
}
Create a near-config.json
file in the root directory to manage NEAR-specific configuration:
{
"network": "testnet",
"nodeUrl": "https://rpc.testnet.near.org",
"walletUrl": "https://wallet.testnet.near.org",
"helperUrl": "https://helper.testnet.near.org",
"explorerUrl": "https://explorer.testnet.near.org",
"keyPath": "~/.near-credentials/testnet/<your-account>.json"
}
Update your README.md
to provide an overview of the project, how to build, deploy, and test the contracts.
# My NEAR Project
## Contracts
This project contains the following smart contracts:
- `contract_a`: Description of contract A.
- `contract_b`: Description of contract B.
## Building
To build all contracts, run:
```sh
./scripts/build.sh
To deploy all contracts, run:
./scripts/deploy.sh
To run the integration tests, use:
cargo test
This structure and pattern help in managing multiple contracts effectively, ensuring clear separation of concerns and ease of building, deploying, and testing the contracts.