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

Investigate fungible trait Holds and Freezes overlap #1873

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/common/codecov/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ runs:
steps:
- name: Install grcov
shell: bash
run: cargo +nightly-2023-07-13 install grcov
run: cargo +nightly-2023-07-13 install --locked grcov
- name: Build
shell: bash # Limited to 10 threads max
run: cargo +nightly-2023-07-13 build -j 10 --features frequency-lint-check
Expand Down
16 changes: 16 additions & 0 deletions e2e/scaffolding/extrinsicHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -795,4 +795,20 @@ export class ExtrinsicHelper {
currentBlock = await getBlockNumber();
}
}

public static submitProposal(keys: KeyringPair, spendAmount: AnyNumber | Compact<u128>) {
return new Extrinsic(
() => ExtrinsicHelper.api.tx.treasury.proposeSpend(spendAmount, keys.address),
keys,
ExtrinsicHelper.api.events.treasury.Proposed
);
}

public static rejectProposal(keys: KeyringPair, proposalId: any) {
return new Extrinsic(
() => ExtrinsicHelper.api.tx.treasury.rejectProposal(proposalId),
keys,
ExtrinsicHelper.api.events.treasury.Rejected
);
}
}
76 changes: 75 additions & 1 deletion e2e/sudo/sudo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
import { isTestnet } from '../scaffolding/env';
import { getSudo, getFundingSource } from '../scaffolding/funding';
import { AVRO_GRAPH_CHANGE } from '../schemas/fixtures/avroGraphChangeSchemaType';
import { Bytes, u16 } from '@polkadot/types';
import { Bytes, u16, u64 } from '@polkadot/types';
import {
DOLLARS,
createDelegatorAndDelegation,
createProviderKeysAndId,
getCurrentItemizedHash,
generateSchemaPartialName,
createKeys,
createMsaAndProvider,
} from '../scaffolding/helpers';
import { AVRO_CHAT_MESSAGE } from '../stateful-pallet-storage/fixtures/itemizedSchemaType';
import { stakeToProvider } from '../scaffolding/helpers';

describe('Sudo required', function () {
let sudoKey: KeyringPair;
Expand Down Expand Up @@ -179,6 +182,77 @@ describe('Sudo required', function () {
});
});
});

describe('Capacity should not be affected by a hold being slashed', function () {
it('stake should fail when overlapping tokens are on hold', async function () {
const accountBalance: bigint = 122n * DOLLARS;
const stakeBalance: bigint = 100n * DOLLARS;
const spendBalance: bigint = 20n * DOLLARS;
const proposalBond: bigint = 100n * DOLLARS;

// Setup some keys and a provider for capacity staking
const stakeKeys: KeyringPair = createKeys('StakeKeys');
const stakeProviderId: u64 = await createMsaAndProvider(
fundingSource,
stakeKeys,
'StakeProvider',
accountBalance
);

// Create a treasury proposal which will result in a hold with minimum bond = 100 DOLLARS
const proposalExt = ExtrinsicHelper.submitProposal(stakeKeys, spendBalance);
const { target: proposalEvent } = await proposalExt.signAndSend();
assert.notEqual(proposalEvent, undefined, 'should return a Proposal event');

// Confirm that the tokens were reserved/hold in the stakeKeys account using the query API
let stakedAcctInfo = await ExtrinsicHelper.getAccountInfo(stakeKeys.address);
assert.equal(
stakedAcctInfo.data.reserved,
proposalBond,
`expected ${proposalBond} reserved balance, got ${stakedAcctInfo.data.reserved}`
);

// Create a stake that will result in overlapping tokens being frozen
// stake will allow only the balance not on hold to be staked
await assert.rejects(stakeToProvider(fundingSource, stakeKeys, stakeProviderId, stakeBalance));

// Slash the provider
const slashExt = ExtrinsicHelper.rejectProposal(sudoKey, proposalEvent?.data.proposalIndex);
const { target: slashEvent } = await slashExt.sudoSignAndSend();
assert.notEqual(slashEvent, undefined, 'should return a Treasury event');

// Confirm that the tokens were slashed from the stakeKeys account using the query API
stakedAcctInfo = await ExtrinsicHelper.getAccountInfo(stakeKeys.address);
assert.equal(
stakedAcctInfo.data.reserved,
0n,
`expected 0 reserved balance, got ${stakedAcctInfo.data.reserved}`
);
});

it('proposal should fail when overlapping tokens are on hold', async function () {
const accountBalance: bigint = 122n * DOLLARS;
const stakeBalance: bigint = 100n * DOLLARS;
const spendBalance: bigint = 20n * DOLLARS;

// Setup some keys and a provider for capacity staking
const stakeKeys: KeyringPair = createKeys('StakeKeys');
const stakeProviderId: u64 = await createMsaAndProvider(
fundingSource,
stakeKeys,
'StakeProvider',
accountBalance
);

// Create a stake that will result in overlapping tokens being frozen
await assert.doesNotReject(stakeToProvider(fundingSource, stakeKeys, stakeProviderId, stakeBalance));

// Create a treasury proposal which will result in a hold with minimum bond = 100 DOLLARS
// The proposal should fail because the stakeKeys account has overlapping tokens frozen
const proposalExt = ExtrinsicHelper.submitProposal(stakeKeys, spendBalance);
await assert.rejects(proposalExt.signAndSend());
});
});
});
});
});
Loading