@api3/commons 0.7.1 → 0.9.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/dist/blockchain-utilities/derivation.d.ts +18 -72
- package/dist/blockchain-utilities/derivation.d.ts.map +1 -1
- package/dist/blockchain-utilities/derivation.js +28 -60
- package/dist/blockchain-utilities/derivation.js.map +1 -1
- package/dist/blockchain-utilities/schema.d.ts +11 -9
- package/dist/blockchain-utilities/schema.d.ts.map +1 -1
- package/dist/blockchain-utilities/schema.js +32 -9
- package/dist/blockchain-utilities/schema.js.map +1 -1
- package/dist/http/index.d.ts +4 -2
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +10 -5
- package/dist/http/index.js.map +1 -1
- package/dist/universal-index.d.ts +1 -0
- package/dist/universal-index.d.ts.map +1 -1
- package/dist/universal-index.js +1 -0
- package/dist/universal-index.js.map +1 -1
- package/package.json +2 -3
- package/src/blockchain-utilities/derivation.test.ts +158 -73
- package/src/blockchain-utilities/derivation.ts +41 -77
- package/src/blockchain-utilities/schema.test.ts +64 -6
- package/src/blockchain-utilities/schema.ts +46 -9
- package/src/http/index.test.ts +4 -6
- package/src/http/index.ts +14 -6
- package/src/universal-index.ts +1 -0
|
@@ -1,78 +1,24 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
|
+
import type { Address, Hex, Mnemonic } from './schema';
|
|
2
3
|
export declare const PROTOCOL_IDS: {
|
|
3
|
-
RRP:
|
|
4
|
-
PSP:
|
|
5
|
-
RELAYED_RRP:
|
|
6
|
-
RELAYED_PSP:
|
|
7
|
-
AIRSEEKER:
|
|
4
|
+
readonly RRP: "1";
|
|
5
|
+
readonly PSP: "2";
|
|
6
|
+
readonly RELAYED_RRP: "3";
|
|
7
|
+
readonly RELAYED_PSP: "4";
|
|
8
|
+
readonly AIRSEEKER: "5";
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export interface Template {
|
|
13
|
-
airnode: string;
|
|
14
|
-
encodedParameters: string;
|
|
15
|
-
endpointId: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Derives a template ID from the input parameters
|
|
19
|
-
*
|
|
20
|
-
* @param airnode an Airnode address
|
|
21
|
-
* @param encodedParameters encoded parameters, see the airnode/abi package's encode function
|
|
22
|
-
* @param endpointId An endpointID (see deriveEndpointId)
|
|
23
|
-
*/
|
|
24
|
-
export declare const deriveTemplateId: ({ airnode, encodedParameters, endpointId }: Template) => string;
|
|
25
|
-
/**
|
|
26
|
-
* Derives an endpoint ID
|
|
27
|
-
*
|
|
28
|
-
* @param oisTitle the OIS title
|
|
29
|
-
* @param endpointName the endpoint name
|
|
30
|
-
*/
|
|
10
|
+
export type ProtocolId = (typeof PROTOCOL_IDS)[keyof typeof PROTOCOL_IDS];
|
|
11
|
+
export declare const deriveTemplateIdV0: (airnode: Address, endpointId: Hex, encodedParameters: Hex) => string;
|
|
12
|
+
export declare const deriveTemplateIdV1: (endpointId: Hex, encodedParameters: Hex) => string;
|
|
31
13
|
export declare const deriveEndpointId: (oisTitle: string, endpointName: string) => string;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
* @param airnodeMnemonic the airnode's mnemonic
|
|
36
|
-
*/
|
|
37
|
-
export declare const deriveAirnodeXpub: (airnodeMnemonic: string) => string;
|
|
38
|
-
/**
|
|
39
|
-
* Derives a wallet path from a sponsor address, used for calculating a sponsor wallet.
|
|
40
|
-
*
|
|
41
|
-
* @param sponsorAddress an EVM-compatible address
|
|
42
|
-
* @param protocolId an API application protocol ID
|
|
43
|
-
*/
|
|
44
|
-
export declare function deriveWalletPathFromSponsorAddress(sponsorAddress: string, protocolId: string): string;
|
|
45
|
-
/**
|
|
46
|
-
* Encodes/formats a string as a hex-encoded bytes32 string.
|
|
47
|
-
*
|
|
48
|
-
* @param input the input string
|
|
49
|
-
*/
|
|
14
|
+
export declare const deriveAirnodeXpub: (airnodeMnemonic: Mnemonic) => string;
|
|
15
|
+
export declare function deriveWalletPathFromSponsorAddress(sponsorAddress: Address, protocolId: ProtocolId): string;
|
|
50
16
|
export declare const toBytes32String: (input: string) => string;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
export declare const
|
|
57
|
-
|
|
58
|
-
* Derives a sponsor wallet, given a mnemonic and dapiName.
|
|
59
|
-
*
|
|
60
|
-
* @param sponsorWalletMnemonic the sponsor wallet mnemonic
|
|
61
|
-
* @param dapiName the dapi name
|
|
62
|
-
*/
|
|
63
|
-
export declare const deriveSponsorWallet: (sponsorWalletMnemonic: string, dapiName: string) => ethers.Wallet;
|
|
64
|
-
/**
|
|
65
|
-
* Derives the ID of a single beacon
|
|
66
|
-
*
|
|
67
|
-
* @param airnodeAddress the airnode address of the provider that supplies the data used to update this beacon
|
|
68
|
-
* @param templateId the templateId of the template used to generate the data used to update this beacon
|
|
69
|
-
*/
|
|
70
|
-
export declare const deriveBeaconId: (airnodeAddress: string, templateId: string) => string;
|
|
71
|
-
/**
|
|
72
|
-
* Derives the ID of a set of beacons.
|
|
73
|
-
* By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
|
|
74
|
-
*
|
|
75
|
-
* @param beaconIds an ordered array of beacon ids
|
|
76
|
-
*/
|
|
77
|
-
export declare const deriveBeaconSetId: (beaconIds: string[]) => string;
|
|
17
|
+
export declare const fromBytes32String: (input: Hex) => string;
|
|
18
|
+
export declare const deriveSponsorWallet: (airnodeMnemonic: Mnemonic, dapiName: string, protocolId: ProtocolId) => ethers.Wallet;
|
|
19
|
+
export declare const deriveBeaconId: (airnodeAddress: Address, templateId: Hex) => string;
|
|
20
|
+
export declare const deriveBeaconSetId: (beaconIds: Hex[]) => string;
|
|
21
|
+
export declare const deriveHdNodeFromXpub: (xpub: string) => ethers.utils.HDNode;
|
|
22
|
+
export declare const verifyAirnodeXpub: (airnodeXpub: string, airnodeAddress: Address) => ethers.utils.HDNode;
|
|
23
|
+
export declare function deriveSponsorWalletAddress(airnodeXpub: string, sponsorAddress: Address, protocolId: ProtocolId, airnodeAddress?: Address): string;
|
|
78
24
|
//# sourceMappingURL=derivation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derivation.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"derivation.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEvD,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAE1E,eAAO,MAAM,kBAAkB,YAAa,OAAO,cAAc,GAAG,qBAAqB,GAAG,WACe,CAAC;AAE5G,eAAO,MAAM,kBAAkB,eAAgB,GAAG,qBAAqB,GAAG,WACa,CAAC;AAExF,eAAO,MAAM,gBAAgB,aAAc,MAAM,gBAAgB,MAAM,WACsC,CAAC;AAE9G,eAAO,MAAM,iBAAiB,oBAAqB,QAAQ,WACwC,CAAC;AAEpG,wBAAgB,kCAAkC,CAAC,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,UAQjG;AAED,eAAO,MAAM,eAAe,UAAW,MAAM,WAA4C,CAAC;AAE1F,eAAO,MAAM,iBAAiB,UAAW,GAAG,WAA2C,CAAC;AAExF,eAAO,MAAM,mBAAmB,oBAAqB,QAAQ,YAAY,MAAM,cAAc,UAAU,kBAStG,CAAC;AAEF,eAAO,MAAM,cAAc,mBAAoB,OAAO,cAAc,GAAG,WACe,CAAC;AAEvF,eAAO,MAAM,iBAAiB,cAAe,GAAG,EAAE,WAEuC,CAAC;AAE1F,eAAO,MAAM,oBAAoB,SAAU,MAAM,wBAA8C,CAAC;AAEhG,eAAO,MAAM,iBAAiB,gBAAiB,MAAM,kBAAkB,OAAO,KAAG,OAAO,KAAK,CAAC,MAQ7F,CAAC;AAEF,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,OAAO,EACvB,UAAU,EAAE,UAAU,EACtB,cAAc,CAAC,EAAE,OAAO,UAKzB"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.deriveBeaconSetId = exports.deriveBeaconId = exports.deriveSponsorWallet = exports.fromBytes32String = exports.toBytes32String = exports.deriveWalletPathFromSponsorAddress = exports.deriveAirnodeXpub = exports.deriveEndpointId = exports.
|
|
3
|
+
exports.deriveSponsorWalletAddress = exports.verifyAirnodeXpub = exports.deriveHdNodeFromXpub = exports.deriveBeaconSetId = exports.deriveBeaconId = exports.deriveSponsorWallet = exports.fromBytes32String = exports.toBytes32String = exports.deriveWalletPathFromSponsorAddress = exports.deriveAirnodeXpub = exports.deriveEndpointId = exports.deriveTemplateIdV1 = exports.deriveTemplateIdV0 = exports.PROTOCOL_IDS = void 0;
|
|
4
4
|
const ethers_1 = require("ethers");
|
|
5
|
-
const schema_1 = require("./schema");
|
|
6
5
|
exports.PROTOCOL_IDS = {
|
|
7
6
|
RRP: '1',
|
|
8
7
|
PSP: '2',
|
|
@@ -10,38 +9,15 @@ exports.PROTOCOL_IDS = {
|
|
|
10
9
|
RELAYED_PSP: '4',
|
|
11
10
|
AIRSEEKER: '5',
|
|
12
11
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* @param encodedParameters encoded parameters, see the airnode/abi package's encode function
|
|
18
|
-
* @param endpointId An endpointID (see deriveEndpointId)
|
|
19
|
-
*/
|
|
20
|
-
const deriveTemplateId = ({ airnode, encodedParameters, endpointId }) => ethers_1.ethers.utils.solidityKeccak256(['address', 'bytes32', 'bytes'], [airnode, endpointId, encodedParameters]);
|
|
21
|
-
exports.deriveTemplateId = deriveTemplateId;
|
|
22
|
-
/**
|
|
23
|
-
* Derives an endpoint ID
|
|
24
|
-
*
|
|
25
|
-
* @param oisTitle the OIS title
|
|
26
|
-
* @param endpointName the endpoint name
|
|
27
|
-
*/
|
|
12
|
+
const deriveTemplateIdV0 = (airnode, endpointId, encodedParameters) => ethers_1.ethers.utils.solidityKeccak256(['address', 'bytes32', 'bytes'], [airnode, endpointId, encodedParameters]);
|
|
13
|
+
exports.deriveTemplateIdV0 = deriveTemplateIdV0;
|
|
14
|
+
const deriveTemplateIdV1 = (endpointId, encodedParameters) => ethers_1.ethers.utils.solidityKeccak256(['bytes32', 'bytes'], [endpointId, encodedParameters]);
|
|
15
|
+
exports.deriveTemplateIdV1 = deriveTemplateIdV1;
|
|
28
16
|
const deriveEndpointId = (oisTitle, endpointName) => ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.defaultAbiCoder.encode(['string', 'string'], [oisTitle, endpointName]));
|
|
29
17
|
exports.deriveEndpointId = deriveEndpointId;
|
|
30
|
-
/**
|
|
31
|
-
* Derives an airnode address's xpub, required for allowing signed data consumers to verify authenticity
|
|
32
|
-
*
|
|
33
|
-
* @param airnodeMnemonic the airnode's mnemonic
|
|
34
|
-
*/
|
|
35
18
|
const deriveAirnodeXpub = (airnodeMnemonic) => ethers_1.ethers.utils.HDNode.fromMnemonic(airnodeMnemonic).derivePath("m/44'/60'/0'").neuter().extendedKey;
|
|
36
19
|
exports.deriveAirnodeXpub = deriveAirnodeXpub;
|
|
37
|
-
/**
|
|
38
|
-
* Derives a wallet path from a sponsor address, used for calculating a sponsor wallet.
|
|
39
|
-
*
|
|
40
|
-
* @param sponsorAddress an EVM-compatible address
|
|
41
|
-
* @param protocolId an API application protocol ID
|
|
42
|
-
*/
|
|
43
20
|
function deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId) {
|
|
44
|
-
schema_1.addressSchema.parse(sponsorAddress);
|
|
45
21
|
const sponsorAddressBN = ethers_1.ethers.BigNumber.from(sponsorAddress);
|
|
46
22
|
const paths = [];
|
|
47
23
|
for (let i = 0; i < 6; i++) {
|
|
@@ -51,47 +27,39 @@ function deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId) {
|
|
|
51
27
|
return `${protocolId}/${paths.join('/')}`;
|
|
52
28
|
}
|
|
53
29
|
exports.deriveWalletPathFromSponsorAddress = deriveWalletPathFromSponsorAddress;
|
|
54
|
-
/**
|
|
55
|
-
* Encodes/formats a string as a hex-encoded bytes32 string.
|
|
56
|
-
*
|
|
57
|
-
* @param input the input string
|
|
58
|
-
*/
|
|
59
30
|
const toBytes32String = (input) => ethers_1.ethers.utils.formatBytes32String(input);
|
|
60
31
|
exports.toBytes32String = toBytes32String;
|
|
61
|
-
/**
|
|
62
|
-
* Decodes a hex-encoded bytes32 string to a normal string.
|
|
63
|
-
*
|
|
64
|
-
* @param input the input hex string
|
|
65
|
-
*/
|
|
66
32
|
const fromBytes32String = (input) => ethers_1.ethers.utils.parseBytes32String(input);
|
|
67
33
|
exports.fromBytes32String = fromBytes32String;
|
|
68
|
-
|
|
69
|
-
* Derives a sponsor wallet, given a mnemonic and dapiName.
|
|
70
|
-
*
|
|
71
|
-
* @param sponsorWalletMnemonic the sponsor wallet mnemonic
|
|
72
|
-
* @param dapiName the dapi name
|
|
73
|
-
*/
|
|
74
|
-
const deriveSponsorWallet = (sponsorWalletMnemonic, dapiName) => {
|
|
34
|
+
const deriveSponsorWallet = (airnodeMnemonic, dapiName, protocolId) => {
|
|
75
35
|
// Take first 20 bytes of dapiName as sponsor address together with the "0x" prefix.
|
|
76
36
|
const sponsorAddress = ethers_1.ethers.utils.getAddress(dapiName.slice(0, 42));
|
|
77
|
-
const sponsorWallet = ethers_1.ethers.Wallet.fromMnemonic(
|
|
37
|
+
const sponsorWallet = ethers_1.ethers.Wallet.fromMnemonic(airnodeMnemonic, `m/44'/60'/0'/${deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId)}`);
|
|
78
38
|
return sponsorWallet;
|
|
79
39
|
};
|
|
80
40
|
exports.deriveSponsorWallet = deriveSponsorWallet;
|
|
81
|
-
/**
|
|
82
|
-
* Derives the ID of a single beacon
|
|
83
|
-
*
|
|
84
|
-
* @param airnodeAddress the airnode address of the provider that supplies the data used to update this beacon
|
|
85
|
-
* @param templateId the templateId of the template used to generate the data used to update this beacon
|
|
86
|
-
*/
|
|
87
41
|
const deriveBeaconId = (airnodeAddress, templateId) => ethers_1.ethers.utils.solidityKeccak256(['address', 'bytes32'], [airnodeAddress, templateId]);
|
|
88
42
|
exports.deriveBeaconId = deriveBeaconId;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
*
|
|
93
|
-
* @param beaconIds an ordered array of beacon ids
|
|
94
|
-
*/
|
|
95
|
-
const deriveBeaconSetId = (beaconIds) => ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [beaconIds]));
|
|
43
|
+
const deriveBeaconSetId = (beaconIds) =>
|
|
44
|
+
// By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
|
|
45
|
+
ethers_1.ethers.utils.keccak256(ethers_1.ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [beaconIds]));
|
|
96
46
|
exports.deriveBeaconSetId = deriveBeaconSetId;
|
|
47
|
+
const deriveHdNodeFromXpub = (xpub) => ethers_1.ethers.utils.HDNode.fromExtendedKey(xpub);
|
|
48
|
+
exports.deriveHdNodeFromXpub = deriveHdNodeFromXpub;
|
|
49
|
+
const verifyAirnodeXpub = (airnodeXpub, airnodeAddress) => {
|
|
50
|
+
// The xpub is expected to belong to the hardened path m/44'/60'/0' so we must derive the child default derivation
|
|
51
|
+
// path m/44'/60'/0'/0/0 to compare it and check if xpub belongs to the Airnode wallet.
|
|
52
|
+
const hdNode = (0, exports.deriveHdNodeFromXpub)(airnodeXpub);
|
|
53
|
+
if (airnodeAddress !== hdNode.derivePath('0/0').address) {
|
|
54
|
+
throw new Error(`xpub does not belong to Airnode: ${airnodeAddress}`);
|
|
55
|
+
}
|
|
56
|
+
return hdNode;
|
|
57
|
+
};
|
|
58
|
+
exports.verifyAirnodeXpub = verifyAirnodeXpub;
|
|
59
|
+
function deriveSponsorWalletAddress(airnodeXpub, sponsorAddress, protocolId, airnodeAddress) {
|
|
60
|
+
const hdNode = airnodeAddress ? (0, exports.verifyAirnodeXpub)(airnodeXpub, airnodeAddress) : (0, exports.deriveHdNodeFromXpub)(airnodeXpub);
|
|
61
|
+
const derivationPath = deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId);
|
|
62
|
+
return hdNode.derivePath(derivationPath).address;
|
|
63
|
+
}
|
|
64
|
+
exports.deriveSponsorWalletAddress = deriveSponsorWalletAddress;
|
|
97
65
|
//# sourceMappingURL=derivation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derivation.js","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":";;;AAAA,mCAAgC;
|
|
1
|
+
{"version":3,"file":"derivation.js","sourceRoot":"","sources":["../../src/blockchain-utilities/derivation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export declare const addressSchema: z.ZodString;
|
|
6
|
-
/**
|
|
7
|
-
* A Zod validation schema that represents an EVM-compatible hash, which includes beacon IDs and template IDs.
|
|
8
|
-
*/
|
|
9
|
-
export declare const idSchema: z.ZodString;
|
|
2
|
+
export declare const hexSchema: z.ZodString;
|
|
3
|
+
export type Hex = `0x${string}`;
|
|
4
|
+
export declare const addressSchema: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
10
5
|
export type Address = z.infer<typeof addressSchema>;
|
|
11
|
-
export
|
|
6
|
+
export declare const keccak256HashSchema: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
7
|
+
export type Keccak256Hash = z.infer<typeof keccak256HashSchema>;
|
|
8
|
+
export declare const chainIdSchema: z.ZodEffects<z.ZodString, string, string>;
|
|
9
|
+
export type ChainId = z.infer<typeof chainIdSchema>;
|
|
10
|
+
export declare const ethUnitsSchema: z.ZodUnion<[z.ZodLiteral<"wei">, z.ZodLiteral<"kwei">, z.ZodLiteral<"mwei">, z.ZodLiteral<"gwei">, z.ZodLiteral<"szabo">, z.ZodLiteral<"finney">, z.ZodLiteral<"ether">]>;
|
|
11
|
+
export type EthUnits = z.infer<typeof ethUnitsSchema>;
|
|
12
|
+
export declare const mnemonicSchema: z.ZodEffects<z.ZodString, string, string>;
|
|
13
|
+
export type Mnemonic = z.infer<typeof mnemonicSchema>;
|
|
12
14
|
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS,aAAoE,CAAC;AAE3F,MAAM,MAAM,GAAG,GAAG,KAAK,MAAM,EAAE,CAAC;AAEhC,eAAO,MAAM,aAAa,kDAQxB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,mBAAmB,kDAGC,CAAC;AAElC,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa,2CAGoD,CAAC;AAE/E,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,eAAO,MAAM,cAAc,2KAQzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,cAAc,2CAEwD,CAAC;AAEpF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.mnemonicSchema = exports.ethUnitsSchema = exports.chainIdSchema = exports.keccak256HashSchema = exports.addressSchema = exports.hexSchema = void 0;
|
|
4
|
+
const promise_utils_1 = require("@api3/promise-utils");
|
|
5
|
+
const ethers_1 = require("ethers");
|
|
4
6
|
const zod_1 = require("zod");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
exports.hexSchema = zod_1.z.string().regex(/^0x[\dA-Fa-f]+$/, 'Must be a valid hex string');
|
|
8
|
+
exports.addressSchema = zod_1.z.string().transform((value, ctx) => {
|
|
9
|
+
const goParseAddress = (0, promise_utils_1.goSync)(() => ethers_1.ethers.utils.getAddress(value));
|
|
10
|
+
if (!goParseAddress.success) {
|
|
11
|
+
ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: 'Invalid EVM address' });
|
|
12
|
+
return zod_1.z.NEVER;
|
|
13
|
+
}
|
|
14
|
+
return goParseAddress.data;
|
|
15
|
+
});
|
|
16
|
+
exports.keccak256HashSchema = zod_1.z
|
|
17
|
+
.string()
|
|
18
|
+
.regex(/^0x[\dA-Fa-f]{64}$/, 'Must be a valid EVM keccak256 hash')
|
|
19
|
+
.transform((val) => val);
|
|
20
|
+
exports.chainIdSchema = zod_1.z
|
|
21
|
+
.string()
|
|
22
|
+
.regex(/^\d+$/, 'Must be a valid chain ID')
|
|
23
|
+
.refine((chainId) => Number(chainId) > 0, 'Chain ID must be greater than 0');
|
|
24
|
+
exports.ethUnitsSchema = zod_1.z.union([
|
|
25
|
+
zod_1.z.literal('wei'),
|
|
26
|
+
zod_1.z.literal('kwei'),
|
|
27
|
+
zod_1.z.literal('mwei'),
|
|
28
|
+
zod_1.z.literal('gwei'),
|
|
29
|
+
zod_1.z.literal('szabo'),
|
|
30
|
+
zod_1.z.literal('finney'),
|
|
31
|
+
zod_1.z.literal('ether'),
|
|
32
|
+
]);
|
|
33
|
+
exports.mnemonicSchema = zod_1.z
|
|
34
|
+
.string()
|
|
35
|
+
.refine((mnemonic) => ethers_1.ethers.utils.isValidMnemonic(mnemonic), 'Invalid mnemonic');
|
|
13
36
|
//# sourceMappingURL=schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/blockchain-utilities/schema.ts"],"names":[],"mappings":";;;AAAA,uDAA6C;AAC7C,mCAAgC;AAChC,6BAAwB;AAEX,QAAA,SAAS,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,iBAAiB,EAAE,4BAA4B,CAAC,CAAC;AAI9E,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC/D,MAAM,cAAc,GAAG,IAAA,sBAAM,EAAC,GAAG,EAAE,CAAC,eAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QAC3B,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC9E,OAAO,OAAC,CAAC,KAAK,CAAC;KAChB;IAED,OAAO,cAAc,CAAC,IAAW,CAAC;AACpC,CAAC,CAAC,CAAC;AAIU,QAAA,mBAAmB,GAAG,OAAC;KACjC,MAAM,EAAE;KACR,KAAK,CAAC,oBAAoB,EAAE,oCAAoC,CAAC;KACjE,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAU,CAAC,CAAC;AAIrB,QAAA,aAAa,GAAG,OAAC;KAC3B,MAAM,EAAE;KACR,KAAK,CAAC,OAAO,EAAE,0BAA0B,CAAC;KAC1C,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,iCAAiC,CAAC,CAAC;AAIlE,QAAA,cAAc,GAAG,OAAC,CAAC,KAAK,CAAC;IACpC,OAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAChB,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACjB,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACjB,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IACjB,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAClB,OAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACnB,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC;CACnB,CAAC,CAAC;AAIU,QAAA,cAAc,GAAG,OAAC;KAC5B,MAAM,EAAE;KACR,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,eAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC,CAAC"}
|
package/dist/http/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Method, type AxiosError
|
|
1
|
+
import { type Method, type AxiosError } from 'axios';
|
|
2
2
|
export interface Request {
|
|
3
3
|
readonly method: Method;
|
|
4
4
|
readonly url: string;
|
|
@@ -8,7 +8,7 @@ export interface Request {
|
|
|
8
8
|
readonly body?: unknown;
|
|
9
9
|
}
|
|
10
10
|
export interface ErrorResponse {
|
|
11
|
-
readonly
|
|
11
|
+
readonly response: unknown;
|
|
12
12
|
readonly message: string;
|
|
13
13
|
readonly code: string | undefined;
|
|
14
14
|
}
|
|
@@ -17,11 +17,13 @@ interface ExecuteRequestSuccess<T> {
|
|
|
17
17
|
success: true;
|
|
18
18
|
errorData: undefined;
|
|
19
19
|
data: T;
|
|
20
|
+
statusCode: number;
|
|
20
21
|
}
|
|
21
22
|
interface ExecuteRequestError {
|
|
22
23
|
success: false;
|
|
23
24
|
errorData: ErrorResponse;
|
|
24
25
|
data: undefined;
|
|
26
|
+
statusCode: number | undefined;
|
|
25
27
|
}
|
|
26
28
|
export type ExecuteRequestResult<T> = ExecuteRequestError | ExecuteRequestSuccess<T>;
|
|
27
29
|
export declare function executeRequest<T>(request: Request): Promise<ExecuteRequestResult<T>>;
|
package/dist/http/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AACA,OAAc,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AACA,OAAc,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,EAAsB,MAAM,OAAO,CAAC;AAIhF,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,eAAO,MAAM,qBAAqB,UAAW,UAAU,KAAG,aAOzD,CAAC;AAEF,UAAU,qBAAqB,CAAC,CAAC;IAC/B,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,IAAI,EAAE,CAAC,CAAC;IACR,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,UAAU,mBAAmB;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,SAAS,EAAE,aAAa,CAAC;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI,mBAAmB,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAErF,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAwB1F"}
|
package/dist/http/index.js
CHANGED
|
@@ -6,12 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.executeRequest = exports.extractAxiosErrorData = void 0;
|
|
7
7
|
const promise_utils_1 = require("@api3/promise-utils");
|
|
8
8
|
const axios_1 = __importDefault(require("axios"));
|
|
9
|
-
const pick_1 = __importDefault(require("lodash/pick"));
|
|
10
9
|
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
11
10
|
const extractAxiosErrorData = (error) => {
|
|
12
11
|
// Inspired by: https://axios-http.com/docs/handling_errors
|
|
13
12
|
return {
|
|
14
|
-
|
|
13
|
+
response: error.response?.data,
|
|
15
14
|
message: error.message,
|
|
16
15
|
code: error.code,
|
|
17
16
|
};
|
|
@@ -27,10 +26,16 @@ async function executeRequest(request) {
|
|
|
27
26
|
params: queryParams,
|
|
28
27
|
timeout,
|
|
29
28
|
}));
|
|
30
|
-
if (!goAxios.success)
|
|
31
|
-
return {
|
|
29
|
+
if (!goAxios.success) {
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
errorData: (0, exports.extractAxiosErrorData)(goAxios.error),
|
|
33
|
+
data: undefined,
|
|
34
|
+
statusCode: goAxios.error.status,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
32
37
|
const response = goAxios.data;
|
|
33
|
-
return { success: true, errorData: undefined, data: response.data };
|
|
38
|
+
return { success: true, errorData: undefined, data: response.data, statusCode: response.status };
|
|
34
39
|
}
|
|
35
40
|
exports.executeRequest = executeRequest;
|
|
36
41
|
//# sourceMappingURL=index.js.map
|
package/dist/http/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":";;;;;;AAAA,uDAAyC;AACzC,kDAAgF;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":";;;;;;AAAA,uDAAyC;AACzC,kDAAgF;AAEhF,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAiB3B,MAAM,qBAAqB,GAAG,CAAC,KAAiB,EAAiB,EAAE;IACxE,2DAA2D;IAC3D,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI;QAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;AACJ,CAAC,CAAC;AAPW,QAAA,qBAAqB,yBAOhC;AAiBK,KAAK,UAAU,cAAc,CAAI,OAAgB;IACtD,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,OAAO,GAAG,kBAAkB,EAAE,GAAG,OAAO,CAAC;IAEpG,MAAM,OAAO,GAAG,MAAM,IAAA,kBAAE,EAAwC,KAAK,IAAI,EAAE,CACzE,IAAA,eAAK,EAAC;QACJ,GAAG;QACH,MAAM;QACN,OAAO;QACP,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,WAAW;QACnB,OAAO;KACR,CAAC,CACH,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;QACpB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,IAAA,6BAAqB,EAAC,OAAO,CAAC,KAAK,CAAC;YAC/C,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;SACjC,CAAC;KACH;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAE9B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AACnG,CAAC;AAxBD,wCAwBC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"universal-index.d.ts","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"universal-index.d.ts","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":"AACA,cAAc,wBAAwB,CAAC;AACvC,cAAc,QAAQ,CAAC"}
|
package/dist/universal-index.js
CHANGED
|
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
// NOTE: Only export modules which work in both Node.js and browser environments.
|
|
18
18
|
__exportStar(require("./blockchain-utilities"), exports);
|
|
19
|
+
__exportStar(require("./http"), exports);
|
|
19
20
|
//# sourceMappingURL=universal-index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"universal-index.js","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iFAAiF;AACjF,yDAAuC"}
|
|
1
|
+
{"version":3,"file":"universal-index.js","sourceRoot":"","sources":["../src/universal-index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iFAAiF;AACjF,yDAAuC;AACvC,yCAAuB"}
|
package/package.json
CHANGED
|
@@ -6,20 +6,24 @@ import {
|
|
|
6
6
|
deriveBeaconSetId,
|
|
7
7
|
deriveEndpointId,
|
|
8
8
|
deriveSponsorWallet,
|
|
9
|
-
|
|
9
|
+
deriveSponsorWalletAddress,
|
|
10
|
+
deriveTemplateIdV0,
|
|
11
|
+
deriveTemplateIdV1,
|
|
10
12
|
deriveWalletPathFromSponsorAddress,
|
|
11
13
|
fromBytes32String,
|
|
12
14
|
PROTOCOL_IDS,
|
|
13
15
|
toBytes32String,
|
|
16
|
+
verifyAirnodeXpub,
|
|
14
17
|
} from './derivation';
|
|
18
|
+
import type { Address } from './schema';
|
|
15
19
|
|
|
16
|
-
describe(
|
|
20
|
+
describe(deriveWalletPathFromSponsorAddress.name, () => {
|
|
17
21
|
it('converts address to derivation path', () => {
|
|
18
22
|
const sponsorAddress = '0x8A45eac0267dD0803Fd957723EdE10693A076698';
|
|
19
23
|
const res = deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER);
|
|
20
24
|
expect(res).toBe('5/973563544/2109481170/2137349576/871269377/610184194/17');
|
|
21
25
|
|
|
22
|
-
const randomAddress = ethers.utils.getAddress(ethers.utils.hexlify(ethers.utils.randomBytes(20)));
|
|
26
|
+
const randomAddress = ethers.utils.getAddress(ethers.utils.hexlify(ethers.utils.randomBytes(20))) as Address;
|
|
23
27
|
const randomPath = deriveWalletPathFromSponsorAddress(randomAddress, PROTOCOL_IDS.AIRSEEKER);
|
|
24
28
|
expect(res).not.toStrictEqual(randomPath);
|
|
25
29
|
});
|
|
@@ -45,103 +49,184 @@ describe('deriveWalletPathFromSponsorAddress', () => {
|
|
|
45
49
|
});
|
|
46
50
|
|
|
47
51
|
it('throws if address is an empty string', () => {
|
|
48
|
-
const sponsorAddress = '';
|
|
52
|
+
const sponsorAddress = '' as Address;
|
|
49
53
|
expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
|
|
50
54
|
expect.objectContaining({ name: expect.stringContaining('Error') })
|
|
51
55
|
);
|
|
52
56
|
});
|
|
57
|
+
});
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
describe(deriveSponsorWallet.name, () => {
|
|
60
|
+
it('derives a sponsor wallet', () => {
|
|
61
|
+
const dapiName = ethers.utils.formatBytes32String('BTC/ETH');
|
|
62
|
+
const sponsorWallet = deriveSponsorWallet(
|
|
63
|
+
'test test test test test test test test test test test junk',
|
|
64
|
+
dapiName,
|
|
65
|
+
'1'
|
|
58
66
|
);
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
expect.objectContaining({ name: expect.stringContaining('Error') })
|
|
63
|
-
);
|
|
68
|
+
expect(sponsorWallet.address).toBe('0x4f86228e0Bc58829Cd77547224291bb8d212174D');
|
|
69
|
+
});
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
it('throws deriving a sponsor wallet due to an invalid DApi name', () => {
|
|
72
|
+
const dapiName = 'invalid dapi name';
|
|
73
|
+
const throwingFn = () =>
|
|
74
|
+
deriveSponsorWallet('test test test test test test test test test test test junk', dapiName, '5');
|
|
75
|
+
|
|
76
|
+
expect(throwingFn).toThrow(expect.objectContaining({ name: expect.stringContaining('Error') }));
|
|
69
77
|
});
|
|
70
78
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
'test test test test test test test test test test test junk',
|
|
76
|
-
dapiName
|
|
79
|
+
it('derives the same sponsor wallet as Airnode', () => {
|
|
80
|
+
function deriveSponsorWalletAirnode(masterHDNode: ethers.utils.HDNode, sponsorAddress: Address): ethers.Wallet {
|
|
81
|
+
const sponsorWalletHdNode = masterHDNode.derivePath(
|
|
82
|
+
`m/44'/60'/0'/${deriveWalletPathFromSponsorAddress(sponsorAddress, '1')}`
|
|
77
83
|
);
|
|
84
|
+
return new ethers.Wallet(sponsorWalletHdNode.privateKey);
|
|
85
|
+
}
|
|
86
|
+
const mnemonic = 'achieve climb couple wait accident symbol spy blouse reduce foil echo label';
|
|
87
|
+
const hdNode = ethers.utils.HDNode.fromMnemonic(mnemonic);
|
|
78
88
|
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
// https://github.com/api3dao/airnode/blob/a4c17c28c8b31c9fb13d2828764b89f1063b702f/packages/airnode-node/src/evm/wallet.test.ts#L25
|
|
90
|
+
const expectedSponsorWallet = deriveSponsorWalletAirnode(hdNode, '0x06f509f73eefba36352bc8228f9112c3786100da');
|
|
91
|
+
const actualSponsorWallet = deriveSponsorWallet(mnemonic, '0x06f509f73eefba36352bc8228f9112c3786100da', '1');
|
|
81
92
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
expect(actualSponsorWallet.address).toBe(expectedSponsorWallet.address);
|
|
94
|
+
expect(actualSponsorWallet.address).toBe('0x228A54F33E46fbb32a62ca650Fcc9eD3C730511d');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
86
97
|
|
|
87
|
-
|
|
88
|
-
|
|
98
|
+
describe(deriveAirnodeXpub.name, () => {
|
|
99
|
+
it(`derives an airnode's xpub from a mnemonic`, () => {
|
|
100
|
+
const xpub = deriveAirnodeXpub('test test test test test test test test test test test junk');
|
|
89
101
|
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
expect(xpub).toBe(
|
|
103
|
+
'xpub6Ce9NcJvTk36xtLSrJLZqE7wtgA5deCeYs7rSQtreh4cj6ByPtrg9sD7V2FNFLPnf8heNP3FGkeV9qwfzvZNSd54JoNXVsXFYSYwHsnJxqP'
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
92
107
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
});
|
|
108
|
+
describe(deriveEndpointId.name, () => {
|
|
109
|
+
it(`derives an endpoint ID`, () => {
|
|
110
|
+
const endpointId = deriveEndpointId('weather', 'temperature');
|
|
97
111
|
|
|
98
|
-
|
|
99
|
-
|
|
112
|
+
expect(endpointId).toBe('0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
100
115
|
|
|
101
|
-
|
|
102
|
-
|
|
116
|
+
describe(deriveTemplateIdV0.name, () => {
|
|
117
|
+
it(`it derives a template ID V0`, () => {
|
|
118
|
+
const templateId = deriveTemplateIdV0(
|
|
119
|
+
'0x4E95C31894a89CdC4288669A6F294836948c862b',
|
|
120
|
+
'0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635',
|
|
121
|
+
'0x6466726f6d63455448'
|
|
122
|
+
);
|
|
103
123
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
endpointId: '0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635',
|
|
108
|
-
encodedParameters: '0x1234',
|
|
109
|
-
});
|
|
124
|
+
expect(templateId).toBe('0x25ea8b12135e4b8d49960ef9e0f967b7c0ccad136b955fbb7fbeb76da27d60b0');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
110
127
|
|
|
111
|
-
|
|
112
|
-
|
|
128
|
+
describe(deriveTemplateIdV1.name, () => {
|
|
129
|
+
it('derives templateId for V1', () => {
|
|
130
|
+
const expectedTemplateIdV1 = deriveTemplateIdV1(
|
|
131
|
+
'0x2f3a3adf6daf5a3bb00ab83aa82262a6a84b59b0a89222386135330a1819ab48',
|
|
132
|
+
'0x6466726f6d63455448'
|
|
133
|
+
);
|
|
113
134
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
135
|
+
expect(expectedTemplateIdV1).toBe('0xe5d99287b5a870c3453bc0b42769c6f37cf4a3143890e9c34753181171fac842');
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe(deriveBeaconId.name, () => {
|
|
140
|
+
it('derives a beacon ID', () => {
|
|
141
|
+
const beaconId = deriveBeaconId(
|
|
142
|
+
'0xc52EeA00154B4fF1EbbF8Ba39FDe37F1AC3B9Fd4',
|
|
143
|
+
'0x457a3b3da67e394a895ea49e534a4d91b2d009477bef15eab8cbed313925b010'
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(beaconId).toBe('0xf5c140bcb4814dfec311d38f6293e86c02d32ba1b7da027fe5b5202cae35dbc6');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe(deriveBeaconSetId.name, () => {
|
|
151
|
+
it(`derives a beacon set ID`, () => {
|
|
152
|
+
const beaconSetId = deriveBeaconSetId([
|
|
153
|
+
'0x0e30ed302a3c8eeaa0053caf5fbd0825c86ce1767584d12c69c310f0068b1176',
|
|
154
|
+
'0x496092597aef79595df1567412c6ddefd037f63a5a1572702dd469f62f31f469',
|
|
155
|
+
'0x84c1da28b2f29f0a2b0ff360d537d405d1cd69249fcf5f32ae9c2298cee6da12',
|
|
156
|
+
'0xe8655dc68f2b765c5e6d4a042ba7ba8606cf37e1c8c96676f85364ec5bfe9163',
|
|
157
|
+
'0xf5c140bcb4814dfec311d38f6293e86c02d32ba1b7da027fe5b5202cae35dbc6',
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
expect(beaconSetId).toBe('0x33bf380fd5b06a317a905b23eaf5c61ef0a9b4a20589a1bf1d13133daca34b0e');
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe(toBytes32String.name, () => {
|
|
165
|
+
it('encodes a string as a bytes32 string', () => {
|
|
166
|
+
const formattedString = toBytes32String('test string');
|
|
167
|
+
|
|
168
|
+
expect(formattedString).toBe('0x7465737420737472696e67000000000000000000000000000000000000000000');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe(fromBytes32String.name, () => {
|
|
173
|
+
it('decodes a bytes32 string to a normal string', () => {
|
|
174
|
+
const formattedString = fromBytes32String('0x7465737420737472696e67000000000000000000000000000000000000000000');
|
|
175
|
+
|
|
176
|
+
expect(formattedString).toBe('test string');
|
|
177
|
+
});
|
|
178
|
+
});
|
|
119
179
|
|
|
120
|
-
|
|
121
|
-
|
|
180
|
+
describe(verifyAirnodeXpub.name, () => {
|
|
181
|
+
it('does not throw for valid xpub/airnode combination', () => {
|
|
182
|
+
expect(() =>
|
|
183
|
+
verifyAirnodeXpub(
|
|
184
|
+
'xpub6CvZvZuFtPUtNirE36eMqYu8pRa1CEQuDon9tT4G8fisU3jj38Sn53TxdHb1SUvWiwVjJ68ytPZf45gnPM7Kg4g4CNTdyjJMevDQ1wk4tYD',
|
|
185
|
+
'0x02F5BD238B866c36f7d7b144D2889fB5e594474e'
|
|
186
|
+
)
|
|
187
|
+
).not.toThrow();
|
|
188
|
+
});
|
|
122
189
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
'
|
|
127
|
-
'
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
190
|
+
it('throws when the xpub is invalid', () => {
|
|
191
|
+
expect(() =>
|
|
192
|
+
verifyAirnodeXpub(
|
|
193
|
+
'xpub6CvZvZuFtPUtNirE36eMqYu8pRa1CEQuDon9tT4G8fisU3jj38Sn53TxdHb1SUvWiwVjJ68ytPZf45gnPM7Kg4g4CNTdyjJMevDQ1wk4tYD',
|
|
194
|
+
'0xDdfd47366cA427e75C26c9F3364EE37b33e1DD38'
|
|
195
|
+
)
|
|
196
|
+
).toThrow('xpub does not belong to Airnode: 0xDdfd47366cA427e75C26c9F3364EE37b33e1DD38');
|
|
197
|
+
});
|
|
198
|
+
});
|
|
131
199
|
|
|
132
|
-
|
|
133
|
-
|
|
200
|
+
describe(deriveSponsorWalletAddress, () => {
|
|
201
|
+
it('derives the sponsor wallet address and verifies airnode address', () => {
|
|
202
|
+
const sponsorWalletAddress = deriveSponsorWalletAddress(
|
|
203
|
+
'xpub6CvZvZuFtPUtNirE36eMqYu8pRa1CEQuDon9tT4G8fisU3jj38Sn53TxdHb1SUvWiwVjJ68ytPZf45gnPM7Kg4g4CNTdyjJMevDQ1wk4tYD',
|
|
204
|
+
'0xE9232cde1f37B029dfbB403f79429f912D7405F3',
|
|
205
|
+
'1',
|
|
206
|
+
'0x02F5BD238B866c36f7d7b144D2889fB5e594474e'
|
|
207
|
+
);
|
|
134
208
|
|
|
135
|
-
|
|
136
|
-
|
|
209
|
+
expect(sponsorWalletAddress).toBe('0xDdfd47366cA427e75C26c9F3364EE37b33e1DD38');
|
|
210
|
+
});
|
|
137
211
|
|
|
138
|
-
|
|
139
|
-
|
|
212
|
+
it('derives the sponsor wallet without xpub verifification', () => {
|
|
213
|
+
const sponsorWalletAddress = deriveSponsorWalletAddress(
|
|
214
|
+
'xpub6CvZvZuFtPUtNirE36eMqYu8pRa1CEQuDon9tT4G8fisU3jj38Sn53TxdHb1SUvWiwVjJ68ytPZf45gnPM7Kg4g4CNTdyjJMevDQ1wk4tYD',
|
|
215
|
+
'0xE9232cde1f37B029dfbB403f79429f912D7405F3',
|
|
216
|
+
'1'
|
|
217
|
+
);
|
|
140
218
|
|
|
141
|
-
|
|
142
|
-
|
|
219
|
+
expect(sponsorWalletAddress).toBe('0xDdfd47366cA427e75C26c9F3364EE37b33e1DD38');
|
|
220
|
+
});
|
|
143
221
|
|
|
144
|
-
|
|
145
|
-
|
|
222
|
+
it('verifies that xpub is valid when airnode address is provided', () => {
|
|
223
|
+
expect(() =>
|
|
224
|
+
deriveSponsorWalletAddress(
|
|
225
|
+
'xpub6CvZvZuFtPUtNirE36eMqYu8pRa1CEQuDon9tT4G8fisU3jj38Sn53TxdHb1SUvWiwVjJ68ytPZf45gnPM7Kg4g4CNTdyjJMevDQ1wk4tYD',
|
|
226
|
+
'0xE9232cde1f37B029dfbB403f79429f912D7405F3',
|
|
227
|
+
'1',
|
|
228
|
+
'0xA143283e75c8e0a3174d51e6ccA38B334E1D6b12'
|
|
229
|
+
)
|
|
230
|
+
).toThrow('xpub does not belong to Airnode: 0xA143283e75c8e0a3174d51e6ccA38B334E1D6b12');
|
|
146
231
|
});
|
|
147
232
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ethers } from 'ethers';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type { Address, Hex, Mnemonic } from './schema';
|
|
4
4
|
|
|
5
5
|
export const PROTOCOL_IDS = {
|
|
6
6
|
RRP: '1',
|
|
@@ -8,53 +8,23 @@ export const PROTOCOL_IDS = {
|
|
|
8
8
|
RELAYED_RRP: '3',
|
|
9
9
|
RELAYED_PSP: '4',
|
|
10
10
|
AIRSEEKER: '5',
|
|
11
|
-
};
|
|
11
|
+
} as const;
|
|
12
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
|
-
}
|
|
13
|
+
export type ProtocolId = (typeof PROTOCOL_IDS)[keyof typeof PROTOCOL_IDS];
|
|
21
14
|
|
|
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) =>
|
|
15
|
+
export const deriveTemplateIdV0 = (airnode: Address, endpointId: Hex, encodedParameters: Hex) =>
|
|
30
16
|
ethers.utils.solidityKeccak256(['address', 'bytes32', 'bytes'], [airnode, endpointId, encodedParameters]);
|
|
31
17
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
* @param oisTitle the OIS title
|
|
36
|
-
* @param endpointName the endpoint name
|
|
37
|
-
*/
|
|
18
|
+
export const deriveTemplateIdV1 = (endpointId: Hex, encodedParameters: Hex) =>
|
|
19
|
+
ethers.utils.solidityKeccak256(['bytes32', 'bytes'], [endpointId, encodedParameters]);
|
|
20
|
+
|
|
38
21
|
export const deriveEndpointId = (oisTitle: string, endpointName: string) =>
|
|
39
22
|
ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['string', 'string'], [oisTitle, endpointName]));
|
|
40
23
|
|
|
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) =>
|
|
24
|
+
export const deriveAirnodeXpub = (airnodeMnemonic: Mnemonic) =>
|
|
47
25
|
ethers.utils.HDNode.fromMnemonic(airnodeMnemonic).derivePath("m/44'/60'/0'").neuter().extendedKey;
|
|
48
26
|
|
|
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
|
-
|
|
27
|
+
export function deriveWalletPathFromSponsorAddress(sponsorAddress: Address, protocolId: ProtocolId) {
|
|
58
28
|
const sponsorAddressBN = ethers.BigNumber.from(sponsorAddress);
|
|
59
29
|
const paths = [];
|
|
60
30
|
for (let i = 0; i < 6; i++) {
|
|
@@ -64,53 +34,47 @@ export function deriveWalletPathFromSponsorAddress(sponsorAddress: string, proto
|
|
|
64
34
|
return `${protocolId}/${paths.join('/')}`;
|
|
65
35
|
}
|
|
66
36
|
|
|
67
|
-
/**
|
|
68
|
-
* Encodes/formats a string as a hex-encoded bytes32 string.
|
|
69
|
-
*
|
|
70
|
-
* @param input the input string
|
|
71
|
-
*/
|
|
72
37
|
export const toBytes32String = (input: string) => ethers.utils.formatBytes32String(input);
|
|
73
38
|
|
|
74
|
-
|
|
75
|
-
|
|
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) => {
|
|
39
|
+
export const fromBytes32String = (input: Hex) => ethers.utils.parseBytes32String(input);
|
|
40
|
+
|
|
41
|
+
export const deriveSponsorWallet = (airnodeMnemonic: Mnemonic, dapiName: string, protocolId: ProtocolId) => {
|
|
88
42
|
// Take first 20 bytes of dapiName as sponsor address together with the "0x" prefix.
|
|
89
|
-
const sponsorAddress = ethers.utils.getAddress(dapiName.slice(0, 42));
|
|
43
|
+
const sponsorAddress = ethers.utils.getAddress(dapiName.slice(0, 42)) as Address;
|
|
90
44
|
const sponsorWallet = ethers.Wallet.fromMnemonic(
|
|
91
|
-
|
|
92
|
-
`m/44'/60'/0'/${
|
|
93
|
-
(deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER), PROTOCOL_IDS.AIRSEEKER)
|
|
94
|
-
}`
|
|
45
|
+
airnodeMnemonic,
|
|
46
|
+
`m/44'/60'/0'/${deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId)}`
|
|
95
47
|
);
|
|
96
48
|
|
|
97
49
|
return sponsorWallet;
|
|
98
50
|
};
|
|
99
51
|
|
|
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) =>
|
|
52
|
+
export const deriveBeaconId = (airnodeAddress: Address, templateId: Hex) =>
|
|
107
53
|
ethers.utils.solidityKeccak256(['address', 'bytes32'], [airnodeAddress, templateId]);
|
|
108
54
|
|
|
109
|
-
|
|
110
|
-
|
|
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[]) =>
|
|
55
|
+
export const deriveBeaconSetId = (beaconIds: Hex[]) =>
|
|
56
|
+
// By convention beacon IDs are sorted alphabetically - the ordering impacts the resulting hash.
|
|
116
57
|
ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(['bytes32[]'], [beaconIds]));
|
|
58
|
+
|
|
59
|
+
export const deriveHdNodeFromXpub = (xpub: string) => ethers.utils.HDNode.fromExtendedKey(xpub);
|
|
60
|
+
|
|
61
|
+
export const verifyAirnodeXpub = (airnodeXpub: string, airnodeAddress: Address): ethers.utils.HDNode => {
|
|
62
|
+
// The xpub is expected to belong to the hardened path m/44'/60'/0' so we must derive the child default derivation
|
|
63
|
+
// path m/44'/60'/0'/0/0 to compare it and check if xpub belongs to the Airnode wallet.
|
|
64
|
+
const hdNode = deriveHdNodeFromXpub(airnodeXpub);
|
|
65
|
+
if (airnodeAddress !== hdNode.derivePath('0/0').address) {
|
|
66
|
+
throw new Error(`xpub does not belong to Airnode: ${airnodeAddress}`);
|
|
67
|
+
}
|
|
68
|
+
return hdNode;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export function deriveSponsorWalletAddress(
|
|
72
|
+
airnodeXpub: string,
|
|
73
|
+
sponsorAddress: Address,
|
|
74
|
+
protocolId: ProtocolId,
|
|
75
|
+
airnodeAddress?: Address
|
|
76
|
+
) {
|
|
77
|
+
const hdNode = airnodeAddress ? verifyAirnodeXpub(airnodeXpub, airnodeAddress) : deriveHdNodeFromXpub(airnodeXpub);
|
|
78
|
+
const derivationPath = deriveWalletPathFromSponsorAddress(sponsorAddress, protocolId);
|
|
79
|
+
return hdNode.derivePath(derivationPath).address;
|
|
80
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { addressSchema,
|
|
1
|
+
import { addressSchema, hexSchema, keccak256HashSchema, chainIdSchema, ethUnitsSchema, mnemonicSchema } from './schema';
|
|
2
2
|
|
|
3
|
-
describe('
|
|
4
|
-
it('validates a valid address', () => {
|
|
5
|
-
expect(
|
|
3
|
+
describe('addressSchema', () => {
|
|
4
|
+
it('validates a valid address and returns its checksum', () => {
|
|
5
|
+
expect(addressSchema.parse('0x8a45eac0267dd0803fd957723ede10693a076698')).toBe(
|
|
6
|
+
'0x8A45eac0267dD0803Fd957723EdE10693A076698'
|
|
7
|
+
);
|
|
6
8
|
});
|
|
7
9
|
|
|
8
10
|
it('throws for an invalid address', () => {
|
|
@@ -10,14 +12,70 @@ describe('schema', () => {
|
|
|
10
12
|
expect.objectContaining({ name: 'ZodError' })
|
|
11
13
|
);
|
|
12
14
|
});
|
|
15
|
+
});
|
|
13
16
|
|
|
17
|
+
describe('keccak256HashSchema', () => {
|
|
14
18
|
it('validates a valid ID', () => {
|
|
15
|
-
expect(() =>
|
|
19
|
+
expect(() =>
|
|
20
|
+
keccak256HashSchema.parse('0x3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')
|
|
21
|
+
).not.toThrow();
|
|
16
22
|
});
|
|
17
23
|
|
|
18
24
|
it('throws for an invalid ID', () => {
|
|
19
|
-
expect(() =>
|
|
25
|
+
expect(() =>
|
|
26
|
+
keccak256HashSchema.parse('0xA3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')
|
|
27
|
+
).toThrow(expect.objectContaining({ name: 'ZodError' }));
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('hexSchema', () => {
|
|
32
|
+
it('validates a valid hex string', () => {
|
|
33
|
+
expect(() => hexSchema.parse('0x3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).not.toThrow();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('throws for an invalid hex string', () => {
|
|
37
|
+
expect(() => hexSchema.parse('3528e42b017a5fbf9d2993a2df04efc3ed474357575065a111b054ddf9de2acc')).toThrow(
|
|
20
38
|
expect.objectContaining({ name: 'ZodError' })
|
|
21
39
|
);
|
|
22
40
|
});
|
|
23
41
|
});
|
|
42
|
+
|
|
43
|
+
describe('chainIdSchema', () => {
|
|
44
|
+
it('validates a valid chain ID', () => {
|
|
45
|
+
expect(() => chainIdSchema.parse('1')).not.toThrow();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('throws for an invalid chain ID', () => {
|
|
49
|
+
expect(() => chainIdSchema.parse('0')).toThrow(expect.objectContaining({ name: 'ZodError' }));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('ethUnitsSchema', () => {
|
|
54
|
+
it('validates a valid unit', () => {
|
|
55
|
+
expect(() => ethUnitsSchema.parse('wei')).not.toThrow();
|
|
56
|
+
expect(() => ethUnitsSchema.parse('kwei')).not.toThrow();
|
|
57
|
+
expect(() => ethUnitsSchema.parse('mwei')).not.toThrow();
|
|
58
|
+
expect(() => ethUnitsSchema.parse('gwei')).not.toThrow();
|
|
59
|
+
expect(() => ethUnitsSchema.parse('szabo')).not.toThrow();
|
|
60
|
+
expect(() => ethUnitsSchema.parse('finney')).not.toThrow();
|
|
61
|
+
expect(() => ethUnitsSchema.parse('ether')).not.toThrow();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('throws for an invalid unit', () => {
|
|
65
|
+
expect(() => ethUnitsSchema.parse('wei2')).toThrow(expect.objectContaining({ name: 'ZodError' }));
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('mnemonicSchema', () => {
|
|
70
|
+
it('validates a valid mnemonic', () => {
|
|
71
|
+
expect(() =>
|
|
72
|
+
mnemonicSchema.parse('destroy manual orange pole pioneer enemy detail lady cake bus shed visa')
|
|
73
|
+
).not.toThrow();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('throws for an invalid mnemonic', () => {
|
|
77
|
+
expect(() =>
|
|
78
|
+
mnemonicSchema.parse('destroy manual orange pole pioneer enemy detail lady cake bus shed WTF')
|
|
79
|
+
).toThrow(expect.objectContaining({ name: 'ZodError' }));
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -1,14 +1,51 @@
|
|
|
1
|
+
import { goSync } from '@api3/promise-utils';
|
|
2
|
+
import { ethers } from 'ethers';
|
|
1
3
|
import { z } from 'zod';
|
|
2
4
|
|
|
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');
|
|
5
|
+
export const hexSchema = z.string().regex(/^0x[\dA-Fa-f]+$/, 'Must be a valid hex string');
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
export type Hex = `0x${string}`; // Not using z.infer<typeof hexSchema> because the inferred type is just `string`.
|
|
8
|
+
|
|
9
|
+
export const addressSchema = z.string().transform((value, ctx) => {
|
|
10
|
+
const goParseAddress = goSync(() => ethers.utils.getAddress(value));
|
|
11
|
+
if (!goParseAddress.success) {
|
|
12
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid EVM address' });
|
|
13
|
+
return z.NEVER;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return goParseAddress.data as Hex;
|
|
17
|
+
});
|
|
12
18
|
|
|
13
19
|
export type Address = z.infer<typeof addressSchema>;
|
|
14
|
-
|
|
20
|
+
|
|
21
|
+
export const keccak256HashSchema = z
|
|
22
|
+
.string()
|
|
23
|
+
.regex(/^0x[\dA-Fa-f]{64}$/, 'Must be a valid EVM keccak256 hash')
|
|
24
|
+
.transform((val) => val as Hex);
|
|
25
|
+
|
|
26
|
+
export type Keccak256Hash = z.infer<typeof keccak256HashSchema>;
|
|
27
|
+
|
|
28
|
+
export const chainIdSchema = z
|
|
29
|
+
.string()
|
|
30
|
+
.regex(/^\d+$/, 'Must be a valid chain ID')
|
|
31
|
+
.refine((chainId) => Number(chainId) > 0, 'Chain ID must be greater than 0');
|
|
32
|
+
|
|
33
|
+
export type ChainId = z.infer<typeof chainIdSchema>;
|
|
34
|
+
|
|
35
|
+
export const ethUnitsSchema = z.union([
|
|
36
|
+
z.literal('wei'),
|
|
37
|
+
z.literal('kwei'),
|
|
38
|
+
z.literal('mwei'),
|
|
39
|
+
z.literal('gwei'),
|
|
40
|
+
z.literal('szabo'),
|
|
41
|
+
z.literal('finney'),
|
|
42
|
+
z.literal('ether'),
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
export type EthUnits = z.infer<typeof ethUnitsSchema>;
|
|
46
|
+
|
|
47
|
+
export const mnemonicSchema = z
|
|
48
|
+
.string()
|
|
49
|
+
.refine((mnemonic) => ethers.utils.isValidMnemonic(mnemonic), 'Invalid mnemonic');
|
|
50
|
+
|
|
51
|
+
export type Mnemonic = z.infer<typeof mnemonicSchema>;
|
package/src/http/index.test.ts
CHANGED
|
@@ -11,12 +11,9 @@ describe(extractAxiosErrorData.name, () => {
|
|
|
11
11
|
} as any as AxiosResponse);
|
|
12
12
|
|
|
13
13
|
expect(extractAxiosErrorData(axiosError)).toStrictEqual({
|
|
14
|
-
|
|
15
|
-
data: 'error data',
|
|
16
|
-
status: 500,
|
|
17
|
-
},
|
|
18
|
-
code: '500',
|
|
14
|
+
response: 'error data',
|
|
19
15
|
message: 'error message',
|
|
16
|
+
code: '500',
|
|
20
17
|
});
|
|
21
18
|
});
|
|
22
19
|
});
|
|
@@ -33,10 +30,11 @@ describe(executeRequest.name, () => {
|
|
|
33
30
|
expect(response).toStrictEqual({
|
|
34
31
|
data: undefined,
|
|
35
32
|
errorData: {
|
|
36
|
-
|
|
33
|
+
response: undefined,
|
|
37
34
|
code: 'ECONNREFUSED',
|
|
38
35
|
message: expect.any(String), // The message is empty in node@20, but "connect ECONNREFUSED ::1:9999" on node@18
|
|
39
36
|
},
|
|
37
|
+
statusCode: undefined,
|
|
40
38
|
success: false,
|
|
41
39
|
});
|
|
42
40
|
});
|
package/src/http/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { go } from '@api3/promise-utils';
|
|
2
2
|
import axios, { type Method, type AxiosError, type AxiosResponse } from 'axios';
|
|
3
|
-
import pick from 'lodash/pick';
|
|
4
3
|
|
|
5
4
|
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
6
5
|
|
|
@@ -14,7 +13,7 @@ export interface Request {
|
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
export interface ErrorResponse {
|
|
17
|
-
readonly
|
|
16
|
+
readonly response: unknown;
|
|
18
17
|
readonly message: string;
|
|
19
18
|
readonly code: string | undefined;
|
|
20
19
|
}
|
|
@@ -22,21 +21,23 @@ export interface ErrorResponse {
|
|
|
22
21
|
export const extractAxiosErrorData = (error: AxiosError): ErrorResponse => {
|
|
23
22
|
// Inspired by: https://axios-http.com/docs/handling_errors
|
|
24
23
|
return {
|
|
25
|
-
|
|
24
|
+
response: error.response?.data,
|
|
26
25
|
message: error.message,
|
|
27
26
|
code: error.code,
|
|
28
|
-
}
|
|
27
|
+
};
|
|
29
28
|
};
|
|
30
29
|
|
|
31
30
|
interface ExecuteRequestSuccess<T> {
|
|
32
31
|
success: true;
|
|
33
32
|
errorData: undefined;
|
|
34
33
|
data: T;
|
|
34
|
+
statusCode: number;
|
|
35
35
|
}
|
|
36
36
|
interface ExecuteRequestError {
|
|
37
37
|
success: false;
|
|
38
38
|
errorData: ErrorResponse;
|
|
39
39
|
data: undefined;
|
|
40
|
+
statusCode: number | undefined;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
export type ExecuteRequestResult<T> = ExecuteRequestError | ExecuteRequestSuccess<T>;
|
|
@@ -54,8 +55,15 @@ export async function executeRequest<T>(request: Request): Promise<ExecuteReques
|
|
|
54
55
|
timeout,
|
|
55
56
|
})
|
|
56
57
|
);
|
|
57
|
-
if (!goAxios.success)
|
|
58
|
+
if (!goAxios.success) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
errorData: extractAxiosErrorData(goAxios.error),
|
|
62
|
+
data: undefined,
|
|
63
|
+
statusCode: goAxios.error.status,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
58
66
|
const response = goAxios.data;
|
|
59
67
|
|
|
60
|
-
return { success: true, errorData: undefined, data: response.data };
|
|
68
|
+
return { success: true, errorData: undefined, data: response.data, statusCode: response.status };
|
|
61
69
|
}
|
package/src/universal-index.ts
CHANGED