mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 16:07:57 +00:00
5d81f23f8f
* First reworking of fungibles API * New API and docs * More fungible::* API improvements * New ref-counting logic for old API * Missing files * Fixes * Use the new transfer logic * Use fungibles for the dispatchables * Use shelve/restore names * Locking works with total balance. * repotting and removal * Separate Holds from Reserves * Introduce freezes * Missing files * Tests for freezing * Fix hold+freeze combo * More tests * Fee-free dispatchable for upgrading accounts * Benchmarks and a few fixes * Another test * Docs and refactor to avoid blanket impls * Repot * Fit out ItemOf fully * Add events to Balanced traits * Introduced events into Hold traits * Fix Assets pallet tests * Assets benchmarks pass * Missing files and fixes * Fixes * Fixes * Benchmarks fixes * Fix balance benchmarks * Formatting * Expose fungible sub modules * Move NIS to fungible API * Fix broken impl and add test * Fix tests * API for `transfer_and_hold` * Use composite APIs * Formatting * Upgraded event * Fixes * Fixes * Fixes * Fixes * Repot tests and some fixed * Fix some bits * Fix dust tests * Rename `set_balance` - `Balances::set_balance` becomes `Balances::force_set_balance` - `Unbalanced::set_balance` becomes `Unbalances::write_balance` * becomes * Move dust handling to fungibles API * Formatting * Fixes and more refactoring * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Fixes * Use reducible_balance for better correctness on fees * Reducing hold to zero should remove entry. * Add test * Docs * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> * Update frame/support/src/traits/tokens/fungibles/regular.rs Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> * Update frame/support/src/traits/tokens/fungible/regular.rs Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> * Docs * Docs * Docs * Fix NIS benchmarks * Doc comment * Remove post_mutation * Fix some tests * Fix some grumbles * Enumify bool args to fungible(s) functions * Fix up assets and balances * Formatting * Fix contracts * Fix tests & benchmarks build * Typify minted boolean arg * Typify on_hold boolean arg; renames * Fix numerous tests * Fix dependency issue * Privatize dangerous API mutate_account * Fix contracts (@alext - please check this commit) * Remove println * Fix tests for contracts * Fix broken rename * Fix broken rename * Fix broken rename * Docs * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * remove from_ref_time * Update frame/executive/src/lib.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/executive/src/lib.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Reenable test * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungible/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/currency.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/lottery/src/tests.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungible/mod.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungible/regular.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungibles/freeze.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungible/regular.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Update frame/support/src/traits/tokens/fungibles/hold.rs Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> * Rename UnwantedRemoval to UnwantedAccountRemoval * Docs * Formatting * Update frame/balances/src/lib.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update primitives/runtime/src/lib.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * handle_raw_dust oes nothing * Formatting * Fixes * Grumble * Fixes * Add test * Add test * Tests for reducible_balance * Fixes * Fix Salary * Fixes * Disable broken test * Disable nicely * Fixes * Fixes * Fixes * Rename some events * Fix nomination pools breakage * Add compatibility stub for transfer tx * Reinstate a safely compatible version of Balances set_balance * Fixes * Grumble * Update frame/nis/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_balances * disable flakey tests * Update frame/balances/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Grumbles * Grumble --------- Co-authored-by: Muharem Ismailov <ismailov.m.h@gmail.com> Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Anthony Alaribe <anthonyalaribe@gmail.com> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: command-bot <>
452 lines
15 KiB
Rust
452 lines
15 KiB
Rust
// This file is part of Substrate.
|
|
|
|
// Copyright (C) Parity Technologies (UK) Ltd.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! Tests for the module.
|
|
|
|
use super::*;
|
|
use frame_support::{assert_noop, assert_ok, assert_storage_noop};
|
|
use mock::{
|
|
new_test_ext, run_to_block, Balances, BalancesCall, Lottery, RuntimeCall, RuntimeOrigin,
|
|
SystemCall, Test,
|
|
};
|
|
use sp_runtime::{traits::BadOrigin, TokenError};
|
|
|
|
#[test]
|
|
fn initial_state() {
|
|
new_test_ext().execute_with(|| {
|
|
assert_eq!(Balances::free_balance(Lottery::account_id()), 0);
|
|
assert!(crate::Lottery::<Test>::get().is_none());
|
|
assert_eq!(Participants::<Test>::get(&1), (0, Default::default()));
|
|
assert_eq!(TicketsCount::<Test>::get(), 0);
|
|
assert!(Tickets::<Test>::get(0).is_none());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn basic_end_to_end_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let price = 10;
|
|
let length = 20;
|
|
let delay = 5;
|
|
let calls = vec![
|
|
RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }),
|
|
RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }),
|
|
];
|
|
|
|
// Set calls for the lottery
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls));
|
|
|
|
// Start lottery, it repeats
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, true));
|
|
assert!(crate::Lottery::<Test>::get().is_some());
|
|
|
|
assert_eq!(Balances::free_balance(&1), 100);
|
|
let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death {
|
|
dest: 2,
|
|
value: 20,
|
|
}));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone()));
|
|
// 20 from the transfer, 10 from buying a ticket
|
|
assert_eq!(Balances::free_balance(&1), 100 - 20 - 10);
|
|
assert_eq!(Participants::<Test>::get(&1).1.len(), 1);
|
|
assert_eq!(TicketsCount::<Test>::get(), 1);
|
|
// 1 owns the 0 ticket
|
|
assert_eq!(Tickets::<Test>::get(0), Some(1));
|
|
|
|
// More ticket purchases
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone()));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(3), call.clone()));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(4), call.clone()));
|
|
assert_eq!(TicketsCount::<Test>::get(), 4);
|
|
|
|
// Go to end
|
|
run_to_block(20);
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(5), call.clone()));
|
|
// Ticket isn't bought
|
|
assert_eq!(TicketsCount::<Test>::get(), 4);
|
|
|
|
// Go to payout
|
|
run_to_block(25);
|
|
// User 1 wins
|
|
assert_eq!(Balances::free_balance(&1), 70 + 40);
|
|
// Lottery is reset and restarted
|
|
assert_eq!(TicketsCount::<Test>::get(), 0);
|
|
assert_eq!(LotteryIndex::<Test>::get(), 2);
|
|
assert_eq!(
|
|
crate::Lottery::<Test>::get().unwrap(),
|
|
LotteryConfig { price, start: 25, length, delay, repeat: true }
|
|
);
|
|
});
|
|
}
|
|
|
|
/// Only the manager can stop the Lottery from repeating via `stop_repeat`.
|
|
#[test]
|
|
fn stop_repeat_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let price = 10;
|
|
let length = 20;
|
|
let delay = 5;
|
|
|
|
// Set no calls for the lottery.
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![]));
|
|
// Start lottery, it repeats.
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, true));
|
|
|
|
// Non-manager fails to `stop_repeat`.
|
|
assert_noop!(Lottery::stop_repeat(RuntimeOrigin::signed(1)), DispatchError::BadOrigin);
|
|
// Manager can `stop_repeat`, even twice.
|
|
assert_ok!(Lottery::stop_repeat(RuntimeOrigin::root()));
|
|
assert_ok!(Lottery::stop_repeat(RuntimeOrigin::root()));
|
|
|
|
// Lottery still exists.
|
|
assert!(crate::Lottery::<Test>::get().is_some());
|
|
// End and pick a winner.
|
|
run_to_block(length + delay);
|
|
|
|
// Lottery stays dead and does not repeat.
|
|
assert!(crate::Lottery::<Test>::get().is_none());
|
|
run_to_block(length + delay + 1);
|
|
assert!(crate::Lottery::<Test>::get().is_none());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn set_calls_works() {
|
|
new_test_ext().execute_with(|| {
|
|
assert!(!CallIndices::<Test>::exists());
|
|
|
|
let calls = vec![
|
|
RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }),
|
|
RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }),
|
|
];
|
|
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls));
|
|
assert!(CallIndices::<Test>::exists());
|
|
|
|
let too_many_calls = vec![
|
|
RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }),
|
|
RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }),
|
|
RuntimeCall::System(SystemCall::remark { remark: vec![] }),
|
|
];
|
|
|
|
assert_noop!(
|
|
Lottery::set_calls(RuntimeOrigin::root(), too_many_calls),
|
|
Error::<Test>::TooManyCalls,
|
|
);
|
|
|
|
// Clear calls
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![]));
|
|
assert!(CallIndices::<Test>::get().is_empty());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn call_to_indices_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let calls = vec![
|
|
RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }),
|
|
RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }),
|
|
];
|
|
let indices = Lottery::calls_to_indices(&calls).unwrap().into_inner();
|
|
// Only comparing the length since it is otherwise dependant on the API
|
|
// of `BalancesCall`.
|
|
assert_eq!(indices.len(), calls.len());
|
|
|
|
let too_many_calls = vec![
|
|
RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }),
|
|
RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }),
|
|
RuntimeCall::System(SystemCall::remark { remark: vec![] }),
|
|
];
|
|
assert_noop!(Lottery::calls_to_indices(&too_many_calls), Error::<Test>::TooManyCalls);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn start_lottery_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let price = 10;
|
|
let length = 20;
|
|
let delay = 5;
|
|
|
|
// Setup ignores bad origin
|
|
assert_noop!(
|
|
Lottery::start_lottery(RuntimeOrigin::signed(1), price, length, delay, false),
|
|
BadOrigin,
|
|
);
|
|
|
|
// All good
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false));
|
|
|
|
// Can't open another one if lottery is already present
|
|
assert_noop!(
|
|
Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false),
|
|
Error::<Test>::InProgress,
|
|
);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn buy_ticket_works_as_simple_passthrough() {
|
|
// This test checks that even if the user could not buy a ticket, that `buy_ticket` acts
|
|
// as a simple passthrough to the real call.
|
|
new_test_ext().execute_with(|| {
|
|
// No lottery set up
|
|
let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death {
|
|
dest: 2,
|
|
value: 20,
|
|
}));
|
|
// This is just a basic transfer then
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone()));
|
|
assert_eq!(Balances::free_balance(&1), 100 - 20);
|
|
assert_eq!(TicketsCount::<Test>::get(), 0);
|
|
|
|
// Lottery is set up, but too expensive to enter, so `do_buy_ticket` fails.
|
|
let calls = vec![
|
|
RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }),
|
|
RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }),
|
|
];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls));
|
|
|
|
// Ticket price of 60 would kill the user's account
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 60, 10, 5, false));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone()));
|
|
assert_eq!(Balances::free_balance(&1), 100 - 20 - 20);
|
|
assert_eq!(TicketsCount::<Test>::get(), 0);
|
|
|
|
// If call would fail, the whole thing still fails the same
|
|
let fail_call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death {
|
|
dest: 2,
|
|
value: 1000,
|
|
}));
|
|
assert_noop!(
|
|
Lottery::buy_ticket(RuntimeOrigin::signed(1), fail_call),
|
|
ArithmeticError::Underflow,
|
|
);
|
|
|
|
let bad_origin_call = Box::new(RuntimeCall::Balances(BalancesCall::force_transfer {
|
|
source: 0,
|
|
dest: 0,
|
|
value: 0,
|
|
}));
|
|
assert_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), bad_origin_call), BadOrigin,);
|
|
|
|
// User can call other txs, but doesn't get a ticket
|
|
let remark_call =
|
|
Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() }));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), remark_call));
|
|
assert_eq!(TicketsCount::<Test>::get(), 0);
|
|
|
|
let successful_call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death {
|
|
dest: 2,
|
|
value: 1,
|
|
}));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), successful_call));
|
|
assert_eq!(TicketsCount::<Test>::get(), 1);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn buy_ticket_works() {
|
|
new_test_ext().execute_with(|| {
|
|
// Set calls for the lottery.
|
|
let calls = vec![
|
|
RuntimeCall::System(SystemCall::remark { remark: vec![] }),
|
|
RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 }),
|
|
];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls));
|
|
|
|
// Can't buy ticket before start
|
|
let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death {
|
|
dest: 2,
|
|
value: 1,
|
|
}));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone()));
|
|
assert_eq!(TicketsCount::<Test>::get(), 0);
|
|
|
|
// Start lottery
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 20, 5, false));
|
|
|
|
// Go to start, buy ticket for transfer
|
|
run_to_block(5);
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call));
|
|
assert_eq!(TicketsCount::<Test>::get(), 1);
|
|
|
|
// Can't buy another of the same ticket (even if call is slightly changed)
|
|
let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_allow_death {
|
|
dest: 3,
|
|
value: 30,
|
|
}));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call));
|
|
assert_eq!(TicketsCount::<Test>::get(), 1);
|
|
|
|
// Buy ticket for remark
|
|
let call =
|
|
Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() }));
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone()));
|
|
assert_eq!(TicketsCount::<Test>::get(), 2);
|
|
|
|
// Go to end, can't buy tickets anymore
|
|
run_to_block(20);
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone()));
|
|
assert_eq!(TicketsCount::<Test>::get(), 2);
|
|
|
|
// Go to payout, can't buy tickets when there is no lottery open
|
|
run_to_block(25);
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone()));
|
|
assert_eq!(TicketsCount::<Test>::get(), 0);
|
|
assert_eq!(LotteryIndex::<Test>::get(), 1);
|
|
});
|
|
}
|
|
|
|
/// Test that `do_buy_ticket` returns an `AlreadyParticipating` error.
|
|
/// Errors of `do_buy_ticket` are ignored by `buy_ticket`, therefore this white-box test.
|
|
#[test]
|
|
fn do_buy_ticket_already_participating() {
|
|
new_test_ext().execute_with(|| {
|
|
let calls =
|
|
vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone()));
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false));
|
|
|
|
// Buying once works.
|
|
assert_ok!(Lottery::do_buy_ticket(&1, &calls[0]));
|
|
// Buying the same ticket again fails.
|
|
assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), Error::<Test>::AlreadyParticipating);
|
|
});
|
|
}
|
|
|
|
/// `buy_ticket` is a storage noop when called with the same ticket again.
|
|
#[test]
|
|
fn buy_ticket_already_participating() {
|
|
new_test_ext().execute_with(|| {
|
|
let calls =
|
|
vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone()));
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false));
|
|
|
|
// Buying once works.
|
|
let call = Box::new(calls[0].clone());
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone()));
|
|
|
|
// Buying the same ticket again returns Ok, but changes nothing.
|
|
assert_storage_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call).unwrap());
|
|
|
|
// Exactly one ticket exists.
|
|
assert_eq!(TicketsCount::<Test>::get(), 1);
|
|
});
|
|
}
|
|
|
|
/// `buy_ticket` is a storage noop when called with insufficient balance.
|
|
#[test]
|
|
fn buy_ticket_insufficient_balance() {
|
|
new_test_ext().execute_with(|| {
|
|
let calls =
|
|
vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone()));
|
|
// Price set to 100.
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 100, 10, 10, false));
|
|
let call = Box::new(calls[0].clone());
|
|
|
|
// Buying a ticket returns Ok, but changes nothing.
|
|
assert_storage_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call).unwrap());
|
|
assert!(TicketsCount::<Test>::get().is_zero());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn do_buy_ticket_insufficient_balance() {
|
|
new_test_ext().execute_with(|| {
|
|
let calls =
|
|
vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone()));
|
|
// Price set to 101.
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 101, 10, 10, false));
|
|
|
|
// Buying fails with InsufficientBalance.
|
|
assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), TokenError::FundsUnavailable,);
|
|
assert!(TicketsCount::<Test>::get().is_zero());
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn do_buy_ticket_keep_alive() {
|
|
new_test_ext().execute_with(|| {
|
|
let calls =
|
|
vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone()));
|
|
// Price set to 100.
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 100, 10, 10, false));
|
|
|
|
assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), TokenError::NotExpendable);
|
|
assert!(TicketsCount::<Test>::get().is_zero());
|
|
});
|
|
}
|
|
|
|
/// The lottery handles the case that no one participated.
|
|
#[test]
|
|
fn no_participants_works() {
|
|
new_test_ext().execute_with(|| {
|
|
let length = 20;
|
|
let delay = 5;
|
|
|
|
// Set no calls for the lottery.
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![]));
|
|
// Start lottery.
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 10, length, delay, false));
|
|
|
|
// End the lottery, no one wins.
|
|
run_to_block(length + delay);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn start_lottery_will_create_account() {
|
|
new_test_ext().execute_with(|| {
|
|
let price = 10;
|
|
let length = 20;
|
|
let delay = 5;
|
|
|
|
assert_eq!(Balances::total_balance(&Lottery::account_id()), 0);
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false));
|
|
assert_eq!(Balances::total_balance(&Lottery::account_id()), 1);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn choose_ticket_trivial_cases() {
|
|
new_test_ext().execute_with(|| {
|
|
assert!(Lottery::choose_ticket(0).is_none());
|
|
assert_eq!(Lottery::choose_ticket(1).unwrap(), 0);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn choose_account_one_participant() {
|
|
new_test_ext().execute_with(|| {
|
|
let calls =
|
|
vec![RuntimeCall::Balances(BalancesCall::transfer_allow_death { dest: 0, value: 0 })];
|
|
assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone()));
|
|
assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 10, 10, 10, false));
|
|
let call = Box::new(calls[0].clone());
|
|
|
|
// Buy one ticket with account 1.
|
|
assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call));
|
|
// Account 1 is always the winner.
|
|
assert_eq!(Lottery::choose_account().unwrap(), 1);
|
|
});
|
|
}
|