@api3/commons 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/blockchain-utilities/derivation.d.ts +78 -0
- package/dist/blockchain-utilities/derivation.d.ts.map +1 -0
- package/dist/blockchain-utilities/derivation.js +97 -0
- package/dist/blockchain-utilities/derivation.js.map +1 -0
- package/dist/blockchain-utilities/schema.d.ts +12 -0
- package/dist/blockchain-utilities/schema.d.ts.map +1 -0
- package/dist/blockchain-utilities/schema.js +13 -0
- package/dist/blockchain-utilities/schema.js.map +1 -0
- package/dist/logger/index.d.ts +1 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/processing/processing.d.ts +70 -18
- package/dist/processing/processing.d.ts.map +1 -1
- package/dist/processing/processing.js +145 -37
- package/dist/processing/processing.js.map +1 -1
- package/dist/processing/schema.d.ts +25 -2
- package/dist/processing/schema.d.ts.map +1 -1
- package/dist/processing/schema.js +10 -9
- package/dist/processing/schema.js.map +1 -1
- package/dist/processing/unsafe-evaluate.d.ts +1 -0
- package/dist/processing/unsafe-evaluate.d.ts.map +1 -1
- package/dist/processing/unsafe-evaluate.js +31 -1
- package/dist/processing/unsafe-evaluate.js.map +1 -1
- package/package.json +5 -3
- package/src/blockchain-utilities/README.md +5 -0
- package/src/blockchain-utilities/derivation.test.ts +147 -0
- package/src/blockchain-utilities/derivation.ts +116 -0
- package/src/blockchain-utilities/schema.test.ts +23 -0
- package/src/blockchain-utilities/schema.ts +14 -0
- package/src/logger/index.test.ts +16 -0
- package/src/logger/index.ts +8 -5
- package/src/processing/README.md +89 -14
- package/src/processing/processing.test.ts +429 -111
- package/src/processing/processing.ts +196 -47
- package/src/processing/schema.ts +21 -8
- package/src/processing/unsafe-evaluate.test.ts +220 -1
- package/src/processing/unsafe-evaluate.ts +39 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
|
|
3
|
+
import { addressSchema } from './schema';
|
|
4
|
+
|
|
5
|
+
export const PROTOCOL_IDS = {
|
|
6
|
+
RRP: '1',
|
|
7
|
+
PSP: '2',
|
|
8
|
+
RELAYED_RRP: '3',
|
|
9
|
+
RELAYED_PSP: '4',
|
|
10
|
+
AIRSEEKER: '5',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* An interface that reflects the structure of a Template
|
|
15
|
+
*/
|
|
16
|
+
export interface Template {
|
|
17
|
+
airnode: string;
|
|
18
|
+
encodedParameters: string;
|
|
19
|
+
endpointId: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Derives a template ID from the input parameters
|
|
24
|
+
*
|
|
25
|
+
* @param airnode an Airnode address
|
|
26
|
+
* @param encodedParameters encoded parameters, see the airnode/abi package's encode function
|
|
27
|
+
* @param endpointId An endpointID (see deriveEndpointId)
|
|
28
|
+
*/
|
|
29
|
+
export const deriveTemplateId = ({ airnode, encodedParameters, endpointId }: Template) =>
|
|
30
|
+
ethers.utils.solidityKeccak256(['address', 'bytes32', 'bytes'], [airnode, endpointId, encodedParameters]);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Derives an endpoint ID
|
|
34
|
+
*
|
|
35
|
+
* @param oisTitle the OIS title
|
|
36
|
+
* @param endpointName the endpoint name
|
|
37
|
+
*/
|
|
38
|
+
export const deriveEndpointId = (oisTitle: string, endpointName: string) =>
|
|
39
|
+
ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['string', 'string'], [oisTitle, endpointName]));
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Derives an airnode address's xpub, required for allowing signed data consumers to verify authenticity
|
|
43
|
+
*
|
|
44
|
+
* @param airnodeMnemonic the airnode's mnemonic
|
|
45
|
+
*/
|
|
46
|
+
export const deriveAirnodeXpub = (airnodeMnemonic: string) =>
|
|
47
|
+
ethers.utils.HDNode.fromMnemonic(airnodeMnemonic).derivePath("m/44'/60'/0'").neuter().extendedKey;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Derives a wallet path from a sponsor address, used for calculating a sponsor wallet.
|
|
51
|
+
*
|
|
52
|
+
* @param sponsorAddress an EVM-compatible address
|
|
53
|
+
* @param protocolId an API application protocol ID
|
|
54
|
+
*/
|
|
55
|
+
export function deriveWalletPathFromSponsorAddress(sponsorAddress: string, protocolId: string) {
|
|
56
|
+
addressSchema.parse(sponsorAddress);
|
|
57
|
+
|
|
58
|
+
const sponsorAddressBN = ethers.BigNumber.from(sponsorAddress);
|
|
59
|
+
const paths = [];
|
|
60
|
+
for (let i = 0; i < 6; i++) {
|
|
61
|
+
const shiftedSponsorAddressBN = sponsorAddressBN.shr(31 * i);
|
|
62
|
+
paths.push(shiftedSponsorAddressBN.mask(31).toString());
|
|
63
|
+
}
|
|
64
|
+
return `${protocolId}/${paths.join('/')}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Encodes/formats a string as a hex-encoded bytes32 string.
|
|
69
|
+
*
|
|
70
|
+
* @param input the input string
|
|
71
|
+
*/
|
|
72
|
+
export const toBytes32String = (input: string) => ethers.utils.formatBytes32String(input);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Decodes a hex-encoded bytes32 string to a normal string.
|
|
76
|
+
*
|
|
77
|
+
* @param input the input hex string
|
|
78
|
+
*/
|
|
79
|
+
export const fromBytes32String = (input: string) => ethers.utils.parseBytes32String(input);
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Derives a sponsor wallet, given a mnemonic and dapiName.
|
|
83
|
+
*
|
|
84
|
+
* @param sponsorWalletMnemonic the sponsor wallet mnemonic
|
|
85
|
+
* @param dapiName the dapi name
|
|
86
|
+
*/
|
|
87
|
+
export const deriveSponsorWallet = (sponsorWalletMnemonic: string, dapiName: string) => {
|
|
88
|
+
// Take first 20 bytes of dapiName as sponsor address together with the "0x" prefix.
|
|
89
|
+
const sponsorAddress = ethers.utils.getAddress(dapiName.slice(0, 42));
|
|
90
|
+
const sponsorWallet = ethers.Wallet.fromMnemonic(
|
|
91
|
+
sponsorWalletMnemonic,
|
|
92
|
+
`m/44'/60'/0'/${
|
|
93
|
+
(deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER), PROTOCOL_IDS.AIRSEEKER)
|
|
94
|
+
}`
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return sponsorWallet;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Derives the ID of a single beacon
|
|
102
|
+
*
|
|
103
|
+
* @param airnodeAddress the airnode address of the provider that supplies the data used to update this beacon
|
|
104
|
+
* @param templateId the templateId of the template used to generate the data used to update this beacon
|
|
105
|
+
*/
|
|
106
|
+
export const deriveBeaconId = (airnodeAddress: string, templateId: string) =>
|
|
107
|
+
ethers.utils.solidityKeccak256(['address', 'bytes32'], [airnodeAddress, templateId]);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Derives the ID of a set of beacons.
|
|
111
|
+
* By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
|
|
112
|
+
*
|
|
113
|
+
* @param beaconIds an ordered array of beacon ids
|
|
114
|
+
*/
|
|
115
|
+
export const deriveBeaconSetId = (beaconIds: string[]) =>
|
|
116
|
+
ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [beaconIds]));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { addressSchema, idSchema } from './schema';
|
|
2
|
+
|
|
3
|
+
describe('schema', () => {
|
|
4
|
+
it('validates a valid address', () => {
|
|
5
|
+
expect(() => addressSchema.parse('0x8A45eac0267dD0803Fd957723EdE10693A076698')).not.toThrow();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('throws for an invalid address', () => {
|
|
9
|
+
expect(() => addressSchema.parse('0xA8A45eac0267dD0803Fd957723EdE10693A076698')).toThrow(
|
|
10
|
+
expect.objectContaining({ name: 'ZodError' })
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('validates a valid ID', () => {
|
|
15
|
+
expect(() => idSchema.parse('0x3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).not.toThrow();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('throws for an invalid ID', () => {
|
|
19
|
+
expect(() => idSchema.parse('0xA3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).toThrow(
|
|
20
|
+
expect.objectContaining({ name: 'ZodError' })
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A Zod validation schema that represents an EVM-compatible address.
|
|
5
|
+
*/
|
|
6
|
+
export const addressSchema = z.string().regex(/^0x[\dA-Fa-f]{40}$/, 'Must be a valid EVM address');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A Zod validation schema that represents an EVM-compatible hash, which includes beacon IDs and template IDs.
|
|
10
|
+
*/
|
|
11
|
+
export const idSchema = z.string().regex(/^0x[\dA-Fa-f]{64}$/, 'Must be a valid EVM hash');
|
|
12
|
+
|
|
13
|
+
export type Address = z.infer<typeof addressSchema>;
|
|
14
|
+
export type Id = z.infer<typeof idSchema>;
|
package/src/logger/index.test.ts
CHANGED
|
@@ -108,4 +108,20 @@ describe('log context', () => {
|
|
|
108
108
|
})
|
|
109
109
|
).rejects.toThrow('some-error');
|
|
110
110
|
});
|
|
111
|
+
|
|
112
|
+
it('can log using all variants of logger.error', () => {
|
|
113
|
+
const { baseLogger, logger } = createTestLogger();
|
|
114
|
+
|
|
115
|
+
logger.error('only message');
|
|
116
|
+
logger.error('message and context', { requestId: 'parent' });
|
|
117
|
+
logger.error('message and error', new Error('some-error'));
|
|
118
|
+
logger.error('message, error and context', new Error('some-error'), { requestId: 'parent' });
|
|
119
|
+
|
|
120
|
+
expect(baseLogger.error).toHaveBeenNthCalledWith(1, 'only message', undefined);
|
|
121
|
+
expect(baseLogger.error).toHaveBeenNthCalledWith(2, 'message and context', { requestId: 'parent' });
|
|
122
|
+
expect(baseLogger.error).toHaveBeenNthCalledWith(3, 'message and error', new Error('some-error'), undefined);
|
|
123
|
+
expect(baseLogger.error).toHaveBeenNthCalledWith(4, 'message, error and context', new Error('some-error'), {
|
|
124
|
+
requestId: 'parent',
|
|
125
|
+
});
|
|
126
|
+
});
|
|
111
127
|
});
|
package/src/logger/index.ts
CHANGED
|
@@ -79,9 +79,12 @@ export interface Logger {
|
|
|
79
79
|
debug: (message: string, context?: LogContext) => void;
|
|
80
80
|
info: (message: string, context?: LogContext) => void;
|
|
81
81
|
warn: (message: string, context?: LogContext) => void;
|
|
82
|
-
error
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
// We need to handle both overloads of the `error` function. It may a bit surprising that the variants are joined with
|
|
83
|
+
// "&" instead of "|", but it forces TypeScript to be more deliberate when resolving overloads. For functions, this
|
|
84
|
+
// means the implementation must handle all overloads, and TypeScript will look for the correct overload based on the
|
|
85
|
+
// arguments provided.
|
|
86
|
+
error: ((message: string, context?: LogContext) => void) &
|
|
87
|
+
((message: string, error: Error, context?: LogContext) => void);
|
|
85
88
|
child: (options: { name: string }) => Logger;
|
|
86
89
|
}
|
|
87
90
|
|
|
@@ -105,7 +108,7 @@ export const wrapper = (logger: winston.Logger): Logger => {
|
|
|
105
108
|
logger.warn(message, fullContext);
|
|
106
109
|
},
|
|
107
110
|
// We need to handle both overloads of the `error` function
|
|
108
|
-
error: (message, errorOrLocalContext, localContext) => {
|
|
111
|
+
error: (message, errorOrLocalContext: Error | LogContext, localContext?: LogContext) => {
|
|
109
112
|
const globalContext = getAsyncLocalStorage().getStore();
|
|
110
113
|
// eslint-disable-next-line lodash/prefer-lodash-typecheck
|
|
111
114
|
if (errorOrLocalContext instanceof Error) {
|
|
@@ -113,7 +116,7 @@ export const wrapper = (logger: winston.Logger): Logger => {
|
|
|
113
116
|
logger.error(message, errorOrLocalContext, fullContext);
|
|
114
117
|
} else {
|
|
115
118
|
const fullContext =
|
|
116
|
-
globalContext || errorOrLocalContext ? { ...globalContext, ...
|
|
119
|
+
globalContext || errorOrLocalContext ? { ...globalContext, ...errorOrLocalContext } : undefined;
|
|
117
120
|
logger.error(message, fullContext);
|
|
118
121
|
}
|
|
119
122
|
},
|
package/src/processing/README.md
CHANGED
|
@@ -6,40 +6,115 @@ The pre/post processing is only supported for Node.js environments and uses inte
|
|
|
6
6
|
|
|
7
7
|
## Documentation
|
|
8
8
|
|
|
9
|
-
The processing module exports
|
|
9
|
+
The processing module exports a multiple functions related to processing (both version 1 and 2). The most important
|
|
10
|
+
functions are:
|
|
10
11
|
|
|
11
12
|
<!-- NOTE: These are copied over from "processing.d.ts" from "dist" file. -->
|
|
12
13
|
|
|
13
14
|
```ts
|
|
14
15
|
/**
|
|
15
|
-
* Pre-processes
|
|
16
|
+
* Pre-processes endpoint parameters based on the provided endpoint's processing specifications.
|
|
17
|
+
*
|
|
18
|
+
* @param preProcessingSpecifications The v1 pre-processing specifications.
|
|
19
|
+
* @param endpointParameters The parameters to be pre-processed.
|
|
20
|
+
* @param processingOptions Options to control the async processing behavior like retries and timeouts.
|
|
21
|
+
*
|
|
22
|
+
* @returns A promise that resolves to the pre-processed parameters.
|
|
23
|
+
*/
|
|
24
|
+
export declare const preProcessEndpointParametersV1: (
|
|
25
|
+
preProcessingSpecifications: ProcessingSpecifications | undefined,
|
|
26
|
+
endpointParameters: EndpointParameters,
|
|
27
|
+
processingOptions?: GoAsyncOptions
|
|
28
|
+
) => Promise<EndpointParameters>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Post-processes the response based on the provided endpoint's processing specifications. The response is usually the
|
|
32
|
+
* API call response, but this logic depends on how the processing is used by the target service. For example, Airnode
|
|
33
|
+
* allows skipping API calls in which case the response is the result of pre-processing.
|
|
34
|
+
*
|
|
35
|
+
* @param response The response to be post-processed.
|
|
36
|
+
* @param postProcessingSpecifications The v1 post-processing specifications.
|
|
37
|
+
* @param endpointParameters The endpoint parameters.
|
|
38
|
+
* @param processingOptions Options to control the async processing behavior like retries and timeouts.
|
|
39
|
+
*
|
|
40
|
+
* @returns A promise that resolves to the post-processed response.
|
|
41
|
+
*/
|
|
42
|
+
export declare const postProcessResponseV1: (
|
|
43
|
+
response: unknown,
|
|
44
|
+
postProcessingSpecifications: ProcessingSpecifications | undefined,
|
|
45
|
+
endpointParameters: EndpointParameters,
|
|
46
|
+
processingOptions?: GoAsyncOptions
|
|
47
|
+
) => Promise<unknown>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pre-processes endpoint parameters based on the provided endpoint's processing specifications.
|
|
51
|
+
*
|
|
52
|
+
* @param preProcessingSpecificationV2 The v2 pre-processing specification.
|
|
53
|
+
* @param endpointParameters The parameters to be pre-processed.
|
|
54
|
+
* @param processingOptions Options to control the async processing behavior like retries and timeouts.
|
|
55
|
+
*
|
|
56
|
+
* @returns A promise that resolves to the pre-processed parameters.
|
|
57
|
+
*/
|
|
58
|
+
export declare const preProcessEndpointParametersV2: (
|
|
59
|
+
preProcessingSpecificationV2: ProcessingSpecificationV2 | undefined,
|
|
60
|
+
endpointParameters: EndpointParameters,
|
|
61
|
+
processingOptions?: GoAsyncOptions
|
|
62
|
+
) => Promise<PreProcessingV2Response>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Post-processes the response based on the provided endpoint's processing specifications. The response is usually the
|
|
66
|
+
* API call response, but this logic depends on how the processing is used by the target service. For example, Airnode
|
|
67
|
+
* allows skipping API calls in which case the response is the result of pre-processing.
|
|
68
|
+
*
|
|
69
|
+
* @param response The response to be post-processed.
|
|
70
|
+
* @param postProcessingSpecificationV2 The v2 post-processing specification.
|
|
71
|
+
* @param endpointParameters The endpoint parameters.
|
|
72
|
+
* @param processingOptions Options to control the async processing behavior like retries and timeouts.
|
|
73
|
+
*
|
|
74
|
+
* @returns A promise that resolves to the post-processed response.
|
|
75
|
+
*/
|
|
76
|
+
export declare const postProcessResponseV2: (
|
|
77
|
+
response: unknown,
|
|
78
|
+
postProcessingSpecificationV2: ProcessingSpecificationV2 | undefined,
|
|
79
|
+
endpointParameters: EndpointParameters,
|
|
80
|
+
processingOptions?: GoAsyncOptions
|
|
81
|
+
) => Promise<PostProcessingV2Response>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Pre-processes endpoint parameters based on the provided endpoint's processing specifications. Internally it
|
|
85
|
+
* determines what processing implementation should be used.
|
|
16
86
|
*
|
|
17
87
|
* @param endpoint The endpoint containing processing specifications.
|
|
18
|
-
* @param
|
|
88
|
+
* @param endpointParameters The parameters to be pre-processed.
|
|
19
89
|
* @param processingOptions Options to control the async processing behavior like retries and timeouts.
|
|
20
90
|
*
|
|
21
91
|
* @returns A promise that resolves to the pre-processed parameters.
|
|
22
92
|
*/
|
|
23
|
-
export declare const
|
|
93
|
+
export declare const preProcessEndpointParameters: (
|
|
24
94
|
endpoint: Endpoint,
|
|
25
|
-
|
|
95
|
+
endpointParameters: EndpointParameters,
|
|
26
96
|
processingOptions?: GoAsyncOptions
|
|
27
|
-
) => Promise<
|
|
97
|
+
) => Promise<PreProcessingV2Response>;
|
|
28
98
|
|
|
29
99
|
/**
|
|
30
|
-
* Post-processes the
|
|
100
|
+
* Post-processes the response based on the provided endpoint's processing specifications. The response is usually the
|
|
101
|
+
* API call response, but this logic depends on how the processing is used by the target service. For example, Airnode
|
|
102
|
+
* allows skipping API calls in which case the response is the result of pre-processing.
|
|
31
103
|
*
|
|
32
|
-
*
|
|
104
|
+
* This function determines what processing version should be used and provides a common interface. This is useful for
|
|
105
|
+
* services that want to use processing and don't care which processing version is used.
|
|
106
|
+
*
|
|
107
|
+
* @param response The response to be post-processed.
|
|
33
108
|
* @param endpoint The endpoint containing processing specifications.
|
|
34
|
-
* @param
|
|
109
|
+
* @param endpointParameters The endpoint parameters.
|
|
35
110
|
* @param processingOptions Options to control the async processing behavior like retries and timeouts.
|
|
36
111
|
*
|
|
37
|
-
* @returns A promise that resolves to the post-processed
|
|
112
|
+
* @returns A promise that resolves to the post-processed response.
|
|
38
113
|
*/
|
|
39
|
-
export declare const
|
|
40
|
-
|
|
114
|
+
export declare const postProcessResponse: (
|
|
115
|
+
response: unknown,
|
|
41
116
|
endpoint: Endpoint,
|
|
42
|
-
|
|
117
|
+
endpointParameters: EndpointParameters,
|
|
43
118
|
processingOptions?: GoAsyncOptions
|
|
44
|
-
) => Promise<
|
|
119
|
+
) => Promise<PostProcessingV2Response>;
|
|
45
120
|
```
|