@obolnetwork/obol-sdk 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/cjs/src/ajv.js +17 -0
- package/dist/cjs/src/base.js +39 -0
- package/dist/cjs/src/constants.js +86 -0
- package/dist/cjs/src/errors.js +11 -0
- package/dist/cjs/src/hash.js +172 -0
- package/dist/cjs/src/index.js +158 -0
- package/dist/cjs/src/schema.js +72 -0
- package/dist/cjs/src/services.js +32 -0
- package/dist/cjs/src/types.js +18 -0
- package/dist/cjs/src/utils.js +11 -0
- package/dist/cjs/src/verify.js +326 -0
- package/dist/cjs/test/fixtures.js +101 -0
- package/dist/cjs/test/methods.test.js +128 -0
- package/dist/esm/src/ajv.js +10 -0
- package/dist/esm/src/base.js +35 -0
- package/dist/esm/src/constants.js +79 -0
- package/dist/esm/src/errors.js +7 -0
- package/dist/esm/src/hash.js +165 -0
- package/dist/esm/src/index.js +140 -0
- package/dist/esm/src/schema.js +69 -0
- package/dist/esm/src/services.js +28 -0
- package/dist/esm/src/types.js +15 -0
- package/dist/esm/src/utils.js +6 -0
- package/dist/esm/src/verify.js +295 -0
- package/dist/esm/test/fixtures.js +98 -0
- package/dist/esm/test/methods.test.js +126 -0
- package/dist/{ajv.d.ts → types/src/ajv.d.ts} +2 -3
- package/dist/{base.d.ts → types/src/base.d.ts} +13 -14
- package/dist/types/src/constants.d.ts +79 -0
- package/dist/{errors.d.ts → types/src/errors.d.ts} +4 -5
- package/dist/{hash.d.ts → types/src/hash.d.ts} +56 -64
- package/dist/{index.d.ts → types/src/index.d.ts} +64 -60
- package/dist/{schema.d.ts → types/src/schema.d.ts} +57 -58
- package/dist/types/src/services.d.ts +11 -0
- package/dist/{types.d.ts → types/src/types.d.ts} +153 -154
- package/dist/types/src/utils.d.ts +2 -0
- package/dist/types/src/verify.d.ts +4 -0
- package/dist/{fixtures.d.ts → types/test/fixtures.d.ts} +61 -62
- package/dist/types/test/methods.test.d.ts +1 -0
- package/package.json +54 -20
- package/src/ajv.ts +11 -0
- package/src/base.ts +44 -0
- package/src/constants.ts +118 -0
- package/src/errors.ts +11 -0
- package/src/hash.ts +250 -0
- package/src/index.ts +160 -0
- package/src/schema.ts +70 -0
- package/src/services.ts +20 -0
- package/src/types.ts +211 -0
- package/src/utils.ts +7 -0
- package/src/verify.ts +479 -0
- package/dist/ajv.d.ts.map +0 -1
- package/dist/base.d.ts.map +0 -1
- package/dist/cluster.test.d.ts +0 -2
- package/dist/cluster.test.d.ts.map +0 -1
- package/dist/constants.d.ts +0 -30
- package/dist/constants.d.ts.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/fixtures.d.ts.map +0 -1
- package/dist/hash.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.es.js +0 -15582
- package/dist/index.js +0 -15586
- package/dist/schema.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|

|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
<h1 align="center">Obol SDK</h1>
|
|
4
5
|
|
|
5
6
|
This repo contains the Obol Software Development Kit, for creating Distributed Validators with the help of the [Obol API](https://docs.obol.tech/api).
|
|
6
7
|
|
|
7
8
|
## Getting Started
|
|
8
9
|
|
|
9
|
-
Checkout our [docs](https://docs.obol.tech/docs/
|
|
10
|
+
Checkout our [docs](https://docs.obol.tech/docs/advanced/quickstart-sdk), [examples](https://github.com/ObolNetwork/obol-sdk-examples/), and SDK [reference](https://obolnetwork.github.io/obol-packages). Further guides and walkthroughs coming soon.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validatePayload = void 0;
|
|
7
|
+
const ajv_1 = __importDefault(require("ajv"));
|
|
8
|
+
function validatePayload(data, schema) {
|
|
9
|
+
const ajv = new ajv_1.default();
|
|
10
|
+
const validate = ajv.compile(schema);
|
|
11
|
+
const isValid = validate(data);
|
|
12
|
+
if (!isValid) {
|
|
13
|
+
throw new Error(`Schema compilation errors', ${validate.errors && validate.errors[0].message}`);
|
|
14
|
+
}
|
|
15
|
+
return isValid;
|
|
16
|
+
}
|
|
17
|
+
exports.validatePayload = validatePayload;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Base = void 0;
|
|
13
|
+
// src/resources/base.ts
|
|
14
|
+
const constants_js_1 = require("./constants.js");
|
|
15
|
+
const types_js_1 = require("./types.js");
|
|
16
|
+
class Base {
|
|
17
|
+
constructor({ baseUrl = constants_js_1.DEFAULT_BASE_URL, chainId = constants_js_1.DEFAULT_CHAIN_ID }) {
|
|
18
|
+
this.baseUrl = baseUrl;
|
|
19
|
+
this.chainId = chainId;
|
|
20
|
+
this.fork_version = types_js_1.FORK_MAPPING[this.chainId];
|
|
21
|
+
}
|
|
22
|
+
request(endpoint, options) {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
25
|
+
const config = Object.assign(Object.assign({}, options), { headers: Object.assign({ 'Content-Type': 'application/json', 'User-Agent': `Obol-SDK/${constants_js_1.SDK_VERSION}` }, options === null || options === void 0 ? void 0 : options.headers) });
|
|
26
|
+
try {
|
|
27
|
+
const response = yield fetch(url, config);
|
|
28
|
+
if (response.ok) {
|
|
29
|
+
return (yield response.json());
|
|
30
|
+
}
|
|
31
|
+
throw new Error(response.statusText);
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.Base = Base;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_CHAIN_ID = exports.DEFAULT_BASE_URL = exports.DefinitionFlow = exports.GENESIS_VALIDATOR_ROOT = exports.DOMAIN_DEPOSIT = exports.DOMAIN_APPLICATION_BUILDER = exports.SDK_VERSION = exports.config_version = exports.dkg_algorithm = exports.signEnrPayload = exports.signOperatorConfigHashPayload = exports.signCreatorConfigHashPayload = exports.ENRTypedMessage = exports.OperatorTypedMessage = exports.OperatorConfigHashSigningTypes = exports.EnrSigningTypes = exports.CreatorTypedMessage = exports.Domain = exports.CreatorConfigHashSigningTypes = exports.EIP712_DOMAIN_VERSION = exports.EIP712_DOMAIN_NAME = exports.CONFLICT_ERROR_MSG = void 0;
|
|
4
|
+
exports.CONFLICT_ERROR_MSG = "Conflict";
|
|
5
|
+
exports.EIP712_DOMAIN_NAME = "Obol";
|
|
6
|
+
exports.EIP712_DOMAIN_VERSION = "1";
|
|
7
|
+
exports.CreatorConfigHashSigningTypes = {
|
|
8
|
+
CreatorConfigHash: [{ name: "creator_config_hash", type: "string" }],
|
|
9
|
+
};
|
|
10
|
+
const EIP712Domain = [
|
|
11
|
+
{ name: 'name', type: 'string' },
|
|
12
|
+
{ name: 'version', type: 'string' },
|
|
13
|
+
{ name: 'chainId', type: 'uint256' },
|
|
14
|
+
];
|
|
15
|
+
const Domain = (chainId) => {
|
|
16
|
+
return {
|
|
17
|
+
name: exports.EIP712_DOMAIN_NAME,
|
|
18
|
+
version: exports.EIP712_DOMAIN_VERSION,
|
|
19
|
+
chainId,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.Domain = Domain;
|
|
23
|
+
exports.CreatorTypedMessage = Object.assign({ EIP712Domain }, exports.CreatorConfigHashSigningTypes);
|
|
24
|
+
//A conflict once updateDefinition is merged
|
|
25
|
+
exports.EnrSigningTypes = {
|
|
26
|
+
ENR: [{ name: "enr", type: "string" }],
|
|
27
|
+
};
|
|
28
|
+
exports.OperatorConfigHashSigningTypes = {
|
|
29
|
+
OperatorConfigHash: [{ name: "operator_config_hash", type: "string" }],
|
|
30
|
+
};
|
|
31
|
+
exports.OperatorTypedMessage = Object.assign({ EIP712Domain }, exports.OperatorConfigHashSigningTypes);
|
|
32
|
+
exports.ENRTypedMessage = Object.assign({ EIP712Domain }, exports.EnrSigningTypes);
|
|
33
|
+
const signCreatorConfigHashPayload = (payload, chainId) => {
|
|
34
|
+
return {
|
|
35
|
+
types: exports.CreatorTypedMessage,
|
|
36
|
+
primaryType: 'CreatorConfigHash',
|
|
37
|
+
domain: {
|
|
38
|
+
name: exports.EIP712_DOMAIN_NAME,
|
|
39
|
+
version: exports.EIP712_DOMAIN_VERSION,
|
|
40
|
+
chainId,
|
|
41
|
+
},
|
|
42
|
+
message: payload,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
exports.signCreatorConfigHashPayload = signCreatorConfigHashPayload;
|
|
46
|
+
const signOperatorConfigHashPayload = (payload, chainId) => {
|
|
47
|
+
return {
|
|
48
|
+
types: exports.OperatorTypedMessage,
|
|
49
|
+
primaryType: 'OperatorConfigHash',
|
|
50
|
+
domain: {
|
|
51
|
+
name: exports.EIP712_DOMAIN_NAME,
|
|
52
|
+
version: exports.EIP712_DOMAIN_VERSION,
|
|
53
|
+
chainId,
|
|
54
|
+
},
|
|
55
|
+
message: payload,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
exports.signOperatorConfigHashPayload = signOperatorConfigHashPayload;
|
|
59
|
+
const signEnrPayload = (payload, chainId) => {
|
|
60
|
+
return {
|
|
61
|
+
types: exports.ENRTypedMessage,
|
|
62
|
+
primaryType: 'ENR',
|
|
63
|
+
domain: {
|
|
64
|
+
name: exports.EIP712_DOMAIN_NAME,
|
|
65
|
+
version: exports.EIP712_DOMAIN_VERSION,
|
|
66
|
+
chainId,
|
|
67
|
+
},
|
|
68
|
+
message: payload,
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
exports.signEnrPayload = signEnrPayload;
|
|
72
|
+
exports.dkg_algorithm = "default";
|
|
73
|
+
exports.config_version = "v1.7.0";
|
|
74
|
+
exports.SDK_VERSION = "1.0.7";
|
|
75
|
+
exports.DOMAIN_APPLICATION_BUILDER = '00000001';
|
|
76
|
+
exports.DOMAIN_DEPOSIT = '03000000';
|
|
77
|
+
exports.GENESIS_VALIDATOR_ROOT = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
78
|
+
// Flow used to create defintion
|
|
79
|
+
var DefinitionFlow;
|
|
80
|
+
(function (DefinitionFlow) {
|
|
81
|
+
DefinitionFlow["Group"] = "LP-Group";
|
|
82
|
+
DefinitionFlow["Solo"] = "LP-Solo";
|
|
83
|
+
DefinitionFlow["Charon"] = "Charon-Command";
|
|
84
|
+
})(DefinitionFlow || (exports.DefinitionFlow = DefinitionFlow = {}));
|
|
85
|
+
exports.DEFAULT_BASE_URL = "https://api.obol.tech";
|
|
86
|
+
exports.DEFAULT_CHAIN_ID = 1;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConflictError = void 0;
|
|
4
|
+
class ConflictError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(`This Cluster has been already posted.`);
|
|
7
|
+
this.name = 'ConflictError';
|
|
8
|
+
Object.setPrototypeOf(this, ConflictError.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.ConflictError = ConflictError;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clusterLockHash = exports.clusterDefinitionContainerType = exports.validatorsContainerType = exports.creatorContainerType = exports.operatorContainerType = exports.hashClusterDefinition = exports.clusterConfigOrDefinitionHash = void 0;
|
|
4
|
+
const ssz_1 = require("@chainsafe/ssz");
|
|
5
|
+
const utils_js_1 = require("./utils.js");
|
|
6
|
+
//cluster-definition
|
|
7
|
+
/**
|
|
8
|
+
* @param cluster The cluster configuration or the cluster definition
|
|
9
|
+
* @param configOnly a boolean to indicate config hash or definition hash
|
|
10
|
+
* @returns The config hash or the definition hash in of the corresponding cluster
|
|
11
|
+
*/
|
|
12
|
+
const clusterConfigOrDefinitionHash = (cluster, configOnly) => {
|
|
13
|
+
const definitionType = (0, exports.clusterDefinitionContainerType)(configOnly);
|
|
14
|
+
const val = (0, exports.hashClusterDefinition)(cluster, configOnly);
|
|
15
|
+
return ('0x' + Buffer.from(definitionType.hashTreeRoot(val).buffer).toString('hex'));
|
|
16
|
+
};
|
|
17
|
+
exports.clusterConfigOrDefinitionHash = clusterConfigOrDefinitionHash;
|
|
18
|
+
const hashClusterDefinition = (cluster, configOnly) => {
|
|
19
|
+
const definitionType = (0, exports.clusterDefinitionContainerType)(configOnly);
|
|
20
|
+
const val = definitionType.defaultValue();
|
|
21
|
+
//order should be same as charon https://github.com/ObolNetwork/charon/blob/d00b31e6465a260a43ce40f15c47fb5a5b009042/cluster/ssz.go#L285
|
|
22
|
+
val.uuid = (0, utils_js_1.strToUint8Array)(cluster.uuid);
|
|
23
|
+
val.name = (0, utils_js_1.strToUint8Array)(cluster.name);
|
|
24
|
+
val.version = (0, utils_js_1.strToUint8Array)(cluster.version);
|
|
25
|
+
val.timestamp = (0, utils_js_1.strToUint8Array)(cluster.timestamp);
|
|
26
|
+
val.num_validators = cluster.num_validators;
|
|
27
|
+
val.threshold = cluster.threshold;
|
|
28
|
+
val.dkg_algorithm = (0, utils_js_1.strToUint8Array)(cluster.dkg_algorithm);
|
|
29
|
+
val.fork_version = (0, ssz_1.fromHexString)(cluster.fork_version);
|
|
30
|
+
val.operators = cluster.operators.map((operator) => {
|
|
31
|
+
return configOnly
|
|
32
|
+
? { address: (0, ssz_1.fromHexString)(operator.address) }
|
|
33
|
+
: {
|
|
34
|
+
address: (0, ssz_1.fromHexString)(operator.address),
|
|
35
|
+
enr: (0, utils_js_1.strToUint8Array)(operator.enr),
|
|
36
|
+
config_signature: (0, ssz_1.fromHexString)(operator.config_signature),
|
|
37
|
+
enr_signature: (0, ssz_1.fromHexString)(operator.enr_signature),
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
val.creator = configOnly
|
|
41
|
+
? { address: (0, ssz_1.fromHexString)(cluster.creator.address) }
|
|
42
|
+
: {
|
|
43
|
+
address: (0, ssz_1.fromHexString)(cluster.creator.address),
|
|
44
|
+
config_signature: (0, ssz_1.fromHexString)(cluster.creator.config_signature),
|
|
45
|
+
};
|
|
46
|
+
val.validators = cluster.validators.map((validator) => {
|
|
47
|
+
return {
|
|
48
|
+
fee_recipient_address: (0, ssz_1.fromHexString)(validator.fee_recipient_address),
|
|
49
|
+
withdrawal_address: (0, ssz_1.fromHexString)(validator.withdrawal_address),
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
if (!configOnly) {
|
|
53
|
+
val.config_hash = (0, ssz_1.fromHexString)(cluster.config_hash);
|
|
54
|
+
}
|
|
55
|
+
return val;
|
|
56
|
+
};
|
|
57
|
+
exports.hashClusterDefinition = hashClusterDefinition;
|
|
58
|
+
const operatorAddressWrapperType = new ssz_1.ContainerType({
|
|
59
|
+
address: new ssz_1.ByteVectorType(20),
|
|
60
|
+
});
|
|
61
|
+
const creatorAddressWrapperType = new ssz_1.ContainerType({
|
|
62
|
+
address: new ssz_1.ByteVectorType(20),
|
|
63
|
+
});
|
|
64
|
+
exports.operatorContainerType = new ssz_1.ContainerType({
|
|
65
|
+
address: new ssz_1.ByteVectorType(20),
|
|
66
|
+
enr: new ssz_1.ByteListType(1024), // This needs to be dynamic, since ENRs do not have a fixed length.
|
|
67
|
+
config_signature: new ssz_1.ByteVectorType(65),
|
|
68
|
+
enr_signature: new ssz_1.ByteVectorType(65),
|
|
69
|
+
});
|
|
70
|
+
exports.creatorContainerType = new ssz_1.ContainerType({
|
|
71
|
+
address: new ssz_1.ByteVectorType(20),
|
|
72
|
+
config_signature: new ssz_1.ByteVectorType(65),
|
|
73
|
+
});
|
|
74
|
+
exports.validatorsContainerType = new ssz_1.ContainerType({
|
|
75
|
+
fee_recipient_address: new ssz_1.ByteVectorType(20),
|
|
76
|
+
withdrawal_address: new ssz_1.ByteVectorType(20),
|
|
77
|
+
});
|
|
78
|
+
const newCreatorContainerType = (configOnly) => {
|
|
79
|
+
return configOnly ? creatorAddressWrapperType : exports.creatorContainerType;
|
|
80
|
+
};
|
|
81
|
+
const newOperatorContainerType = (configOnly) => {
|
|
82
|
+
return configOnly ? operatorAddressWrapperType : exports.operatorContainerType;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* @param configOnly a boolean to indicate config hash or definition hash
|
|
86
|
+
* @returns SSZ Containerized type of cluster definition
|
|
87
|
+
*/
|
|
88
|
+
const clusterDefinitionContainerType = (configOnly) => {
|
|
89
|
+
let returnedContainerType = {
|
|
90
|
+
uuid: new ssz_1.ByteListType(64),
|
|
91
|
+
name: new ssz_1.ByteListType(256),
|
|
92
|
+
version: new ssz_1.ByteListType(16),
|
|
93
|
+
timestamp: new ssz_1.ByteListType(32),
|
|
94
|
+
num_validators: new ssz_1.UintNumberType(8),
|
|
95
|
+
threshold: new ssz_1.UintNumberType(8),
|
|
96
|
+
dkg_algorithm: new ssz_1.ByteListType(32),
|
|
97
|
+
fork_version: new ssz_1.ByteVectorType(4),
|
|
98
|
+
operators: new ssz_1.ListCompositeType(newOperatorContainerType(configOnly), 256),
|
|
99
|
+
creator: newCreatorContainerType(configOnly),
|
|
100
|
+
validators: new ssz_1.ListCompositeType(exports.validatorsContainerType, 65536),
|
|
101
|
+
};
|
|
102
|
+
if (!configOnly) {
|
|
103
|
+
returnedContainerType = Object.assign(Object.assign({}, returnedContainerType), { config_hash: new ssz_1.ByteVectorType(32) });
|
|
104
|
+
}
|
|
105
|
+
return new ssz_1.ContainerType(returnedContainerType);
|
|
106
|
+
};
|
|
107
|
+
exports.clusterDefinitionContainerType = clusterDefinitionContainerType;
|
|
108
|
+
//cluster-lock
|
|
109
|
+
/**
|
|
110
|
+
* @param cluster The published cluster lock
|
|
111
|
+
* @returns The lock hash in of the corresponding cluster
|
|
112
|
+
*/
|
|
113
|
+
const clusterLockHash = (cluster) => {
|
|
114
|
+
const lockType = clusterLockContainerType();
|
|
115
|
+
const val = lockType.defaultValue();
|
|
116
|
+
//Check if we can replace with definition_hash
|
|
117
|
+
val.cluster_definition = (0, exports.hashClusterDefinition)(cluster.cluster_definition, false);
|
|
118
|
+
val.distributed_validators = cluster.distributed_validators.map(dVaidator => {
|
|
119
|
+
return {
|
|
120
|
+
distributed_public_key: (0, ssz_1.fromHexString)(dVaidator.distributed_public_key),
|
|
121
|
+
public_shares: dVaidator.public_shares.map(publicShare => (0, ssz_1.fromHexString)(publicShare)),
|
|
122
|
+
deposit_data: {
|
|
123
|
+
pubkey: (0, ssz_1.fromHexString)(dVaidator.deposit_data.pubkey),
|
|
124
|
+
withdrawal_credentials: (0, ssz_1.fromHexString)(dVaidator.deposit_data.withdrawal_credentials),
|
|
125
|
+
amount: parseInt(dVaidator.deposit_data.amount),
|
|
126
|
+
signature: (0, ssz_1.fromHexString)(dVaidator.deposit_data.signature),
|
|
127
|
+
},
|
|
128
|
+
builder_registration: {
|
|
129
|
+
message: {
|
|
130
|
+
fee_recipient: (0, ssz_1.fromHexString)(dVaidator.builder_registration.message.fee_recipient),
|
|
131
|
+
gas_limit: dVaidator.builder_registration.message.gas_limit,
|
|
132
|
+
timestamp: dVaidator.builder_registration.message.timestamp,
|
|
133
|
+
pubkey: (0, ssz_1.fromHexString)(dVaidator.builder_registration.message.pubkey),
|
|
134
|
+
},
|
|
135
|
+
signature: (0, ssz_1.fromHexString)(dVaidator.builder_registration.signature),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
return '0x' + Buffer.from(lockType.hashTreeRoot(val).buffer).toString('hex');
|
|
140
|
+
};
|
|
141
|
+
exports.clusterLockHash = clusterLockHash;
|
|
142
|
+
const depositDataContainer = new ssz_1.ContainerType({
|
|
143
|
+
pubkey: new ssz_1.ByteVectorType(48),
|
|
144
|
+
withdrawal_credentials: new ssz_1.ByteVectorType(32),
|
|
145
|
+
amount: new ssz_1.UintNumberType(8),
|
|
146
|
+
signature: new ssz_1.ByteVectorType(96),
|
|
147
|
+
});
|
|
148
|
+
const builderRegistrationMessageContainer = new ssz_1.ContainerType({
|
|
149
|
+
fee_recipient: new ssz_1.ByteVectorType(20),
|
|
150
|
+
gas_limit: new ssz_1.UintNumberType(8),
|
|
151
|
+
timestamp: new ssz_1.UintNumberType(8),
|
|
152
|
+
pubkey: new ssz_1.ByteVectorType(48),
|
|
153
|
+
});
|
|
154
|
+
const builderRegistrationContainer = new ssz_1.ContainerType({
|
|
155
|
+
message: builderRegistrationMessageContainer,
|
|
156
|
+
signature: new ssz_1.ByteVectorType(96),
|
|
157
|
+
});
|
|
158
|
+
const dvContainerType = new ssz_1.ContainerType({
|
|
159
|
+
distributed_public_key: new ssz_1.ByteVectorType(48),
|
|
160
|
+
public_shares: new ssz_1.ListCompositeType(new ssz_1.ByteVectorType(48), 256),
|
|
161
|
+
deposit_data: depositDataContainer,
|
|
162
|
+
builder_registration: builderRegistrationContainer,
|
|
163
|
+
});
|
|
164
|
+
/**
|
|
165
|
+
* @returns SSZ Containerized type of cluster lock
|
|
166
|
+
*/
|
|
167
|
+
const clusterLockContainerType = () => {
|
|
168
|
+
return new ssz_1.ContainerType({
|
|
169
|
+
cluster_definition: (0, exports.clusterDefinitionContainerType)(false),
|
|
170
|
+
distributed_validators: new ssz_1.ListCompositeType(dvContainerType, 65536),
|
|
171
|
+
});
|
|
172
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
17
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
18
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
19
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
20
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
21
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
22
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Client = void 0;
|
|
27
|
+
const uuid_1 = require("uuid");
|
|
28
|
+
const base_js_1 = require("./base.js");
|
|
29
|
+
const constants_js_1 = require("./constants.js");
|
|
30
|
+
const errors_js_1 = require("./errors.js");
|
|
31
|
+
const hash_js_1 = require("./hash.js");
|
|
32
|
+
const ajv_js_1 = require("./ajv.js");
|
|
33
|
+
const schema_js_1 = require("./schema.js");
|
|
34
|
+
__exportStar(require("./types.js"), exports);
|
|
35
|
+
__exportStar(require("./services.js"), exports);
|
|
36
|
+
/**
|
|
37
|
+
* Obol sdk Client can be used for creating, managing and activating distributed validators.
|
|
38
|
+
*/
|
|
39
|
+
class Client extends base_js_1.Base {
|
|
40
|
+
/**
|
|
41
|
+
* @param config - Client configurations
|
|
42
|
+
* @param config.baseUrl - obol-api url
|
|
43
|
+
* @param config.chainId - Blockchain network ID
|
|
44
|
+
* @param signer - ethersJS Signer
|
|
45
|
+
* @returns Obol-SDK Client instance
|
|
46
|
+
*
|
|
47
|
+
* An example of how to instantiate obol-sdk Client:
|
|
48
|
+
* [obolClient](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts#L29)
|
|
49
|
+
*/
|
|
50
|
+
constructor(config, signer) {
|
|
51
|
+
super(config);
|
|
52
|
+
this.signer = signer;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a cluster definition which contains cluster configuration.
|
|
56
|
+
* @param {ClusterPayload} newCluster - The new unique cluster.
|
|
57
|
+
* @returns {Promise<string>} config_hash.
|
|
58
|
+
* @throws On duplicate entries, missing or wrong cluster keys.
|
|
59
|
+
*
|
|
60
|
+
* An example of how to use createClusterDefinition:
|
|
61
|
+
* [createObolCluster](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts)
|
|
62
|
+
*/
|
|
63
|
+
createClusterDefinition(newCluster) {
|
|
64
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
if (!this.signer)
|
|
66
|
+
throw "Signer is required in createClusterDefinition";
|
|
67
|
+
(0, ajv_js_1.validatePayload)(newCluster, schema_js_1.definitionSchema);
|
|
68
|
+
const clusterConfig = Object.assign(Object.assign({}, newCluster), { fork_version: this.fork_version, dkg_algorithm: constants_js_1.dkg_algorithm, version: constants_js_1.config_version, uuid: (0, uuid_1.v4)(), timestamp: new Date().toISOString(), threshold: Math.ceil((2 * newCluster.operators.length) / 3), num_validators: newCluster.validators.length });
|
|
69
|
+
try {
|
|
70
|
+
const address = yield this.signer.getAddress();
|
|
71
|
+
clusterConfig.creator = { address };
|
|
72
|
+
clusterConfig.config_hash = (0, hash_js_1.clusterConfigOrDefinitionHash)(clusterConfig, true);
|
|
73
|
+
const creatorConfigSignature = yield this.signer.signTypedData((0, constants_js_1.Domain)(this.chainId), constants_js_1.CreatorConfigHashSigningTypes, { creator_config_hash: clusterConfig.config_hash });
|
|
74
|
+
const clusterDefinition = yield this.request(`/dv`, {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
body: JSON.stringify(clusterConfig),
|
|
77
|
+
headers: {
|
|
78
|
+
Authorization: `Bearer ${creatorConfigSignature}`,
|
|
79
|
+
"fork-version": this.fork_version,
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return clusterDefinition === null || clusterDefinition === void 0 ? void 0 : clusterDefinition.config_hash;
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if ((err === null || err === void 0 ? void 0 : err.message) == constants_js_1.CONFLICT_ERROR_MSG)
|
|
86
|
+
throw new errors_js_1.ConflictError();
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Approves joining a cluster with specific configuration.
|
|
93
|
+
* @param {OperatorPayload} operatorPayload - The operator data including signatures.
|
|
94
|
+
* @param {string} configHash - The config hash of the cluster which the operator confirms joining to.
|
|
95
|
+
* @returns {Promise<ClusterDefintion>} The cluster definition.
|
|
96
|
+
* @throws On unauthorized, duplicate entries, missing keys, not found cluster or invalid data.
|
|
97
|
+
*
|
|
98
|
+
* An example of how to use acceptClusterDefinition:
|
|
99
|
+
* [acceptClusterDefinition](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts)
|
|
100
|
+
*/
|
|
101
|
+
acceptClusterDefinition(operatorPayload, configHash) {
|
|
102
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
if (!this.signer)
|
|
104
|
+
throw "Signer is required in acceptClusterDefinition";
|
|
105
|
+
(0, ajv_js_1.validatePayload)(operatorPayload, schema_js_1.operatorPayloadSchema);
|
|
106
|
+
try {
|
|
107
|
+
const address = yield this.signer.getAddress();
|
|
108
|
+
const operatorConfigSignature = yield this.signer.signTypedData((0, constants_js_1.Domain)(this.chainId), constants_js_1.OperatorConfigHashSigningTypes, { operator_config_hash: configHash });
|
|
109
|
+
const operatorENRSignature = yield this.signer.signTypedData((0, constants_js_1.Domain)(this.chainId), constants_js_1.EnrSigningTypes, { enr: operatorPayload.enr });
|
|
110
|
+
const operatorData = Object.assign(Object.assign({}, operatorPayload), { address, enr_signature: operatorENRSignature, fork_version: this.fork_version });
|
|
111
|
+
const clusterDefinition = yield this.request(`/dv/${configHash}`, {
|
|
112
|
+
method: 'PUT',
|
|
113
|
+
body: JSON.stringify(operatorData),
|
|
114
|
+
headers: {
|
|
115
|
+
Authorization: `Bearer ${operatorConfigSignature}`,
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return clusterDefinition;
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @param configHash - The configuration hash returned in createClusterDefinition
|
|
127
|
+
* @returns {Promise<ClusterDefintion>} The cluster definition for config hash
|
|
128
|
+
* @throws On not found config hash.
|
|
129
|
+
*
|
|
130
|
+
* An example of how to use getClusterDefinition:
|
|
131
|
+
* [getObolClusterDefinition](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts)
|
|
132
|
+
*/
|
|
133
|
+
getClusterDefinition(configHash) {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
+
const clusterDefinition = yield this.request(`/dv/${configHash}`, {
|
|
136
|
+
method: 'GET',
|
|
137
|
+
});
|
|
138
|
+
return clusterDefinition;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* @param configHash - The configuration hash in cluster-definition
|
|
143
|
+
* @returns {Promise<ClusterLock>} The matched cluster details (lock) from DB
|
|
144
|
+
* @throws On not found cluster definition or lock.
|
|
145
|
+
*
|
|
146
|
+
* An example of how to use getClusterLock:
|
|
147
|
+
* [getObolClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts)
|
|
148
|
+
*/
|
|
149
|
+
getClusterLock(configHash) {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
const lock = yield this.request(`/lock/configHash/${configHash}`, {
|
|
152
|
+
method: 'GET',
|
|
153
|
+
});
|
|
154
|
+
return lock;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.Client = Client;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.definitionSchema = exports.operatorPayloadSchema = void 0;
|
|
4
|
+
exports.operatorPayloadSchema = {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
version: {
|
|
8
|
+
type: "string"
|
|
9
|
+
},
|
|
10
|
+
enr: {
|
|
11
|
+
type: "string"
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
required: [
|
|
15
|
+
"version",
|
|
16
|
+
"enr",
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
exports.definitionSchema = {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
name: {
|
|
23
|
+
type: "string"
|
|
24
|
+
},
|
|
25
|
+
operators: {
|
|
26
|
+
type: "array",
|
|
27
|
+
minItems: 4,
|
|
28
|
+
uniqueItems: true,
|
|
29
|
+
items: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
address: {
|
|
33
|
+
type: "string",
|
|
34
|
+
minLength: 42,
|
|
35
|
+
maxLength: 42
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: [
|
|
39
|
+
"address"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
validators: {
|
|
44
|
+
type: "array",
|
|
45
|
+
minItems: 1,
|
|
46
|
+
items: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
fee_recipient_address: {
|
|
50
|
+
type: "string",
|
|
51
|
+
minLength: 42,
|
|
52
|
+
maxLength: 42
|
|
53
|
+
},
|
|
54
|
+
withdrawal_address: {
|
|
55
|
+
type: "string",
|
|
56
|
+
minLength: 42,
|
|
57
|
+
maxLength: 42
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
required: [
|
|
61
|
+
"fee_recipient_address",
|
|
62
|
+
"withdrawal_address"
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
required: [
|
|
68
|
+
"name",
|
|
69
|
+
"operators",
|
|
70
|
+
"validators"
|
|
71
|
+
]
|
|
72
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.validateClusterLock = void 0;
|
|
13
|
+
const verify_js_1 = require("./verify.js");
|
|
14
|
+
/**
|
|
15
|
+
* Verifies Cluster Lock's validity.
|
|
16
|
+
* @param lock - cluster lock
|
|
17
|
+
* @returns {Promise<{ result: boolean }> } boolean result to indicate if lock is valid
|
|
18
|
+
* @throws on missing keys or values.
|
|
19
|
+
*
|
|
20
|
+
* An example of how to use validateClusterLock:
|
|
21
|
+
* [validateClusterLock](https://github.com/ObolNetwork/obol-sdk-examples/blob/main/TS-Example/index.ts)
|
|
22
|
+
*/
|
|
23
|
+
const validateClusterLock = (lock) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
try {
|
|
25
|
+
const isLockValid = yield (0, verify_js_1.isValidClusterLock)(lock);
|
|
26
|
+
return isLockValid;
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
exports.validateClusterLock = validateClusterLock;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FORK_MAPPING = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Permitted ChainID's
|
|
6
|
+
*/
|
|
7
|
+
var FORK_MAPPING;
|
|
8
|
+
(function (FORK_MAPPING) {
|
|
9
|
+
/** Mainnet. */
|
|
10
|
+
FORK_MAPPING[FORK_MAPPING["0x00000000"] = 1] = "0x00000000";
|
|
11
|
+
/** Goerli/Prater. */
|
|
12
|
+
FORK_MAPPING[FORK_MAPPING["0x00001020"] = 5] = "0x00001020";
|
|
13
|
+
/** Gnosis Chain. */
|
|
14
|
+
FORK_MAPPING[FORK_MAPPING["0x00000064"] = 100] = "0x00000064";
|
|
15
|
+
/** Holesky. */
|
|
16
|
+
FORK_MAPPING[FORK_MAPPING["0x01017000"] = 17000] = "0x01017000";
|
|
17
|
+
})(FORK_MAPPING || (exports.FORK_MAPPING = FORK_MAPPING = {}));
|
|
18
|
+
;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.strToUint8Array = exports.hexWithout0x = void 0;
|
|
4
|
+
const hexWithout0x = (hex) => {
|
|
5
|
+
return hex.slice(2, hex.length);
|
|
6
|
+
};
|
|
7
|
+
exports.hexWithout0x = hexWithout0x;
|
|
8
|
+
const strToUint8Array = (str) => {
|
|
9
|
+
return new TextEncoder().encode(str);
|
|
10
|
+
};
|
|
11
|
+
exports.strToUint8Array = strToUint8Array;
|