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: support for feeByEvent query param which will abstract the fees by events #970

Merged
merged 18 commits into from
Jul 7, 2022
Merged
2 changes: 1 addition & 1 deletion docs/dist/app.bundle.js

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions docs/src/openapi-v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,31 @@ paths:
example: 0-499
schema:
type: string
- name: eventDocs
in: query
description: When set to `true`, every event will have an extra `docs`
property with a string of the events documentation.
required: false
schema:
type: boolean
default: false
- name: extrinsicDocs
in: query
description: When set to `true`, every extrinsic will have an extra `docs`
property with a string of the extrinsics documentation.
required: false
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -427,6 +452,15 @@ paths:
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -507,6 +541,15 @@ paths:
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down Expand Up @@ -554,6 +597,15 @@ paths:
schema:
type: boolean
default: false
- name: feeByEvent
in: query
description: When set to `true`, extrinsics will have their fees retrieved by their events.
This query param will use a fee estimation via `rpc::payment::query_info` to accurately identify
which event has the corresponding fee information that is closest to the value provided by `query_info`.
required: false
schema:
type: boolean
default: false
responses:
"200":
description: successful operation
Expand Down
12 changes: 9 additions & 3 deletions src/controllers/blocks/BlocksController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@ export default class BlocksController extends AbstractController<BlocksService>
* @param res Express Response
*/
private getLatestBlock: RequestHandler = async (
{ query: { eventDocs, extrinsicDocs, finalized } },
{ query: { eventDocs, extrinsicDocs, finalized, feeByEvent } },
res
) => {
const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';

let hash, queryFinalizedHead, omitFinalizedTag;
if (!this.options.finalizes) {
Expand All @@ -149,6 +150,7 @@ export default class BlocksController extends AbstractController<BlocksService>
checkFinalized: false,
queryFinalizedHead,
omitFinalizedTag,
getFeeByEvent,
};

const historicApi = await this.api.at(hash);
Expand All @@ -166,7 +168,7 @@ export default class BlocksController extends AbstractController<BlocksService>
* @param res Express Response
*/
private getBlockById: RequestHandler<INumberParam> = async (
{ params: { number }, query: { eventDocs, extrinsicDocs } },
{ params: { number }, query: { eventDocs, extrinsicDocs, feeByEvent } },
res
): Promise<void> => {
const checkFinalized = isHex(number);
Expand All @@ -175,6 +177,7 @@ export default class BlocksController extends AbstractController<BlocksService>

const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';

const queryFinalizedHead = !this.options.finalizes ? false : true;
const omitFinalizedTag = !this.options.finalizes ? true : false;
Expand All @@ -185,6 +188,7 @@ export default class BlocksController extends AbstractController<BlocksService>
checkFinalized,
queryFinalizedHead,
omitFinalizedTag,
getFeeByEvent,
};

// HistoricApi to fetch any historic information that doesnt include the current runtime
Expand Down Expand Up @@ -249,7 +253,7 @@ export default class BlocksController extends AbstractController<BlocksService>
unknown,
IRangeQueryParam
> = async (
{ query: { range, eventDocs, extrinsicDocs } },
{ query: { range, eventDocs, extrinsicDocs, feeByEvent } },
res
): Promise<void> => {
if (!range) throw new BadRequest('range query parameter must be inputted.');
Expand All @@ -259,6 +263,7 @@ export default class BlocksController extends AbstractController<BlocksService>

const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';
const queryFinalizedHead = !this.options.finalizes ? false : true;
const omitFinalizedTag = !this.options.finalizes ? true : false;
const options = {
Expand All @@ -267,6 +272,7 @@ export default class BlocksController extends AbstractController<BlocksService>
checkFinalized: false,
queryFinalizedHead,
omitFinalizedTag,
getFeeByEvent,
};

const pQueue = new PromiseQueue(4);
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/blocks/BlocksExtrinsicsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,23 @@ export default class BlocksExtrinsicsController extends AbstractController<Block
private getExtrinsicByTimepoint: RequestHandler<INumberParam> = async (
{
params: { blockId, extrinsicIndex },
query: { eventDocs, extrinsicDocs },
query: { eventDocs, extrinsicDocs, feeByEvent },
},
res
): Promise<void> => {
const hash = await this.getHashForBlock(blockId);

const eventDocsArg = eventDocs === 'true';
const extrinsicDocsArg = extrinsicDocs === 'true';
const getFeeByEvent = feeByEvent === 'true';

const options = {
eventDocs: eventDocsArg,
extrinsicDocs: extrinsicDocsArg,
checkFinalized: true,
queryFinalizedHead: false,
omitFinalizedTag: true,
getFeeByEvent,
};

const historicApi = await this.api.at(hash);
Expand Down
97 changes: 96 additions & 1 deletion src/services/blocks/BlocksService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
kusamaRegistry,
polkadotRegistry,
} from '../../test-helpers/registries';
import { IBlock } from '../../types/responses/';
import { IBlock, ISanitizedEvent } from '../../types/responses/';
import {
blockHash20000,
blockHash100000,
Expand All @@ -39,6 +39,12 @@ import {
} from '../test-helpers/mock';
import block789629 from '../test-helpers/mock/data/block789629.json';
import { events789629 } from '../test-helpers/mock/data/events789629Hex';
import {
balancesDepositEvent,
constructEvent,
treasuryEvent,
withdrawEvent,
} from '../test-helpers/mock/data/mockEventData';
import { validators789629Hex } from '../test-helpers/mock/data/validators789629Hex';
import { parseNumberOrThrow } from '../test-helpers/mock/parseNumberOrThrow';
import block789629Extrinsic from '../test-helpers/responses/blocks/block789629Extrinsic.json';
Expand Down Expand Up @@ -128,6 +134,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};

expect(
Expand Down Expand Up @@ -163,6 +170,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};
const tempGetBlock = mockApi.rpc.chain.getBlock;
mockApi.rpc.chain.getBlock = (() =>
Expand All @@ -189,6 +197,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: true,
getFeeByEvent: false,
};

const block = await blocksService.fetchBlock(
Expand Down Expand Up @@ -413,6 +422,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};

it('Returns the correct extrinisics object for block 789629', async () => {
Expand Down Expand Up @@ -518,6 +528,7 @@ describe('BlocksService', () => {
checkFinalized: false,
queryFinalizedHead: false,
omitFinalizedTag: false,
getFeeByEvent: false,
};

it('Should correctly store the most recent queried blocks', async () => {
Expand All @@ -542,4 +553,88 @@ describe('BlocksService', () => {
expect(cache.length).toBe(2);
});
});

describe('FeeByEvent', () => {
describe('getPartialFeeByEvents', () => {
const partialFee = polkadotRegistry.createType('Balance', '2490128143');
const expectedResponse = { partialFee: '2490128143' };

it('Should retrieve the correct fee for balances::withdraw events', () => {
const response = blocksService['getPartialFeeByEvents'](
withdrawEvent,
partialFee
);

expect(response).toStrictEqual(expectedResponse);
});

it('Should retrieve the correct fee for treasury::deposit events', () => {
const response = blocksService['getPartialFeeByEvents'](
treasuryEvent,
partialFee
);

expect(response).toStrictEqual(expectedResponse);
});

it('Should retrieve the correct fee for balances::deposit events', () => {
const response = blocksService['getPartialFeeByEvents'](
balancesDepositEvent,
partialFee
);

expect(response).toStrictEqual(expectedResponse);
});

it('Should error correctly when there is no fee in the events', () => {
const expectedResponseWithError = {
...expectedResponse,
error: 'Could not find a reliable fee within the events data.',
};
const emptyArray = [] as unknown as ISanitizedEvent[];
const response = blocksService['getPartialFeeByEvents'](
emptyArray,
partialFee
);

expect(response).toStrictEqual(expectedResponseWithError);
});
});

describe('getPartialFeeInfo', () => {
const mockEvent = [
constructEvent('balances', 'Withdraw', ['0x', '149000011']),
];

it('Should correctly handle `getEventByFee` when true', async () => {
const response = await blocksService['getPartialFeeInfo'](
mockEvent,
'0x',
blockHash789629,
true
);

expect(sanitizeNumbers(response)).toStrictEqual({
dispatchClass: 'Normal',
partialFee: '149000011',
error: undefined,
});
});

it('Should correctly handle `getEventByFee` when false', async () => {
const response = await blocksService['getPartialFeeInfo'](
mockEvent,
'0x',
blockHash789629,
false
);

expect(sanitizeNumbers(response)).toStrictEqual({
dispatchClass: 'Normal',
partialFee: '149000000',
error: undefined,
});
});
});
});
});
Loading