forked from Learn-NEAR/factory-example
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
629b1b2
commit 645d253
Showing
3 changed files
with
206 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,19 @@ | ||
// Find all our documentation at https://docs.near.org | ||
use near_sdk::store::LazyOption; | ||
use near_sdk::{near, Gas, NearToken}; | ||
|
||
mod deploy; | ||
|
||
const NEAR_PER_STORAGE: NearToken = NearToken::from_yoctonear(10u128.pow(18)); // 10e18yⓃ | ||
const FT_CONTRACT: &[u8] = include_bytes!("./ft-contract/ft.wasm"); | ||
const TGAS: Gas = Gas::from_tgas(1); // 10e12yⓃ | ||
const NO_DEPOSIT: NearToken = NearToken::from_near(0); // 0yⓃ | ||
|
||
// Define the contract structure | ||
#[near(contract_state)] | ||
pub struct Contract { } | ||
pub struct Contract {} | ||
|
||
// Define the default, which automatically initializes the contract | ||
impl Default for Contract { | ||
fn default() -> Self { | ||
Self { } | ||
Self {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,197 @@ | ||
use near_workspaces::types::{AccountId, KeyType, NearToken, SecretKey}; | ||
use near_contract_standards::fungible_token::metadata::FungibleTokenMetadata; | ||
use near_sdk::{json_types::U128, near}; | ||
use near_workspaces::{types::NearToken, Account, AccountId, Contract}; | ||
use serde_json::json; | ||
|
||
#[near(serializers = [json, borsh])] | ||
struct TokenArgs { | ||
owner_id: AccountId, | ||
total_supply: U128, | ||
metadata: FungibleTokenMetadata, | ||
} | ||
|
||
#[tokio::test] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let sandbox = near_workspaces::sandbox().await?; | ||
let contract_wasm = near_workspaces::compile_project("./").await?; | ||
let contract = sandbox.dev_deploy(&contract_wasm).await?; | ||
let token_owner_account = sandbox.root_account().unwrap(); | ||
let alice_account = token_owner_account | ||
.create_subaccount("alice") | ||
.initial_balance(NearToken::from_near(30)) | ||
.transact() | ||
.await? | ||
.into_result()?; | ||
let bob_account = token_owner_account | ||
.create_subaccount("bob") | ||
.initial_balance(NearToken::from_near(30)) | ||
.transact() | ||
.await? | ||
.into_result()?; | ||
|
||
create_token( | ||
&contract, | ||
&token_owner_account, | ||
&alice_account, | ||
&bob_account, | ||
) | ||
.await?; | ||
|
||
let alice = sandbox | ||
.create_tla( | ||
"alice.test.near".parse().unwrap(), | ||
SecretKey::from_random(KeyType::ED25519), | ||
) | ||
Ok(()) | ||
} | ||
|
||
async fn create_token( | ||
contract: &Contract, | ||
token_owner_account: &Account, | ||
alice_account: &Account, | ||
bob_account: &Account, | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
// Initial setup | ||
let symbol = "TEST"; | ||
let total_supply = U128(100); | ||
let token_id = symbol.to_ascii_lowercase(); | ||
let metadata = FungibleTokenMetadata { | ||
spec: "ft-1.0.0".to_string(), | ||
name: "Test Token".to_string(), | ||
symbol: symbol.to_string(), | ||
decimals: 1, | ||
icon: None, | ||
reference: None, | ||
reference_hash: None, | ||
}; | ||
let token_args = TokenArgs { | ||
owner_id: token_owner_account.id().clone(), | ||
total_supply, | ||
metadata, | ||
}; | ||
|
||
// Getting required deposit based on provided arguments | ||
let required_deposit: serde_json::Value = contract | ||
.view("get_required") | ||
.args_json(json!({"args": token_args})) | ||
.await? | ||
.unwrap(); | ||
.json()?; | ||
|
||
let bob = sandbox.dev_create_account().await?; | ||
// Creating token with less than required deposit (should fail) | ||
let res_0 = contract | ||
.call("create_token") | ||
.args_json(json!({"args": token_args})) | ||
.max_gas() | ||
.deposit(NearToken::from_yoctonear( | ||
required_deposit.as_str().unwrap().parse::<u128>()? - 1, | ||
)) | ||
.transact() | ||
.await?; | ||
assert!(res_0.is_failure()); | ||
|
||
let res = contract | ||
.call("create_factory_subaccount_and_deploy") | ||
.args_json(json!({"name": "donation_for_alice", "beneficiary": alice.id()})) | ||
// Creating token with the required deposit | ||
let res_1 = contract | ||
.call("create_token") | ||
.args_json(json!({"args": token_args})) | ||
.max_gas() | ||
.deposit(NearToken::from_near(5)) | ||
.deposit(NearToken::from_yoctonear( | ||
required_deposit.as_str().unwrap().parse::<u128>()?, | ||
)) | ||
.transact() | ||
.await?; | ||
|
||
assert!(res.is_success()); | ||
assert!(res_1.is_success()); | ||
|
||
// Checking created token account and metadata | ||
let token_account_id: AccountId = format!("{}.{}", token_id, contract.id()).parse().unwrap(); | ||
let token_metadata: FungibleTokenMetadata = token_owner_account | ||
.view(&token_account_id, "ft_metadata") | ||
.args_json(json!({})) | ||
.await? | ||
.json()?; | ||
|
||
let sub_accountid: AccountId = format!("donation_for_alice.{}", contract.id()) | ||
.parse() | ||
.unwrap(); | ||
assert_eq!(token_metadata.symbol, symbol); | ||
|
||
let res = bob | ||
.view(&sub_accountid, "get_beneficiary") | ||
.args_json({}) | ||
.await?; | ||
// Checking token supply | ||
let token_total_supply: serde_json::Value = token_owner_account | ||
.view(&token_account_id, "ft_total_supply") | ||
.args_json(json!({})) | ||
.await? | ||
.json()?; | ||
assert_eq!( | ||
token_total_supply.as_str().unwrap().parse::<u128>()?, | ||
u128::from(total_supply) | ||
); | ||
|
||
// Checking total supply belongs to the owner account | ||
let token_owner_balance: serde_json::Value = token_owner_account | ||
.view(&token_account_id, "ft_balance_of") | ||
.args_json(json!({"account_id": token_owner_account.id()})) | ||
.await? | ||
.json()?; | ||
|
||
assert_eq!(res.json::<AccountId>()?, alice.id().clone()); | ||
assert_eq!( | ||
token_owner_balance.as_str().unwrap().parse::<u128>()?, | ||
u128::from(total_supply) | ||
); | ||
|
||
let res = bob | ||
.call(&sub_accountid, "donate") | ||
.args_json({}) | ||
// Checking transfering tokens from owner to other account | ||
let _ = alice_account | ||
.call(&token_account_id, "storage_deposit") | ||
.args_json(json!({"account_id": alice_account.id()})) | ||
.max_gas() | ||
.deposit(NearToken::from_near(5)) | ||
.deposit(NearToken::from_millinear(250)) | ||
.transact() | ||
.await?; | ||
let alice_balance_before: serde_json::Value = alice_account | ||
.view(&token_account_id, "ft_balance_of") | ||
.args_json(json!({"account_id": alice_account.id()})) | ||
.await? | ||
.json()?; | ||
assert_eq!(alice_balance_before, "0"); | ||
|
||
assert!(res.is_success()); | ||
let _ = token_owner_account | ||
.call(&token_account_id, "ft_transfer") | ||
.args_json(json!({ | ||
"receiver_id": alice_account.id(), | ||
"amount": "1", | ||
})) | ||
.max_gas() | ||
.deposit(NearToken::from_yoctonear(1)) | ||
.transact() | ||
.await?; | ||
|
||
let alice_balance_after: serde_json::Value = alice_account | ||
.view(&token_account_id, "ft_balance_of") | ||
.args_json(json!({"account_id": alice_account.id()})) | ||
.await? | ||
.json()?; | ||
assert_eq!(alice_balance_after, "1"); | ||
|
||
// Checking transfering token from alice to bob | ||
let _ = bob_account | ||
.call(&token_account_id, "storage_deposit") | ||
.args_json(json!({"account_id": bob_account.id()})) | ||
.max_gas() | ||
.deposit(NearToken::from_millinear(250)) | ||
.transact() | ||
.await?; | ||
let bob_balance_before: serde_json::Value = bob_account | ||
.view(&token_account_id, "ft_balance_of") | ||
.args_json(json!({"account_id": bob_account.id()})) | ||
.await? | ||
.json()?; | ||
assert_eq!(bob_balance_before, "0"); | ||
let _ = alice_account | ||
.call(&token_account_id, "ft_transfer") | ||
.args_json(json!({ | ||
"receiver_id": bob_account.id(), | ||
"amount": "1", | ||
})) | ||
.max_gas() | ||
.deposit(NearToken::from_yoctonear(1)) | ||
.transact() | ||
.await?; | ||
let bob_balance_after: serde_json::Value = bob_account | ||
.view(&token_account_id, "ft_balance_of") | ||
.args_json(json!({"account_id": bob_account.id()})) | ||
.await? | ||
.json()?; | ||
assert_eq!(bob_balance_after, "1"); | ||
Ok(()) | ||
} |