|
1 | | -use chrono::Utc; |
2 | | -use near_sdk::{json_types::U128, NearToken}; |
3 | | -use near_sdk::{near, AccountId, Gas}; |
4 | | -use near_workspaces::result::ExecutionFinalResult; |
5 | | -use near_workspaces::{Account, Contract}; |
6 | | -use serde_json::json; |
7 | | - |
8 | | -const TEN_NEAR: NearToken = NearToken::from_near(10); |
| 1 | +use near_api::{AccountId, NearGas, NearToken}; |
| 2 | +use near_sdk::json_types::U128; |
| 3 | +use near_sdk::serde_json::json; |
| 4 | + |
9 | 5 | const FT_WASM_FILEPATH: &str = "./tests/fungible_token.wasm"; |
10 | 6 |
|
11 | | -#[near(serializers = [json])] |
| 7 | +#[derive(near_sdk::serde::Deserialize)] |
| 8 | +#[serde(crate = "near_sdk::serde")] |
12 | 9 | pub struct Bid { |
13 | 10 | pub bidder: AccountId, |
14 | 11 | pub bid: U128, |
15 | 12 | } |
16 | 13 |
|
17 | 14 | #[tokio::test] |
18 | 15 |
|
19 | | -async fn test_contract_is_operational() -> Result<(), Box<dyn std::error::Error>> { |
20 | | - let sandbox = near_workspaces::sandbox().await?; |
21 | | - |
22 | | - let root: near_workspaces::Account = sandbox.root_account()?; |
23 | | - |
24 | | - // Create accounts |
25 | | - let alice = create_subaccount(&root, "alice").await?; |
26 | | - let auctioneer = create_subaccount(&root, "auctioneer").await?; |
27 | | - let contract_account = create_subaccount(&root, "contract").await?; |
28 | | - let nft_account = create_subaccount(&root, "nft").await?; |
| 16 | +async fn test_contract_is_operational() -> testresult::TestResult<()> { |
| 17 | + // Build the contract wasm file |
| 18 | + let contract_wasm_path = cargo_near_build::build_with_cli(Default::default())?; |
| 19 | + let contract_wasm = std::fs::read(contract_wasm_path)?; |
29 | 20 |
|
| 21 | + // Read the FT wasm file |
30 | 22 | let ft_wasm = std::fs::read(FT_WASM_FILEPATH)?; |
31 | | - let ft_contract = sandbox.dev_deploy(&ft_wasm).await?; |
32 | | - |
33 | | - // Initialize FT contract |
34 | | - let res = ft_contract |
35 | | - .call("new_default_meta") |
36 | | - .args_json(serde_json::json!({ |
37 | | - "owner_id": root.id(), |
38 | | - "total_supply": U128(1_000_000), |
39 | | - })) |
40 | | - .transact() |
41 | | - .await?; |
42 | 23 |
|
43 | | - assert!(res.is_success()); |
| 24 | + // Initialize the sandbox |
| 25 | + let sandbox = near_sandbox::Sandbox::start_sandbox().await?; |
| 26 | + let sandbox_network = |
| 27 | + near_api::NetworkConfig::from_rpc_url("sandbox", sandbox.rpc_addr.parse()?); |
| 28 | + |
| 29 | + // Create accounts |
| 30 | + let alice = create_subaccount(&sandbox, "alice.sandbox").await?; |
| 31 | + let auctioneer = create_subaccount(&sandbox, "auctioneer.sandbox").await?; |
| 32 | + let nft_contract = create_subaccount(&sandbox, "nft-contract.sandbox") |
| 33 | + .await? |
| 34 | + .as_contract(); |
| 35 | + let ft_contract = create_subaccount(&sandbox, "ft-contract.sandbox") |
| 36 | + .await? |
| 37 | + .as_contract(); |
| 38 | + let contract = create_subaccount(&sandbox, "contract.sandbox") |
| 39 | + .await? |
| 40 | + .as_contract(); |
| 41 | + |
| 42 | + // Initialize signer for the contract deployment |
| 43 | + let signer = near_api::Signer::from_secret_key( |
| 44 | + near_sandbox::config::DEFAULT_GENESIS_ACCOUNT_PRIVATE_KEY |
| 45 | + .parse() |
| 46 | + .unwrap(), |
| 47 | + )?; |
| 48 | + |
| 49 | + // Deploy the FT contract |
| 50 | + near_api::Contract::deploy(ft_contract.account_id().clone()) |
| 51 | + .use_code(ft_wasm) |
| 52 | + .with_init_call( |
| 53 | + "new_default_meta", |
| 54 | + json!({"owner_id": ft_contract.account_id(), "total_supply": U128(1_000_000)}), |
| 55 | + )? |
| 56 | + .with_signer(signer.clone()) |
| 57 | + .send_to(&sandbox_network) |
| 58 | + .await? |
| 59 | + .assert_success(); |
44 | 60 |
|
45 | 61 | // Skip creating NFT contract as we are are only going to test making a bid to the auction |
46 | 62 |
|
47 | 63 | // Deploy factory contract |
48 | | - let contract_wasm = near_workspaces::compile_project("./").await?; |
49 | | - let contract = contract_account.deploy(&contract_wasm).await?.unwrap(); |
| 64 | + near_api::Contract::deploy(contract.account_id().clone()) |
| 65 | + .use_code(contract_wasm) |
| 66 | + .without_init_call() |
| 67 | + .with_signer(signer.clone()) |
| 68 | + .send_to(&sandbox_network) |
| 69 | + .await? |
| 70 | + .assert_success(); |
50 | 71 |
|
51 | 72 | // Create auction by calling factory contract |
52 | | - let now = Utc::now().timestamp(); |
| 73 | + let now = std::time::SystemTime::now() |
| 74 | + .duration_since(std::time::SystemTime::UNIX_EPOCH)? |
| 75 | + .as_secs(); |
53 | 76 | let a_minute_from_now = (now + 60) * 1000000000; |
54 | 77 | let starting_price = U128(10_000); |
55 | 78 |
|
56 | | - let deploy_new_auction: ExecutionFinalResult = alice |
57 | | - .call(contract.id(), "deploy_new_auction") |
58 | | - .args_json( |
59 | | - json!({"name": "new-auction", "end_time": a_minute_from_now.to_string(),"auctioneer": auctioneer.id(),"ft_contract": ft_contract.id(),"nft_contract": nft_account.id(),"token_id":"1", "starting_price":starting_price }), |
60 | | - ) |
61 | | - .max_gas() |
| 79 | + contract |
| 80 | + .call_function("deploy_new_auction", json!({"name": "new-auction", "end_time": a_minute_from_now.to_string(),"auctioneer": auctioneer.account_id(),"ft_contract": ft_contract.account_id(),"nft_contract": nft_contract.account_id(),"token_id":"1", "starting_price":starting_price }),) |
| 81 | + .transaction() |
62 | 82 | .deposit(NearToken::from_millinear(1600)) |
63 | | - .transact() |
64 | | - .await?; |
65 | | - |
66 | | - assert!(deploy_new_auction.is_success()); |
| 83 | + .with_signer(alice.account_id().clone(), signer.clone()) |
| 84 | + .send_to(&sandbox_network) |
| 85 | + .await? |
| 86 | + .assert_success(); |
67 | 87 |
|
68 | | - let auction_account_id: AccountId = format!("new-auction.{}", contract.id()).parse().unwrap(); |
| 88 | + let auction_account_id: AccountId = format!("new-auction.{}", contract.account_id()) |
| 89 | + .parse() |
| 90 | + .unwrap(); |
| 91 | + sandbox |
| 92 | + .import_account( |
| 93 | + sandbox.rpc_addr.to_string(), |
| 94 | + format!("new-auction.{}", contract.account_id()) |
| 95 | + .parse() |
| 96 | + .unwrap(), |
| 97 | + ) |
| 98 | + .send() |
| 99 | + .await?; |
| 100 | + let auction_account = near_api::Account(auction_account_id.clone()).as_contract(); |
69 | 101 |
|
70 | 102 | // Register accounts |
71 | | - for account_id in [alice.id().clone(), auction_account_id.clone()].iter() { |
72 | | - let register = ft_contract |
73 | | - .call("storage_deposit") |
74 | | - .args_json(serde_json::json!({ "account_id": account_id })) |
| 103 | + for account_id in [alice.account_id().clone(), auction_account_id.clone()].iter() { |
| 104 | + ft_contract |
| 105 | + .call_function( |
| 106 | + "storage_deposit", |
| 107 | + serde_json::json!({ "account_id": account_id }), |
| 108 | + ) |
| 109 | + .transaction() |
75 | 110 | .deposit(NearToken::from_yoctonear(8000000000000000000000)) |
76 | | - .transact() |
77 | | - .await?; |
78 | | - |
79 | | - assert!(register.is_success()); |
| 111 | + .with_signer(alice.account_id().clone(), signer.clone()) |
| 112 | + .send_to(&sandbox_network) |
| 113 | + .await? |
| 114 | + .assert_success(); |
80 | 115 | } |
81 | 116 |
|
82 | | - // Transfer FTs |
| 117 | + // Transfer FTs to Alice and Bob to top up their balances |
83 | 118 | let transfer_amount = U128(150_000); |
84 | 119 |
|
85 | | - let root_transfer_alice = |
86 | | - ft_transfer(&root, alice.clone(), ft_contract.clone(), transfer_amount).await?; |
87 | | - assert!(root_transfer_alice.is_success()); |
| 120 | + ft_transfer( |
| 121 | + &ft_contract, |
| 122 | + &ft_contract.account_id(), |
| 123 | + alice.account_id(), |
| 124 | + transfer_amount, |
| 125 | + &signer, |
| 126 | + &sandbox_network, |
| 127 | + ) |
| 128 | + .await?; |
88 | 129 |
|
89 | 130 | // Alice makes a bid |
90 | | - let alice_bid = ft_transfer_call( |
91 | | - alice.clone(), |
92 | | - ft_contract.id(), |
| 131 | + ft_transfer_call( |
| 132 | + &ft_contract, |
| 133 | + &alice, |
93 | 134 | &auction_account_id, |
94 | 135 | U128(50_000), |
| 136 | + &signer, |
| 137 | + &sandbox_network, |
95 | 138 | ) |
96 | 139 | .await?; |
97 | 140 |
|
98 | | - assert!(alice_bid.is_success()); |
99 | | - |
100 | | - let highest_bid_alice: Bid = alice |
101 | | - .view(&auction_account_id, "get_highest_bid") |
102 | | - .args_json({}) |
| 141 | + let highest_bid: Bid = auction_account |
| 142 | + .call_function("get_highest_bid", ()) |
| 143 | + .read_only() |
| 144 | + .fetch_from(&sandbox_network) |
103 | 145 | .await? |
104 | | - .json()?; |
105 | | - assert_eq!(highest_bid_alice.bid, U128(50_000)); |
106 | | - assert_eq!(highest_bid_alice.bidder, *alice.id()); |
| 146 | + .data; |
| 147 | + assert_eq!(highest_bid.bid, U128(50_000)); |
| 148 | + assert_eq!(&highest_bid.bidder, alice.account_id()); |
| 149 | + |
| 150 | + // Contract balance has increased |
| 151 | + let auction_contract_balance: U128 = |
| 152 | + ft_balance_of(&ft_contract, auction_account.account_id(), &sandbox_network).await?; |
| 153 | + assert_eq!(auction_contract_balance, U128(50_000)); |
107 | 154 |
|
108 | | - let contract_account_balance: U128 = ft_balance_of(&ft_contract, &auction_account_id).await?; |
109 | | - assert_eq!(contract_account_balance, U128(50_000)); |
110 | | - let alice_balance_after_bid: U128 = ft_balance_of(&ft_contract, alice.id()).await?; |
111 | | - assert_eq!(alice_balance_after_bid, U128(100_000)); |
| 155 | + // Alice balance has decreased |
| 156 | + let alice_balance: U128 = |
| 157 | + ft_balance_of(&ft_contract, alice.account_id(), &sandbox_network).await?; |
| 158 | + assert_eq!(alice_balance, U128(100_000)); |
112 | 159 |
|
113 | 160 | // Try to launch a new auction with insufficient deposit |
114 | | - let deploy_new_auction: ExecutionFinalResult = alice |
115 | | - .call(contract.id(), "deploy_new_auction") |
116 | | - .args_json( |
117 | | - json!({"name": "new-auction", "end_time": a_minute_from_now.to_string(),"auctioneer": auctioneer.id(),"ft_contract": ft_contract.id(),"nft_contract": nft_account.id(),"token_id":"1", "starting_price":starting_price }), |
118 | | - ) |
119 | | - .max_gas() |
| 161 | + contract |
| 162 | + .call_function("deploy_new_auction", json!({"name": "new-auction", "end_time": a_minute_from_now.to_string(),"auctioneer": auctioneer.account_id(),"ft_contract": ft_contract.account_id(),"nft_contract": nft_contract.account_id(),"token_id":"1", "starting_price":starting_price }),) |
| 163 | + .transaction() |
120 | 164 | .deposit(NearToken::from_millinear(1400)) |
121 | | - .transact() |
122 | | - .await?; |
123 | | - |
124 | | - assert!(deploy_new_auction.is_failure()); |
| 165 | + .with_signer(alice.account_id().clone(), signer.clone()) |
| 166 | + .send_to(&sandbox_network) |
| 167 | + .await? |
| 168 | + .assert_failure(); |
125 | 169 |
|
126 | 170 | Ok(()) |
127 | 171 | } |
128 | 172 |
|
129 | 173 | async fn create_subaccount( |
130 | | - root: &near_workspaces::Account, |
| 174 | + sandbox: &near_sandbox::Sandbox, |
131 | 175 | name: &str, |
132 | | -) -> Result<near_workspaces::Account, Box<dyn std::error::Error>> { |
133 | | - let subaccount = root |
134 | | - .create_subaccount(name) |
135 | | - .initial_balance(TEN_NEAR) |
136 | | - .transact() |
137 | | - .await? |
138 | | - .unwrap(); |
139 | | - |
140 | | - Ok(subaccount) |
| 176 | +) -> testresult::TestResult<near_api::Account> { |
| 177 | + let account_id: AccountId = name.parse().unwrap(); |
| 178 | + sandbox |
| 179 | + .create_account(account_id.clone()) |
| 180 | + .initial_balance(NearToken::from_near(10)) |
| 181 | + .send() |
| 182 | + .await?; |
| 183 | + Ok(near_api::Account(account_id)) |
141 | 184 | } |
142 | 185 |
|
143 | 186 | async fn ft_transfer( |
144 | | - root: &near_workspaces::Account, |
145 | | - account: Account, |
146 | | - ft_contract: Contract, |
147 | | - transfer_amount: U128, |
148 | | -) -> Result<ExecutionFinalResult, Box<dyn std::error::Error>> { |
149 | | - let transfer = root |
150 | | - .call(ft_contract.id(), "ft_transfer") |
151 | | - .args_json(serde_json::json!({ |
152 | | - "receiver_id": account.id(), |
153 | | - "amount": transfer_amount |
154 | | - })) |
| 187 | + ft_contract: &near_api::Contract, |
| 188 | + from: &AccountId, |
| 189 | + to: &AccountId, |
| 190 | + amount: U128, |
| 191 | + signer: &std::sync::Arc<near_api::Signer>, |
| 192 | + network: &near_api::NetworkConfig, |
| 193 | +) -> testresult::TestResult<()> { |
| 194 | + ft_contract |
| 195 | + .call_function( |
| 196 | + "ft_transfer", |
| 197 | + serde_json::json!({"receiver_id": to, "amount": amount}), |
| 198 | + ) |
| 199 | + .transaction() |
155 | 200 | .deposit(NearToken::from_yoctonear(1)) |
156 | | - .transact() |
157 | | - .await?; |
158 | | - Ok(transfer) |
| 201 | + .with_signer(from.clone(), signer.clone()) |
| 202 | + .send_to(network) |
| 203 | + .await? |
| 204 | + .assert_success(); |
| 205 | + Ok(()) |
159 | 206 | } |
160 | 207 |
|
161 | 208 | async fn ft_balance_of( |
162 | | - ft_contract: &Contract, |
| 209 | + ft_contract: &near_api::Contract, |
163 | 210 | account_id: &AccountId, |
164 | | -) -> Result<U128, Box<dyn std::error::Error>> { |
165 | | - let result = ft_contract |
166 | | - .view("ft_balance_of") |
167 | | - .args_json(json!({"account_id": account_id})) |
| 211 | + network: &near_api::NetworkConfig, |
| 212 | +) -> testresult::TestResult<U128> { |
| 213 | + let result: U128 = ft_contract |
| 214 | + .call_function( |
| 215 | + "ft_balance_of", |
| 216 | + serde_json::json!({"account_id": account_id}), |
| 217 | + ) |
| 218 | + .read_only() |
| 219 | + .fetch_from(network) |
168 | 220 | .await? |
169 | | - .json()?; |
170 | | - |
| 221 | + .data; |
171 | 222 | Ok(result) |
172 | 223 | } |
173 | 224 |
|
174 | 225 | async fn ft_transfer_call( |
175 | | - account: Account, |
176 | | - ft_contract_id: &AccountId, |
| 226 | + ft_contract: &near_api::Contract, |
| 227 | + account: &near_api::Account, |
177 | 228 | receiver_id: &AccountId, |
178 | 229 | amount: U128, |
179 | | -) -> Result<ExecutionFinalResult, Box<dyn std::error::Error>> { |
180 | | - let transfer = account |
181 | | - .call(ft_contract_id, "ft_transfer_call") |
182 | | - .args_json(serde_json::json!({ |
183 | | - "receiver_id": receiver_id, "amount":amount, "msg": "0" })) |
| 230 | + signer: &std::sync::Arc<near_api::Signer>, |
| 231 | + network: &near_api::NetworkConfig, |
| 232 | +) -> testresult::TestResult<()> { |
| 233 | + let _ = ft_contract |
| 234 | + .call_function( |
| 235 | + "ft_transfer_call", |
| 236 | + serde_json::json!({"receiver_id": receiver_id, "amount": amount, "msg": "0"}), |
| 237 | + ) |
| 238 | + .transaction() |
184 | 239 | .deposit(NearToken::from_yoctonear(1)) |
185 | | - .gas(Gas::from_tgas(300)) |
186 | | - .transact() |
187 | | - .await?; |
188 | | - Ok(transfer) |
| 240 | + .gas(NearGas::from_tgas(300)) |
| 241 | + .with_signer(account.account_id().clone(), signer.clone()) |
| 242 | + .send_to(network) |
| 243 | + .await? |
| 244 | + .assert_success(); |
| 245 | + Ok(()) |
189 | 246 | } |
0 commit comments