Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/dapp staking v3 precompiles #1096

Merged
merged 39 commits into from
Dec 19, 2023
Merged
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c6b63a6
Init commit
Dinonard Dec 5, 2023
e317f4d
All legacy calls covered
Dinonard Dec 5, 2023
b675c77
v2 interface first definition
Dinonard Dec 5, 2023
e2dbf48
Rename
Dinonard Dec 5, 2023
4cef3cf
Merge remote-tracking branch 'origin/feat/dapp-staking-v3' into feat/…
Dinonard Dec 5, 2023
f3b0804
Resolve merge errors
Dinonard Dec 5, 2023
13fcfe6
TODO
Dinonard Dec 6, 2023
d1668d6
v2 init implementation
Dinonard Dec 6, 2023
cd66ee7
Prepared mock
Dinonard Dec 6, 2023
777b0a8
todo
Dinonard Dec 8, 2023
58e5500
Migration to v2 utils
Dinonard Dec 14, 2023
5df87ca
More adjustments
Dinonard Dec 14, 2023
791243f
Finish adapting implementation to v2
Dinonard Dec 14, 2023
dac1dd4
Mock & fixes
Dinonard Dec 14, 2023
0ffe023
Primitive smart contract
Dinonard Dec 14, 2023
03ee458
Fix dsv3 test
Dinonard Dec 14, 2023
9e8e81b
Prepare impl & mock
Dinonard Dec 14, 2023
94b480c
Remove redundant code, adjust mock & prepare tests
Dinonard Dec 15, 2023
ff0d6cd
Tests & utils
Dinonard Dec 15, 2023
578d0e2
Test for legacy getters/view functions
Dinonard Dec 15, 2023
4ac2884
More legacy tests
Dinonard Dec 15, 2023
96e7c2b
v1 interface covered with tests
Dinonard Dec 15, 2023
fadf928
Minor refactor, organization, improvements
Dinonard Dec 15, 2023
127a80a
v2 tests
Dinonard Dec 16, 2023
7ce2370
Cleanup TODOs
Dinonard Dec 16, 2023
391a3e8
More tests
Dinonard Dec 16, 2023
c6148b1
Updates
Dinonard Dec 16, 2023
65db544
docs
Dinonard Dec 16, 2023
c8431e5
Merge remote-tracking branch 'origin/feat/dapp-staking-v3' into feat/…
Dinonard Dec 16, 2023
c880ed2
Fixes
Dinonard Dec 16, 2023
6ae4a2a
Merge remote-tracking branch 'origin/master' into feat/dapp-staking-v…
Dinonard Dec 18, 2023
feab9d6
Address review comments
Dinonard Dec 18, 2023
eea2f21
Merge remote-tracking branch 'origin/feat/dapp-staking-v3' into feat/…
Dinonard Dec 18, 2023
c4f0fc2
Merge remote-tracking branch 'origin/feat/dapp-staking-v3' into feat/…
Dinonard Dec 18, 2023
1aaa0be
Adjustments
Dinonard Dec 18, 2023
10f1019
Audit comments
Dinonard Dec 18, 2023
9504670
Fix mock
Dinonard Dec 18, 2023
30ac30d
FMT
Dinonard Dec 18, 2023
547d57f
Review comments
Dinonard Dec 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
v1 interface covered with tests
Dinonard committed Dec 15, 2023
commit 96e7c2b727e623e5639d631259878745cbd463c1
240 changes: 239 additions & 1 deletion precompiles/dapps-staking-v3/src/tests.rs
Original file line number Diff line number Diff line change
@@ -612,7 +612,7 @@ fn withdraw_unbonded_is_ok() {
let unlock_block = Ledger::<Test>::get(&staker_native).unlocking[0].unlock_block;
run_to_block(unlock_block);

// Execute legacy call, expect funds to be unlocked
// Execute legacy call, expect unlocked funds to be claimed back
System::reset_events();
precompiles()
.prepare_test(
@@ -635,6 +635,244 @@ fn withdraw_unbonded_is_ok() {
});
}

#[test]
fn claim_dapp_is_ok() {
ExternalityBuilder::build().execute_with(|| {
initialize();

// Register a dApp for staking
let staker_h160 = ALICE;
let staker_native = AddressMapper::into_account_id(staker_h160);
let smart_contract_h160 = H160::repeat_byte(0xFA);
let smart_contract =
<Test as pallet_dapp_staking_v3::Config>::SmartContract::evm(smart_contract_h160);
let amount = 1_000_000_000_000;
register_and_stake(staker_h160, smart_contract.clone(), amount);

// Advance enough eras so we can claim dApp reward
advance_to_era(3);
let claim_era = 2;

// Execute legacy call, expect dApp rewards to be claimed
System::reset_events();
precompiles()
.prepare_test(
staker_h160,
precompile_address(),
PrecompileCall::claim_dapp {
contract_h160: smart_contract_h160.into(),
era: claim_era,
},
)
.expect_no_logs()
.execute_returns(true);

let events = dapp_staking_events();
assert_eq!(events.len(), 1);
assert_matches!(
events[0].clone(),
pallet_dapp_staking_v3::Event::DAppReward {
amount: claim_era,
smart_contract,
..
}
);
});
}

#[test]
fn claim_staker_is_ok() {
ExternalityBuilder::build().execute_with(|| {
initialize();

// Register a dApp for staking
let staker_h160 = ALICE;
let staker_native = AddressMapper::into_account_id(staker_h160);
let smart_contract_h160 = H160::repeat_byte(0xFA);
let smart_contract =
<Test as pallet_dapp_staking_v3::Config>::SmartContract::evm(smart_contract_h160);
let amount = 1_000_000_000_000;
register_and_stake(staker_h160, smart_contract.clone(), amount);

// Advance enough eras so we can claim dApp reward
advance_to_era(5);
let number_of_claims = (2..=4).count();

// Execute legacy call, expect dApp rewards to be claimed
System::reset_events();
precompiles()
.prepare_test(
staker_h160,
precompile_address(),
PrecompileCall::claim_staker {
contract_h160: smart_contract_h160.into(),
},
)
.expect_no_logs()
.execute_returns(true);

// We expect multiple reward to be claimed
let events = dapp_staking_events();
assert_eq!(events.len(), number_of_claims as usize);
for era in 2..=4 {
assert_matches!(
events[era as usize - 2].clone(),
pallet_dapp_staking_v3::Event::Reward { era, .. }
);
}
});
}

#[test]
fn withdraw_from_unregistered_is_ok() {
ExternalityBuilder::build().execute_with(|| {
initialize();

// Register a dApp for staking
let staker_h160 = ALICE;
let staker_native = AddressMapper::into_account_id(staker_h160);
let smart_contract_h160 = H160::repeat_byte(0xFA);
let smart_contract =
<Test as pallet_dapp_staking_v3::Config>::SmartContract::evm(smart_contract_h160);
let amount = 1_000_000_000_000;
register_and_stake(staker_h160, smart_contract.clone(), amount);

// Unregister the dApp
assert_ok!(DappStaking::unregister(
RawOrigin::Root.into(),
smart_contract.clone()
));

// Execute legacy call, expect funds to be unstaked & withdrawn
System::reset_events();
precompiles()
.prepare_test(
staker_h160,
precompile_address(),
PrecompileCall::withdraw_from_unregistered {
contract_h160: smart_contract_h160.into(),
},
)
.expect_no_logs()
.execute_returns(true);

let events = dapp_staking_events();
assert_eq!(events.len(), 1);
assert_matches!(
events[0].clone(),
pallet_dapp_staking_v3::Event::UnstakeFromUnregistered {
smart_contract,
amount,
..
}
);
});
}

#[test]
fn nomination_transfer_is_ok() {
ExternalityBuilder::build().execute_with(|| {
initialize();

// Register the first dApp, and stke on it.
let staker_h160 = ALICE;
let staker_native = AddressMapper::into_account_id(staker_h160);
let smart_contract_h160_1 = H160::repeat_byte(0xFA);
let smart_contract_1 =
<Test as pallet_dapp_staking_v3::Config>::SmartContract::evm(smart_contract_h160_1);
let amount = 1_000_000_000_000;
register_and_stake(staker_h160, smart_contract_1.clone(), amount);

// Register the second dApp.
let smart_contract_h160_2 = H160::repeat_byte(0xBF);
let smart_contract_2 =
<Test as pallet_dapp_staking_v3::Config>::SmartContract::evm(smart_contract_h160_2);
assert_ok!(DappStaking::register(
RawOrigin::Root.into(),
staker_native.clone(),
smart_contract_2.clone()
));

// 1st scenario - transfer enough amount from the first to second dApp to cover the stake,
// but not enough for full unstake.
let minimum_stake_amount: Balance =
<Test as pallet_dapp_staking_v3::Config>::MinimumStakeAmount::get();

System::reset_events();
precompiles()
.prepare_test(
staker_h160,
precompile_address(),
PrecompileCall::nomination_transfer {
origin_contract_h160: smart_contract_h160_1.into(),
amount: minimum_stake_amount,
target_contract_h160: smart_contract_h160_2.into(),
},
)
.expect_no_logs()
.execute_returns(true);

// We expect the same amount to be staked on the second contract
let events = dapp_staking_events();
assert_eq!(events.len(), 2);
assert_matches!(
events[0].clone(),
pallet_dapp_staking_v3::Event::Unstake {
smart_contract: smart_contract_1,
amount: minimum_stake_amount,
..
}
);
assert_matches!(
events[1].clone(),
pallet_dapp_staking_v3::Event::Stake {
smart_contract: smart_contract_2,
amount: minimum_stake_amount,
..
}
);

// 2nd scenario - transfer almost the entire amount from the first to second dApp.
// The amount is large enough to trigger full unstake of the first contract.
let unstake_amount = amount - minimum_stake_amount - 1;
let expected_stake_unstake_amount = amount - minimum_stake_amount;

System::reset_events();
precompiles()
.prepare_test(
staker_h160,
precompile_address(),
PrecompileCall::nomination_transfer {
origin_contract_h160: smart_contract_h160_1.into(),
amount: unstake_amount,
target_contract_h160: smart_contract_h160_2.into(),
},
)
.expect_no_logs()
.execute_returns(true);

// We expect the same amount to be staked on the second contract
let events = dapp_staking_events();
assert_eq!(events.len(), 2);
assert_matches!(
events[0].clone(),
pallet_dapp_staking_v3::Event::Unstake {
smart_contract: smart_contract_1,
amount: expected_stake_unstake_amount,
..
}
);
assert_matches!(
events[1].clone(),
pallet_dapp_staking_v3::Event::Stake {
smart_contract: smart_contract_2,
amount: expected_stake_unstake_amount,
..
}
);
});
}

// #[test]
// fn claim_dapp_is_ok() {
// ExternalityBuilder::default()