Skip to content

Commit

Permalink
Moving signing templates from api-request folder
Browse files Browse the repository at this point in the history
  • Loading branch information
Siegrift committed Oct 1, 2023
1 parent 39be0ab commit 9ef0294
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 60 deletions.
5 changes: 2 additions & 3 deletions packages/data-pusher/src/api-requests/data-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import * as node from '@api3/airnode-node';
import { isNil, pick } from 'lodash';
import { getState } from '../state';
import { preProcessApiSpecifications } from '../unexported-airnode-features/api-specification-processing';
import { SignedApiUpdate, TemplateId } from '../validation/schema';
import { SignedApiUpdate } from '../validation/schema';
import { logger } from '../logger';

export type TemplateResponse = [TemplateId, node.HttpGatewayApiCallSuccessResponse];
import { TemplateResponse } from '../sign-template-data';

export const callApi = async (payload: node.ApiCallPayload) => {
logger.debug('Preprocessing API call payload', pick(payload.aggregatedApiCall, ['endpointName', 'oisTitle']));
Expand Down
20 changes: 2 additions & 18 deletions packages/data-pusher/src/api-requests/signed-api.test.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
import axios from 'axios';
import { ZodError } from 'zod';
import { postSignedApiData, signTemplateResponses } from './signed-api';
import { config, signedApiResponse, nodarySignedTemplateResponses, nodaryTemplateResponses } from '../../test/fixtures';
import { postSignedApiData } from './signed-api';
import { config, signedApiResponse, nodarySignedTemplateResponses } from '../../test/fixtures';
import { logger } from '../logger';
import * as stateModule from '../state';

describe(signTemplateResponses.name, () => {
it('signs template responses', async () => {
const state = stateModule.getInitialState(config);
jest.spyOn(stateModule, 'getState').mockReturnValue(state);
jest.useFakeTimers().setSystemTime(new Date('2023-01-20'));

const signedTemplateResponses = await signTemplateResponses(nodaryTemplateResponses);

expect(signedTemplateResponses).toEqual(nodarySignedTemplateResponses);
});

afterEach(() => {
jest.useRealTimers();
});
});

describe(postSignedApiData.name, () => {
it('posts data to central api', async () => {
const state = stateModule.getInitialState(config);
Expand Down
37 changes: 1 addition & 36 deletions packages/data-pusher/src/api-requests/signed-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ import axios, { AxiosError } from 'axios';
import { isEmpty, isNil } from 'lodash';
import { ethers } from 'ethers';
import { deriveBeaconId } from '@api3/airnode-node';
import { TemplateResponse } from './data-provider';
import { logger } from '../logger';
import { getState } from '../state';
import { SignedApiNameUpdateDelayGroup } from '../update-signed-api';
import { SignedApiPayload, SignedData, TemplateId, signedApiResponseSchema } from '../validation/schema';
import { signWithTemplateId } from '../utils';

export type SignedResponse = [TemplateId, SignedData];
import { SignedApiPayload, signedApiResponseSchema } from '../validation/schema';

export const postSignedApiData = async (group: SignedApiNameUpdateDelayGroup) => {
const {
Expand Down Expand Up @@ -70,34 +66,3 @@ export const postSignedApiData = async (group: SignedApiNameUpdateDelayGroup) =>
logger.info(`Pushed signed data updates to the signed API.`, { ...logContext, count });
return { success: true, count };
};

// TODO: This function could be moved elsewhere
export const signTemplateResponses = async (templateResponses: TemplateResponse[]) => {
logger.debug('Signing template responses', { templateResponses });

const signPromises = templateResponses.map(async ([templateId, response]) => {
const encodedValue = response.data.encodedValue;
const timestamp = Math.floor(Date.now() / 1000).toString();

const wallet = ethers.Wallet.fromMnemonic(getState().config.airnodeWalletMnemonic);
const goSignWithTemplateId = await go(() => signWithTemplateId(wallet, templateId, timestamp, encodedValue));
if (!goSignWithTemplateId.success) {
const message = `Failed to sign response. Error: "${goSignWithTemplateId.error}"`;
logger.warn(message, { templateId });
return null;
}

return [
templateId,
{
timestamp: timestamp,
encodedValue: encodedValue,
signature: goSignWithTemplateId.data,
},
];
});
const signedResponsesOrNull = await Promise.all(signPromises);
const signedResponses = signedResponsesOrNull.filter((response): response is SignedResponse => !isNil(response));

return signedResponses;
};
2 changes: 1 addition & 1 deletion packages/data-pusher/src/fetch-beacon-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { sleep } from './utils';
import { SignedApiUpdate } from './validation/schema';
import { NO_FETCH_EXIT_CODE } from './constants';
import { makeTemplateRequests } from './api-requests/data-provider';
import { signTemplateResponses } from './api-requests/signed-api';
import { signTemplateResponses } from './sign-template-data';

export const initiateFetchingBeaconData = () => {
logger.debug('Initiating fetching all beacon data');
Expand Down
19 changes: 19 additions & 0 deletions packages/data-pusher/src/sign-template-data.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { signTemplateResponses } from './sign-template-data';
import * as stateModule from './state';
import { config, nodarySignedTemplateResponses, nodaryTemplateResponses } from '../test/fixtures';

describe(signTemplateResponses.name, () => {
it('signs template responses', async () => {
const state = stateModule.getInitialState(config);
jest.spyOn(stateModule, 'getState').mockReturnValue(state);
jest.useFakeTimers().setSystemTime(new Date('2023-01-20'));

const signedTemplateResponses = await signTemplateResponses(nodaryTemplateResponses);

expect(signedTemplateResponses).toEqual(nodarySignedTemplateResponses);
});

afterEach(() => {
jest.useRealTimers();
});
});
44 changes: 44 additions & 0 deletions packages/data-pusher/src/sign-template-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { ethers } from 'ethers';
import { go } from '@api3/promise-utils';
import * as node from '@api3/airnode-node';
import { isNil } from 'lodash';
import { logger } from './logger';
import { getState } from './state';
import { signWithTemplateId } from './utils';
import { SignedData, TemplateId } from './validation/schema';

export type SignedResponse = [TemplateId, SignedData];

export type TemplateResponse = [TemplateId, node.HttpGatewayApiCallSuccessResponse];

export const signTemplateResponses = async (templateResponses: TemplateResponse[]) => {
logger.debug('Signing template responses', { templateResponses });

const signPromises = templateResponses.map(async ([templateId, response]) => {
const encodedValue = response.data.encodedValue;
const timestamp = Math.floor(Date.now() / 1000).toString();

const wallet = ethers.Wallet.fromMnemonic(getState().config.airnodeWalletMnemonic);
const goSignWithTemplateId = await go(() => signWithTemplateId(wallet, templateId, timestamp, encodedValue));
if (!goSignWithTemplateId.success) {
const message = `Failed to sign response. Error: "${goSignWithTemplateId.error}"`;
logger.warn(message, {
templateId,
});
return null;
}

return [
templateId,
{
timestamp: timestamp,
encodedValue: encodedValue,
signature: goSignWithTemplateId.data,
},
];
});
const signedResponsesOrNull = await Promise.all(signPromises);
const signedResponses = signedResponsesOrNull.filter((response): response is SignedResponse => !isNil(response));

return signedResponses;
};
3 changes: 1 addition & 2 deletions packages/data-pusher/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { PerformApiCallSuccess } from '@api3/airnode-node/dist/src/api';
import { ApiCallErrorResponse } from '@api3/airnode-node';
import { AxiosResponse } from 'axios';
import { Config } from '../src/validation/schema';
import { SignedResponse } from '../src/api-requests/signed-api';
import { TemplateResponse } from '../src/api-requests/data-provider';
import { SignedResponse, TemplateResponse } from '../src/sign-template-data';

export const config: Config = {
airnodeWalletMnemonic: 'diamond result history offer forest diagram crop armed stumble orchard stage glance',
Expand Down

0 comments on commit 9ef0294

Please sign in to comment.