Skip to content

Commit ef8be49

Browse files
author
blockchainlover2019
committed
complete the test
0 parents  commit ef8be49

File tree

3 files changed

+315
-0
lines changed

3 files changed

+315
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.aptos
2+
build

Move.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = 'VaultTest'
3+
version = '1.0.0'
4+
5+
[dependencies.AptosFramework]
6+
git = 'https://github.com/aptos-labs/aptos-core.git'
7+
rev = 'main'
8+
subdir = 'aptos-move/framework/aptos-framework'
9+
10+
[addresses]
11+
AptosFramework = "0x1"
12+
VaultTest = "05c647a9f4ab1546ae4b3131aaf224501c3832f6f8e428b4cfa7198141a572b9"

sources/Vault.move

+301
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
module VaultTest::Vault {
2+
3+
use std::signer;
4+
use std::error;
5+
use std::bcs;
6+
use std::vector;
7+
use aptos_std::type_info;
8+
use aptos_framework::coin;
9+
use aptos_framework::account;
10+
11+
/* Errors. */
12+
const EAPP_NOT_INITIALIZED: u64 = 0;
13+
const EVAULT_NOT_EXISTS: u64 = 1;
14+
const EINVALID_BALANCE: u64 = 2;
15+
const EINVALID_VALUE: u64 = 3;
16+
const EINVALID_DEDICATED_INITIALIZER: u64 = 4;
17+
const EINVALID_ADMIN: u64 = 5;
18+
const EINVALID_COIN: u64 = 6;
19+
const EAPP_IS_PAUSED: u64 = 7;
20+
21+
/* Constants. */
22+
const APP_INFO_SEED: vector<u8> = b"APP_INFO_SEED";
23+
const VAULT_SEED: vector<u8> = b"VAULT_SEED";
24+
25+
/* data structures. */
26+
struct AppInfo has key, store {
27+
admin_addr: address,
28+
is_paused: u8,
29+
}
30+
31+
struct VaultInfo has key, store {
32+
amount: u64,
33+
deposit_coin_addr: address,
34+
signer_cap: account::SignerCapability,
35+
}
36+
37+
/* entry functions */
38+
public entry fun initialize_app(initializer: &signer, admin_addr: address) {
39+
let initializer_addr = signer::address_of(initializer);
40+
assert!(initializer_addr == @VaultTest, error::permission_denied(EINVALID_DEDICATED_INITIALIZER));
41+
// pool is derived from contract address
42+
let (app, _) = account::create_resource_account(initializer, APP_INFO_SEED);
43+
move_to<AppInfo>(&app, AppInfo {
44+
admin_addr,
45+
is_paused: 0,
46+
});
47+
}
48+
49+
public entry fun deposit<CoinType>(account: &signer, amount: u64) acquires VaultInfo, AppInfo {
50+
51+
let app_addr = account::create_resource_address(&@VaultTest, APP_INFO_SEED);
52+
// check if app exists
53+
assert!(exists<AppInfo>(app_addr), error::not_found(EAPP_NOT_INITIALIZED));
54+
55+
let account_addr = signer::address_of(account);
56+
let app_info = borrow_global_mut<AppInfo>(app_addr);
57+
assert!(app_info.is_paused == 0, error::permission_denied(EAPP_IS_PAUSED));
58+
59+
let coin_addr = coin_address<CoinType>();
60+
61+
let vault_addr = account::create_resource_address(&account_addr, seed_with_address(coin_addr, VAULT_SEED));
62+
if (!exists<VaultInfo>(vault_addr)) {
63+
// if it is first deposit, move VaultInfo resource to account
64+
let (vault, vault_signer_cap) = account::create_resource_account(account, seed_with_address(coin_addr, VAULT_SEED));
65+
move_to<VaultInfo>(&vault, VaultInfo {
66+
amount,
67+
deposit_coin_addr: coin_addr,
68+
signer_cap: vault_signer_cap
69+
});
70+
coin::register<CoinType>(&vault);
71+
} else {
72+
// if already deposited, then update vault_info
73+
let vault_info = borrow_global_mut<VaultInfo>(vault_addr);
74+
vault_info.amount = vault_info.amount + amount;
75+
76+
check_coin_type<CoinType>(vault_info.deposit_coin_addr);
77+
};
78+
79+
// deposit coin to vault
80+
coin::transfer<CoinType>(account, vault_addr, amount);
81+
}
82+
83+
public entry fun withdraw<CoinType>(account: &signer, amount: u64) acquires VaultInfo, AppInfo {
84+
85+
let account_addr = signer::address_of(account);
86+
let app_addr = account::create_resource_address(&@VaultTest, APP_INFO_SEED);
87+
// check if app exists
88+
assert!(exists<AppInfo>(app_addr), error::not_found(EAPP_NOT_INITIALIZED));
89+
90+
let coin_addr = coin_address<CoinType>();
91+
let vault_addr = account::create_resource_address(&account_addr, seed_with_address(coin_addr, VAULT_SEED));
92+
assert!(exists<VaultInfo>(vault_addr), error::not_found(EVAULT_NOT_EXISTS));
93+
94+
// update user's stake amount in stakeInfo
95+
let vault_info = borrow_global_mut<VaultInfo>(vault_addr);
96+
assert!(amount <= vault_info.amount, error::invalid_argument(EINVALID_VALUE));
97+
vault_info.amount = vault_info.amount - amount;
98+
99+
// check if app is paused
100+
let app_info = borrow_global_mut<AppInfo>(app_addr);
101+
assert!(app_info.is_paused == 0, error::permission_denied(EAPP_IS_PAUSED));
102+
103+
// check coin type
104+
check_coin_type<CoinType>(vault_info.deposit_coin_addr);
105+
106+
// transfer to user
107+
let vault_account_from_cap = account::create_signer_with_capability(&vault_info.signer_cap);
108+
coin::transfer<CoinType>(&vault_account_from_cap, account_addr, amount);
109+
}
110+
111+
public entry fun pause(account: &signer) acquires AppInfo {
112+
let app_addr = account::create_resource_address(&@VaultTest, APP_INFO_SEED);
113+
// check if app exists
114+
assert!(exists<AppInfo>(app_addr), error::not_found(EAPP_NOT_INITIALIZED));
115+
116+
let app_info = borrow_global_mut<AppInfo>(app_addr);
117+
118+
// check if account is admin
119+
let account_addr = signer::address_of(account);
120+
assert!(app_info.admin_addr == account_addr, error::permission_denied(EINVALID_ADMIN));
121+
122+
// resume the app
123+
app_info.is_paused = 1;
124+
}
125+
126+
public entry fun unpause(account: &signer) acquires AppInfo {
127+
let app_addr = account::create_resource_address(&@VaultTest, APP_INFO_SEED);
128+
// check if app exists
129+
assert!(exists<AppInfo>(app_addr), error::not_found(EAPP_NOT_INITIALIZED));
130+
131+
let app_info = borrow_global_mut<AppInfo>(app_addr);
132+
133+
// check if account is admin
134+
let account_addr = signer::address_of(account);
135+
assert!(app_info.admin_addr == account_addr, error::permission_denied(EINVALID_ADMIN));
136+
137+
// resume the app
138+
app_info.is_paused = 0;
139+
}
140+
141+
142+
/* private functions*/
143+
144+
/// function to get mixed seeds (addr + seed)
145+
fun seed_with_address(addr: address, seed: vector<u8>): vector<u8> {
146+
let bytes = bcs::to_bytes(&addr);
147+
vector::append(&mut bytes, seed);
148+
bytes
149+
}
150+
151+
/// function to check if coin is stakable coin
152+
fun check_coin_type<CoinType>(coin_addr: address) {
153+
assert!(coin_addr == type_info::account_address(&type_info::type_of<CoinType>()), error::invalid_argument(EINVALID_COIN));
154+
}
155+
156+
/// A helper function that returns the address of CoinType.
157+
fun coin_address<CoinType>(): address {
158+
let type_info = type_info::type_of<CoinType>();
159+
type_info::account_address(&type_info)
160+
}
161+
162+
/* Here are tests. */
163+
164+
#[test_only]
165+
struct CoinA {}
166+
167+
#[test_only]
168+
struct CoinB {}
169+
170+
#[test_only]
171+
use aptos_framework::managed_coin;
172+
173+
#[test_only]
174+
use aptos_framework::aptos_account;
175+
176+
#[test_only]
177+
public fun initialize_and_mint<CoinType>(authority: &signer, to: &signer, mint_amount: u64) {
178+
179+
let to_addr = signer::address_of(to);
180+
managed_coin::initialize<CoinType>(authority, b"FakeCoinX", b"CoinX", 9, false);
181+
if (!account::exists_at(to_addr)) {
182+
aptos_account::create_account(to_addr);
183+
};
184+
if (!coin::is_account_registered<CoinType>(to_addr)) {
185+
coin::register<CoinType>(to);
186+
};
187+
managed_coin::mint<CoinType>(authority, to_addr, mint_amount);
188+
}
189+
190+
#[test(fake_admin = @0x1234)]
191+
#[expected_failure(abort_code = 327684)] // EINVALID_DEDICATED_INITIALIZER
192+
public fun test_others_can_init(fake_admin: signer) {
193+
initialize_app(&fake_admin, signer::address_of(&fake_admin));
194+
}
195+
196+
#[test(alice = @0x1234, admin = @0x3333, initializer = @VaultTest)]
197+
#[expected_failure(abort_code = 327687)] // EAPP_IS_PAUSED
198+
public fun test_can_deposit_if_paused(alice: signer, admin: signer, initializer: signer) acquires AppInfo, VaultInfo {
199+
// init and mint coins
200+
initialize_and_mint<CoinA>(&initializer, &alice, 10000);
201+
202+
// initialize app
203+
let admin_addr = signer::address_of(&admin);
204+
initialize_app(&initializer, admin_addr);
205+
206+
// pause app
207+
pause(&admin);
208+
// try deposit but will be failed
209+
deposit<CoinA>(&alice, 500);
210+
}
211+
212+
#[test(alice = @0x1234, admin = @0x3333, initializer = @VaultTest)]
213+
#[expected_failure(abort_code = 327687)] // EAPP_IS_PAUSED
214+
public fun test_can_withdraw_if_paused(alice: signer, admin: signer, initializer: signer) acquires AppInfo, VaultInfo {
215+
// init and mint coins
216+
initialize_and_mint<CoinA>(&initializer, &alice, 10000);
217+
218+
// initialize app
219+
let admin_addr = signer::address_of(&admin);
220+
initialize_app(&initializer, admin_addr);
221+
222+
// deposit 500
223+
deposit<CoinA>(&alice, 500);
224+
225+
// pause app
226+
pause(&admin);
227+
228+
// try withdraw but will be failed
229+
withdraw<CoinA>(&alice, 500);
230+
}
231+
232+
#[test(alice = @0x1234, admin = @0x3333, initializer = @VaultTest)]
233+
public fun test_can_resume(alice: signer, admin: signer, initializer: signer) acquires AppInfo, VaultInfo {
234+
// init and mint coins
235+
initialize_and_mint<CoinA>(&initializer, &alice, 10000);
236+
237+
// initialize app
238+
let admin_addr = signer::address_of(&admin);
239+
initialize_app(&initializer, admin_addr);
240+
241+
// deposit 500
242+
deposit<CoinA>(&alice, 500);
243+
244+
// pause app
245+
pause(&admin);
246+
247+
// resume app
248+
unpause(&admin);
249+
250+
// withdraw 500
251+
withdraw<CoinA>(&alice, 500);
252+
}
253+
254+
#[test(alice = @0x1234, bob = @0x2345, admin = @0x3333, initializer = @VaultTest)]
255+
public fun e2e_test(alice: signer, bob: signer, admin: signer, initializer: signer) acquires AppInfo, VaultInfo {
256+
let alice_addr = signer::address_of(&alice);
257+
let bob_addr = signer::address_of(&bob);
258+
259+
// init and mint coins
260+
initialize_and_mint<CoinA>(&initializer, &alice, 10000);
261+
initialize_and_mint<CoinB>(&initializer, &bob, 10000);
262+
263+
assert!(coin::balance<CoinA>(alice_addr) == 10000, error::invalid_argument(EINVALID_BALANCE));
264+
assert!(coin::balance<CoinB>(bob_addr) == 10000, error::invalid_argument(EINVALID_BALANCE));
265+
266+
// initialize app
267+
let admin_addr = signer::address_of(&admin);
268+
initialize_app(&initializer, admin_addr);
269+
270+
// alice deposit 500 CoinA
271+
deposit<CoinA>(&alice, 500);
272+
assert!(coin::balance<CoinA>(alice_addr) == 9500, error::invalid_argument(EINVALID_BALANCE));
273+
274+
let alice_coin_a_vault_addr = account::create_resource_address(&alice_addr, seed_with_address(coin_address<CoinA>(), VAULT_SEED));
275+
assert!(coin::balance<CoinA>(alice_coin_a_vault_addr) == 500, error::invalid_argument(EINVALID_BALANCE));
276+
277+
let vault_info = borrow_global<VaultInfo>(alice_coin_a_vault_addr);
278+
assert!(vault_info.amount == 500, error::invalid_argument(EINVALID_BALANCE));
279+
280+
// alice withdraw 300 coinA
281+
withdraw<CoinA>(&alice, 300);
282+
assert!(coin::balance<CoinA>(alice_addr) == 9800, error::invalid_argument(EINVALID_BALANCE));
283+
assert!(coin::balance<CoinA>(alice_coin_a_vault_addr) == 200, error::invalid_argument(EINVALID_BALANCE));
284+
285+
let vault_info = borrow_global<VaultInfo>(alice_coin_a_vault_addr);
286+
assert!(vault_info.amount == 200, error::invalid_argument(EINVALID_BALANCE));
287+
288+
// bob deposit 500 CoinA
289+
deposit<CoinB>(&bob, 500);
290+
assert!(coin::balance<CoinB>(bob_addr) == 9500, error::invalid_argument(EINVALID_BALANCE));
291+
292+
let bob_coin_b_vault_addr = account::create_resource_address(&bob_addr, seed_with_address(coin_address<CoinB>(), VAULT_SEED));
293+
assert!(coin::balance<CoinB>(bob_coin_b_vault_addr) == 500, error::invalid_argument(EINVALID_BALANCE));
294+
295+
// bob withdraw 300 coinA
296+
withdraw<CoinB>(&bob, 300);
297+
assert!(coin::balance<CoinB>(bob_addr) == 9800, error::invalid_argument(EINVALID_BALANCE));
298+
assert!(coin::balance<CoinB>(bob_coin_b_vault_addr) == 200, error::invalid_argument(EINVALID_BALANCE));
299+
300+
}
301+
}

0 commit comments

Comments
 (0)