crowdfund.rs 42.8 KiB
Newer Older
			// Onboard crowdfund
			assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
			// Fund is assigned a parachain id
			let fund = Crowdfund::funds(0).unwrap();
			assert_eq!(fund.parachain, Some(0.into()));

			// Cannot retire fund whose deposit has not been returned
			assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), "parachain still has deposit");

			run_to_block(50);

			// Cannot retire invalid fund index
			assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 1), "invalid fund index");

			// Cannot retire twice
			assert_ok!(Crowdfund::begin_retirement(Origin::signed(1), 0));
			assert_noop!(Crowdfund::begin_retirement(Origin::signed(1), 0), "fund has no parachain");
		});
	}

	#[test]
	fn withdraw_works() {
		with_externalities(&mut new_test_ext(), || {
			// Set up a crowdfund
			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
			assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 9));
			// Transfer fee is taken here
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 100));
			assert_ok!(Crowdfund::contribute(Origin::signed(2), 0, 200));
			assert_ok!(Crowdfund::contribute(Origin::signed(3), 0, 300));

			// Skip all the way to the end
			run_to_block(50);

			// User can withdraw their full balance without fees
			assert_ok!(Crowdfund::withdraw(Origin::signed(1), 0));
			assert_eq!(Balances::free_balance(1), 989);

			assert_ok!(Crowdfund::withdraw(Origin::signed(2), 0));
			assert_eq!(Balances::free_balance(2), 1990);

			assert_ok!(Crowdfund::withdraw(Origin::signed(3), 0));
			assert_eq!(Balances::free_balance(3), 2990);
		});
	}
	#[test]
	fn withdraw_handles_basic_errors() {
		with_externalities(&mut new_test_ext(), || {
			// Set up a crowdfund
			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
			assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 9));
			// Transfer fee is taken here
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 49));
			assert_eq!(Balances::free_balance(1), 940);

			run_to_block(5);

			// Cannot withdraw before fund ends
			assert_noop!(Crowdfund::withdraw(Origin::signed(1), 0), "fund has not ended");

			run_to_block(10);

			// Cannot withdraw if they did not contribute
			assert_noop!(Crowdfund::withdraw(Origin::signed(2), 0), "no contributions stored");
			// Cannot withdraw from a non-existent fund
			assert_noop!(Crowdfund::withdraw(Origin::signed(1), 1), "invalid fund index");
		});
	}

	#[test]
	fn dissolve_works() {
		with_externalities(&mut new_test_ext(), || {
			// Set up a crowdfund
			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
			assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 9));
			// Transfer fee is taken here
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 100));
			assert_ok!(Crowdfund::contribute(Origin::signed(2), 0, 200));
			assert_ok!(Crowdfund::contribute(Origin::signed(3), 0, 300));

			// Skip all the way to the end
			run_to_block(50);
			// Check current funds (contributions + deposit)
			assert_eq!(Balances::free_balance(Crowdfund::fund_account_id(0)), 601);

			// Dissolve the crowdfund
			assert_ok!(Crowdfund::dissolve(Origin::signed(1), 0));

			// Fund account is emptied
			assert_eq!(Balances::free_balance(Crowdfund::fund_account_id(0)), 0);
			// Deposit is returned
			assert_eq!(Balances::free_balance(1), 890);
			// Treasury account is filled
			assert_eq!(Balances::free_balance(Treasury::account_id()), 600);

			// Storage trie is removed
			assert_eq!(Crowdfund::contribution_get(0,&0), 0);
			// Fund storage is removed
			assert_eq!(Crowdfund::funds(0), None);

		});
	}

	#[test]
	fn dissolve_handles_basic_errors() {
		with_externalities(&mut new_test_ext(), || {
			// Set up a crowdfund
			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
			assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 9));
			// Transfer fee is taken here
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 100));
			assert_ok!(Crowdfund::contribute(Origin::signed(2), 0, 200));
			assert_ok!(Crowdfund::contribute(Origin::signed(3), 0, 300));

			// Cannot dissolve an invalid fund index
			assert_noop!(Crowdfund::dissolve(Origin::signed(1), 1), "invalid fund index");
			// Cannot dissolve a fund in progress
			assert_noop!(Crowdfund::dissolve(Origin::signed(1), 0), "retirement period not over");

			run_to_block(10);

			// Onboard fund
			assert_ok!(Crowdfund::fix_deploy_data(
				Origin::signed(1),
				0,
				<Test as system::Trait>::Hash::default(),
				vec![0]
			));
			assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));

			// Cannot dissolve an active fund
			assert_noop!(Crowdfund::dissolve(Origin::signed(1), 0), "cannot dissolve fund with active parachain");
		});
	}

	#[test]
	fn fund_before_auction_works() {
		with_externalities(&mut new_test_ext(), || {
			// Create a crowdfund before an auction is created
			assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 9));
			// Users can already contribute
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 49));
			// Fund added to NewRaise
			assert_eq!(Crowdfund::new_raise(), vec![0]);

			// Some blocks later...
			run_to_block(2);
			// Create an auction
			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
			// Add deploy data
			assert_ok!(Crowdfund::fix_deploy_data(
				Origin::signed(1),
				0,
				<Test as system::Trait>::Hash::default(),
				vec![0]
			));
			// Move to the end of auction...
			run_to_block(12);

			// Endings count incremented
			assert_eq!(Crowdfund::endings_count(), 1);

			// Onboard crowdfund
			assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));

			let fund = Crowdfund::funds(0).unwrap();
			// Crowdfund is now assigned a parachain id
			assert_eq!(fund.parachain, Some(0.into()));
			// This parachain is managed by Slots
			assert_eq!(Slots::managed_ids(), vec![0.into()]);
		});
	}

	#[test]
	fn fund_across_multiple_auctions_works() {
		with_externalities(&mut new_test_ext(), || {
			// Create an auction
			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
			// Create two competing crowdfunds, with end dates across multiple auctions
			// Each crowdfund is competing for the same slots, so only one can win
			assert_ok!(Crowdfund::create(Origin::signed(1), 1000, 1, 4, 30));
			assert_ok!(Crowdfund::create(Origin::signed(2), 1000, 1, 4, 30));

			// Contribute to all, but more money to 0, less to 1
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 0, 300));
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 1, 200));

			// Add deploy data to all
			assert_ok!(Crowdfund::fix_deploy_data(
				Origin::signed(1),
				0,
				<Test as system::Trait>::Hash::default(),
				vec![0]
			));
			assert_ok!(Crowdfund::fix_deploy_data(
				Origin::signed(2),
				1,
				<Test as system::Trait>::Hash::default(),
				vec![0]
			));

			// End the current auction, fund 0 wins!
			run_to_block(10);
			assert_eq!(Crowdfund::endings_count(), 1);
			// Onboard crowdfund
			assert_ok!(Crowdfund::onboard(Origin::signed(1), 0, 0.into()));
			let fund = Crowdfund::funds(0).unwrap();
			// Crowdfund is now assigned a parachain id
			assert_eq!(fund.parachain, Some(0.into()));
			// This parachain is managed by Slots
			assert_eq!(Slots::managed_ids(), vec![0.into()]);

			// Create a second auction
			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
			// Contribute to existing funds add to NewRaise
			assert_ok!(Crowdfund::contribute(Origin::signed(1), 1, 10));

			// End the current auction, fund 1 wins!
			run_to_block(20);
			assert_eq!(Crowdfund::endings_count(), 2);
			// Onboard crowdfund
			assert_ok!(Crowdfund::onboard(Origin::signed(2), 1, 1.into()));
			let fund = Crowdfund::funds(1).unwrap();
			// Crowdfund is now assigned a parachain id
			assert_eq!(fund.parachain, Some(1.into()));
			// This parachain is managed by Slots
			assert_eq!(Slots::managed_ids(), vec![0.into(), 1.into()]);
		});
	}
}