@api3/commons 0.7.1 → 0.8.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 +15 -72
- package/dist/blockchain-utilities/derivation.d.ts.map +1 -1
- package/dist/blockchain-utilities/derivation.js +10 -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/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 +43 -30
- package/src/blockchain-utilities/derivation.ts +17 -76
- package/src/blockchain-utilities/schema.test.ts +64 -6
- package/src/blockchain-utilities/schema.ts +46 -9
- package/src/universal-index.ts +1 -0
|
@@ -1,78 +1,21 @@
|
|
|
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 fromBytes32String: (input: string) => string;
|
|
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;
|
|
78
21
|
//# 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"}
|
|
@@ -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.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,21 @@ 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;
|
|
97
47
|
//# 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"}
|
|
@@ -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,12 +6,14 @@ import {
|
|
|
6
6
|
deriveBeaconSetId,
|
|
7
7
|
deriveEndpointId,
|
|
8
8
|
deriveSponsorWallet,
|
|
9
|
-
|
|
9
|
+
deriveTemplateIdV0,
|
|
10
|
+
deriveTemplateIdV1,
|
|
10
11
|
deriveWalletPathFromSponsorAddress,
|
|
11
12
|
fromBytes32String,
|
|
12
13
|
PROTOCOL_IDS,
|
|
13
14
|
toBytes32String,
|
|
14
15
|
} from './derivation';
|
|
16
|
+
import type { Address } from './schema';
|
|
15
17
|
|
|
16
18
|
describe('deriveWalletPathFromSponsorAddress', () => {
|
|
17
19
|
it('converts address to derivation path', () => {
|
|
@@ -19,7 +21,7 @@ describe('deriveWalletPathFromSponsorAddress', () => {
|
|
|
19
21
|
const res = deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER);
|
|
20
22
|
expect(res).toBe('5/973563544/2109481170/2137349576/871269377/610184194/17');
|
|
21
23
|
|
|
22
|
-
const randomAddress = ethers.utils.getAddress(ethers.utils.hexlify(ethers.utils.randomBytes(20)));
|
|
24
|
+
const randomAddress = ethers.utils.getAddress(ethers.utils.hexlify(ethers.utils.randomBytes(20))) as Address;
|
|
23
25
|
const randomPath = deriveWalletPathFromSponsorAddress(randomAddress, PROTOCOL_IDS.AIRSEEKER);
|
|
24
26
|
expect(res).not.toStrictEqual(randomPath);
|
|
25
27
|
});
|
|
@@ -45,24 +47,7 @@ describe('deriveWalletPathFromSponsorAddress', () => {
|
|
|
45
47
|
});
|
|
46
48
|
|
|
47
49
|
it('throws if address is an empty string', () => {
|
|
48
|
-
const sponsorAddress = '';
|
|
49
|
-
expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
|
|
50
|
-
expect.objectContaining({ name: expect.stringContaining('Error') })
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('throws if address is invalid', () => {
|
|
55
|
-
let sponsorAddress = '7dD0803Fd957723EdE10693A076698';
|
|
56
|
-
expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
|
|
57
|
-
expect.objectContaining({ name: expect.stringContaining('Error') })
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
sponsorAddress = ethers.utils.hexlify(ethers.utils.randomBytes(4));
|
|
61
|
-
expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
|
|
62
|
-
expect.objectContaining({ name: expect.stringContaining('Error') })
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
sponsorAddress = ethers.utils.hexlify(ethers.utils.randomBytes(32));
|
|
50
|
+
const sponsorAddress = '' as Address;
|
|
66
51
|
expect(() => deriveWalletPathFromSponsorAddress(sponsorAddress, PROTOCOL_IDS.AIRSEEKER)).toThrow(
|
|
67
52
|
expect.objectContaining({ name: expect.stringContaining('Error') })
|
|
68
53
|
);
|
|
@@ -73,20 +58,39 @@ describe('deriveWalletPathFromSponsorAddress', () => {
|
|
|
73
58
|
const dapiName = ethers.utils.formatBytes32String('BTC/ETH');
|
|
74
59
|
const sponsorWallet = deriveSponsorWallet(
|
|
75
60
|
'test test test test test test test test test test test junk',
|
|
76
|
-
dapiName
|
|
61
|
+
dapiName,
|
|
62
|
+
'1'
|
|
77
63
|
);
|
|
78
64
|
|
|
79
|
-
expect(sponsorWallet.address).toBe('
|
|
65
|
+
expect(sponsorWallet.address).toBe('0x4f86228e0Bc58829Cd77547224291bb8d212174D');
|
|
80
66
|
});
|
|
81
67
|
|
|
82
68
|
it('throws deriving a sponsor wallet due to an invalid DApi name', () => {
|
|
83
69
|
const dapiName = 'invalid dapi name';
|
|
84
70
|
const throwingFn = () =>
|
|
85
|
-
deriveSponsorWallet('test test test test test test test test test test test junk', dapiName);
|
|
71
|
+
deriveSponsorWallet('test test test test test test test test test test test junk', dapiName, '5');
|
|
86
72
|
|
|
87
73
|
expect(throwingFn).toThrow(expect.objectContaining({ name: expect.stringContaining('Error') }));
|
|
88
74
|
});
|
|
89
75
|
|
|
76
|
+
it('derives the same sponsor wallet as Airnode', () => {
|
|
77
|
+
function deriveSponsorWalletAirnode(masterHDNode: ethers.utils.HDNode, sponsorAddress: Address): ethers.Wallet {
|
|
78
|
+
const sponsorWalletHdNode = masterHDNode.derivePath(
|
|
79
|
+
`m/44'/60'/0'/${deriveWalletPathFromSponsorAddress(sponsorAddress, '1')}`
|
|
80
|
+
);
|
|
81
|
+
return new ethers.Wallet(sponsorWalletHdNode.privateKey);
|
|
82
|
+
}
|
|
83
|
+
const mnemonic = 'achieve climb couple wait accident symbol spy blouse reduce foil echo label';
|
|
84
|
+
const hdNode = ethers.utils.HDNode.fromMnemonic(mnemonic);
|
|
85
|
+
|
|
86
|
+
// https://github.com/api3dao/airnode/blob/a4c17c28c8b31c9fb13d2828764b89f1063b702f/packages/airnode-node/src/evm/wallet.test.ts#L25
|
|
87
|
+
const expectedSponsorWallet = deriveSponsorWalletAirnode(hdNode, '0x06f509f73eefba36352bc8228f9112c3786100da');
|
|
88
|
+
const actualSponsorWallet = deriveSponsorWallet(mnemonic, '0x06f509f73eefba36352bc8228f9112c3786100da', '1');
|
|
89
|
+
|
|
90
|
+
expect(actualSponsorWallet.address).toBe(expectedSponsorWallet.address);
|
|
91
|
+
expect(actualSponsorWallet.address).toBe('0x228A54F33E46fbb32a62ca650Fcc9eD3C730511d');
|
|
92
|
+
});
|
|
93
|
+
|
|
90
94
|
it(`derives an airnode's xpub from a mnemonic`, () => {
|
|
91
95
|
const xpub = deriveAirnodeXpub('test test test test test test test test test test test junk');
|
|
92
96
|
|
|
@@ -101,14 +105,23 @@ describe('deriveWalletPathFromSponsorAddress', () => {
|
|
|
101
105
|
expect(endpointId).toBe('0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635');
|
|
102
106
|
});
|
|
103
107
|
|
|
104
|
-
it(`it derives a template ID`, () => {
|
|
105
|
-
const templateId =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
it(`it derives a template ID V0`, () => {
|
|
109
|
+
const templateId = deriveTemplateIdV0(
|
|
110
|
+
'0x4E95C31894a89CdC4288669A6F294836948c862b',
|
|
111
|
+
'0x5a82d40e44ecd3ef0906e9e82c1a20f2f4ffe4f613ac70f999047496a9cd4635',
|
|
112
|
+
'0x6466726f6d63455448'
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
expect(templateId).toBe('0x25ea8b12135e4b8d49960ef9e0f967b7c0ccad136b955fbb7fbeb76da27d60b0');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('derives templateId for V1', () => {
|
|
119
|
+
const expectedTemplateIdV1 = deriveTemplateIdV1(
|
|
120
|
+
'0x2f3a3adf6daf5a3bb00ab83aa82262a6a84b59b0a89222386135330a1819ab48',
|
|
121
|
+
'0x6466726f6d63455448'
|
|
122
|
+
);
|
|
110
123
|
|
|
111
|
-
expect(
|
|
124
|
+
expect(expectedTemplateIdV1).toBe('0xe5d99287b5a870c3453bc0b42769c6f37cf4a3143890e9c34753181171fac842');
|
|
112
125
|
});
|
|
113
126
|
|
|
114
127
|
it('derives a beacon ID', () => {
|
|
@@ -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,24 @@ 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
|
-
* 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);
|
|
39
|
+
export const fromBytes32String = (input: Hex) => ethers.utils.parseBytes32String(input);
|
|
80
40
|
|
|
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) => {
|
|
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]));
|
|
@@ -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/universal-index.ts
CHANGED