Skip to content

Commit

Permalink
feat: 🎸 add extra validation for nominat procedure
Browse files Browse the repository at this point in the history
make sure at least one nominator is set and ensure none are blocked
  • Loading branch information
polymath-eric committed Jan 22, 2025
1 parent 61da779 commit a54bb7e
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 11 deletions.
38 changes: 36 additions & 2 deletions src/api/procedures/__tests__/nominateValidators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('nominateValidators procedure', () => {
dsMockUtils.cleanup();
});

it('should throw an error if the target is not a controller', async () => {
it('should throw an error if the acting account is not a controller', async () => {
const proc = procedureMockUtils.getInstance<Params, void, Storage>(mockContext, {
...storage,
ledger: null,
Expand All @@ -88,7 +88,7 @@ describe('nominateValidators procedure', () => {

await expect(
prepareNominateValidators.call(proc, {
validators: [],
validators: [validator],
})
).rejects.toThrow(expectedError);
});
Expand Down Expand Up @@ -126,6 +126,40 @@ describe('nominateValidators procedure', () => {
).rejects.toThrow(expectedError);
});

it('should throw an error if a nominator is blocked', async () => {
const proc = procedureMockUtils.getInstance<Params, void, Storage>(mockContext, storage);

const args = {
validators: [
entityMockUtils.getAccountInstance({
stakingGetCommission: { blocked: true, commission: new BigNumber(10) },
}),
],
};

const expectedError = new PolymeshError({
code: ErrorCode.ValidationError,
message: 'Validator(s) have been blocked',
});

await expect(prepareNominateValidators.call(proc, args)).rejects.toThrow(expectedError);
});

it('should throw an error if no nominators are received', async () => {
const proc = procedureMockUtils.getInstance<Params, void, Storage>(mockContext, storage);

const args = {
validators: [],
};

const expectedError = new PolymeshError({
code: ErrorCode.ValidationError,
message: 'At least one validator must be nominated',
});

await expect(prepareNominateValidators.call(proc, args)).rejects.toThrow(expectedError);
});

it('should return a nominate transaction spec', async () => {
const proc = procedureMockUtils.getInstance<Params, void, Storage>(mockContext, storage);

Expand Down
44 changes: 35 additions & 9 deletions src/api/procedures/nominateValidators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,65 @@ export async function prepareNominateValidators(

const validators = validatorsInput.map(validator => asAccount(validator, context));

if (validators.length === 0) {
throw new PolymeshError({
code: ErrorCode.ValidationError,
message: 'At least one validator must be nominated',
});
}

if (uniqBy(validators, 'address').length !== validators.length) {
throw new PolymeshError({
code: ErrorCode.ValidationError,
message: 'Validators cannot be repeated',
});
}

const commissions = await Promise.all(
const invalidCommissions = await Promise.all(
validators.map(validator => {
return validator.staking.getCommission();
})
);

const missingCommissions = commissions.reduce((missing, commission, index) => {
if (!commission) {
missing.push(index);
}
const badCommissions = invalidCommissions.reduce(
(invalidItems, commission, index) => {
if (!commission) {
invalidItems.missing.push(index);
}

if (commission?.blocked) {
invalidItems.blocked.push(index);
}

return missing;
}, [] as number[]);
return invalidItems;
},
{ missing: [] as number[], blocked: [] as number[] }
);

if (missingCommissions.length) {
if (badCommissions.missing.length) {
throw new PolymeshError({
code: ErrorCode.DataUnavailable,
message: 'Commission not found for validator(s)',
data: {
missingCommissions: missingCommissions.map(
missingCommissions: badCommissions.missing.map(
missingIndex => validators[missingIndex].address
),
},
});
}

if (badCommissions.blocked.length) {
throw new PolymeshError({
code: ErrorCode.ValidationError,
message: 'Validator(s) have been blocked',
data: {
blockedValidators: badCommissions.blocked.map(
blockedIndex => validators[blockedIndex].address
),
},
});
}

if (!ledger) {
throw new PolymeshError({
code: ErrorCode.ValidationError,
Expand Down

0 comments on commit a54bb7e

Please sign in to comment.